car*_*ret 5 java generics wildcard
我在 Effective Java 中读到你不应该使用有界通配符作为返回类型,但我不知道我应该怎么做。我的代码编译的唯一方法是RequestCloner<? extends HttpUriRequest>
在静态工厂中使用作为返回类型。我做错了什么还是有解决方法?
注意:要注意的一件事是HttpUriRequest
有方法setHeader
,但只有HttpPost
方法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;
}
}
Run Code Online (Sandbox Code Playgroud)
查看您的代码,您的类不需要是通用的。进一步看,有一个奇怪的问题:调用者传入一个 URL 来创建克隆器,然后将 a HttpServletRequest
(理论上可能是不同类型的请求)传递到克隆方法中。
我可以看到两种解决方案,具体取决于您是否真的需要RequestCloner
通用。
如果 RequestCloner 不需要是通用的
更改基类如下:
abstract class RequestCloner {
private enum RequestType {
GET, POST, 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 AssertionFailedError(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
}
}
Run Code Online (Sandbox Code Playgroud)
的子类RequestCloner
将覆盖clone()
,可选择更改返回值以返回 的子类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;
}
...
}
Run Code Online (Sandbox Code Playgroud)
上述解决方案的缺点是 GET 请求与 POST 请求的返回值cloneRequest()
相同。
如果您愿意,可以通过向枚举添加代码来删除开关:
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);
}
...
}
Run Code Online (Sandbox Code Playgroud)
如果您希望返回值取决于请求的类型,那么调用者将需要指定某种类型标记、显式引用 的子类RequestCloner
,或者RequestCloner
为每种类型的请求添加一个静态方法。
如果 RequestCloner 需要通用
鉴于问题中的代码,通用的唯一好处RequestCloner
是使clone()
GET 或 POST 的返回值不同。
为此,您有两种选择
newInstance()
用多种创建方法替换您的方法以下是选项 2 的示例:
public static RequestCloner<HttpPost> forPostRequest(String URL) {
return new PostRequestCloner(URL);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
542 次 |
最近记录: |