Java – bounded wildcard of static factory pattern of return type

I read in effective Java that you shouldn't use bounded wildcards as return types, but I don't know what I should do The only way to compile my code is to use requestcloner as the return type in the static factory Did I do something wrong or have a solution?

Note: it should be noted that httpurirequest has a method setheader, but only httppost has a method setentity

abstract class RequestCloner<T extends HttpUriRequest> {

  protected T clonedRequest;

  private enum RequestType {
    GET,POST,DELETE
  }

  static RequestCloner<? extends HttpUriRequest> newInstance(
      String type,String url) {
    RequestType requestType = RequestType.valueOf(type);
    switch (requestType) {
    case GET:
      return new GetRequestCloner(url);
    case POST:
      return new PostRequestCloner(url);
    case DELETE:
      return new DeleteRequestCloner(url);
    default:
      throw new IllegalArgumentException(String.format(
          "Method '%s' not supported",type));
    }
  }

  public abstract HttpUriRequest clone(HttpServletRequest servletRequest) throws IOException;

  protected void cloneHeaders(HttpServletRequest servletRequest) {
    @SuppressWarnings("unchecked")
    Enumeration<String> e = servletRequest.getHeaderNames();
    while (e.hasMoreElements()) {
        String header = e.nextElement();
        if (!header.equalsIgnoreCase("Content-Length")
                && !header.equalsIgnoreCase("Authorization")
                && !header.equalsIgnoreCase("Host")) {
            clonedRequest.setHeader(new BasicHeader(header,servletRequest.getHeader(header)));
        }
    }
  }
}

...

class GetRequestCloner extends RequestCloner<HttpGet> {

  GetRequestCloner(String url) {
    this.clonedRequest = new HttpGet(url);
  }

  @Override
  public HttpUriRequest clone(HttpServletRequest servletRequest) {
    cloneHeaders(servletRequest);
    return clonedRequest;
  }
}

...

class PostRequestCloner extends RequestCloner<HttpPost> {

  private static final int MAX_STR_LEN = 1024;

  PostRequestCloner(String url) {
    this.clonedRequest = new HttpPost(url);
  }

  @Override
  public HttpUriRequest clone(HttpServletRequest servletRequest) throws IOException {
    cloneHeaders(servletRequest);
    cloneBody(servletRequest);
    return clonedRequest;
  }

  private void cloneBody(HttpServletRequest servletRequest) throws IOException {
    StringBuilder sb = new StringBuilder("");
    BufferedReader br = new BufferedReader(new InputStreamReader(
            servletRequest.getInputStream(),"UTF-8"));
    String line = "";
    while ((line = br.readLine()) != null && sb.length() < MAX_STR_LEN) {
        sb.append(line);
    }
    br.close();
    clonedRequest.setEntity(new StringEntity(sb.toString(),"UTF-8"));
  }
}

...

class DeleteRequestCloner extends RequestCloner<HttpDelete> {

  DeleteRequestCloner(String url) {
    this.clonedRequest = new HttpDelete(url);
  }

  @Override
  public HttpUriRequest clone(HttpServletRequest servletRequest) {
    cloneHeaders(servletRequest);
    return clonedRequest;
  }
}

Solution

Looking at your code, your class does not need to be generic Further, there is a strange problem, that is, the caller passes in the URL to create the clone, and then passes HttpServletRequest (which can theoretically be different types of requests) to the clone method

I can see two solutions, depending on whether you really need requestcloner to be generic

If requestcloner does not require a generic

Change the base class as follows:

abstract class RequestCloner {

  private enum RequestType {
    GET,DELETE
  }

  public static HttpUriRequest cloneRequest(HttpServletRequest servletRequest)
        throws IOException {
    RequestCloner cloner = createCloner(servletRequest);
    String uri = servletRequest.getRequestURI();
    return cloner.clone(uri,servletRequest);
  }

  private static RequestCloner createCloner(HttpServletRequest servletRequest) {
    RequestType requestType = RequestType.valueOf(servletRequest. getmethod());
    switch (requestType) {
    case GET:
      return new GetRequestCloner();
    case POST:
      return new PostRequestCloner();
    case DELETE:
      return new DeleteRequestCloner();
    default:
      throw new Assertion@R_404_1455@Error(String.format(
          "RequestType '%s' not supported",requestType));
    }
  }

  protected abstract HttpUriRequest clone(
      String uri,HttpServletRequest servletRequest)
      throws IOException;

  protected final void cloneHeaders(
      HttpServletRequest servletRequest,HttpUriRequest clonedRequest) { // note addition of parameter
    // same code as before,but modify the passed-in clonedRequest
  }
}

Subclasses of requestcloner will override clone (). Optionally, change the return value to return subclasses of httpurirequest:

class PostRequestCloner extends RequestCloner {
  private static final int MAX_STR_LEN = 1024;

  @Override
  protected HttpPost clone(
      String uri,HttpServletRequest servletRequest)
      throws IOException {
    HttpPost clonedRequest = new HttpPost(uri);
    cloneHeaders(servletRequest,clonedRequest);
    cloneBody(servletRequest,clonedRequest);
    return clonedRequest;
  }

  ...
}

The disadvantage of the above solution is that the return value of clonerequest () is the same as the get request as a post request

If you prefer, you can remove the switch by adding code to the enumeration:

abstract class RequestCloner {

  private enum RequestType {
    GET(new GetRequestCloner()),POST(new PostRequestCloner()),DELETE(new DeleteRequestCLoner());

    private final RequestCloner requestCloner;

    private RequestType(RequestCloner requestCloner) {
      this.requestCloner = requestCloner();
    }
  }

  public static HttpUriRequest cloneRequest(HttpServletRequest servletRequest)
        throws IOException {
    RequestType requestType = RequestType.valueOf(servletRequest. getmethod());
    String uri = servletRequest.getRequestURI();
    return requestType.requestCloner.clone(uri,servletRequest);
  }

  ...
}

If you want the return value to depend on the type of request, the caller needs to specify some type of tag, explicitly reference the subclass of requestcloner, or add a static method to requestcloner for each type of request

If requestcloner needs a generic

Given the code in the problem, the only advantage of making requestcloner generic is to make the return value of clone () different from get or post

You have two options for this

>Expose subclasses (and their constructors). > Replace the newinstance () method with multiple creation methods

The following is an example of option 2:

public static RequestCloner<HttpPost> forPostRequest(String URL) {
  return new PostRequestCloner(URL);
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>