具有多个类型参数的通用帮助器方法

时间:2016-03-03 13:19:38

标签: java arrays generics

我有一个WebTarget POST调用,每次调用都会调用不同的参数和不同的反序列化类。所以,我想将WebTarget代码抽象为一个简单接受参数的方法,也允许我在一次调用时失败而不停止其他调用。

这是当前的WebTarget调用(下面列出的3个Token。*类是Token的内部类,它们也扩展了Token,Text是一个简单的包装类):

private Token[] execPost(WebTarget target, String content, Class tokenClass) {
    try {
        return target.request().post(Entity.json(new Text(content)), tokenClass);
    } catch (javax.ws.rs.BadRequestException bre) {
            LOG.error(bre.getMessage());
}

我想创建类似于下面的方法:

private <T extends Token>Token[] execPost(WebTarget target, String content, T tokenClass) {
    try {
        return target.request().post(Entity.json(new Text(content)), tokenClass);
    } catch (javax.ws.rs.BadRequestException bre) {
        LOG.error(bre.getMessage());
    }
}

我知道我需要在类型中进行类泛型和某种方式或其他传递,但是我已经尝试了每一种我能想到的方式,并且每次我得到编译时&#34;推理变量具有不兼容的界限& #34;错误。另一个似乎让我搞砸的问题是我传递了子类的类(例如Token.ProfileLocationToken)以进行反序列化并将结果称为超类,所以我试图创建有界类型...不成功。

我没有在课堂上的任何其他地方使用泛型;类型定义将来自同一类中的调用方法。

如果有人可以通过向我展示如何正确创建该方法来帮助它以我喜欢的方式工作,我会很感激。

编辑1 根据请求,以下是我尝试过的几种方式。请注意,我的尝试到处都是,我还没有使用过Generics。我也有尝试强制它进入我的类类型数组的问题。

我第一次尝试使用以下方法开始:

method javax.ws.rs.client.SyncInvoker.<T>post(javax.ws.rs.client.Entity<?>,java.lang.Class<T>) is not applicable
  (cannot infer type-variable(s) T 
   (argument mismatch; T cannot be converted to java.lang.Class<T>))
method javax.ws.rs.client.SyncInvoker.<T>post(javax.ws.rs.client.Entity<?>,javax.ws.rs.core.GenericType<T>) is not applicable
  (cannot infer type-variable(s) T
    (argument mismatch; T cannot be converted to javax.ws.rs.core.GenericType<T>))

出现以下错误:

private <T extends Token>T[] execPost(WebTarget target, String content, Class<T> tokenClass) {
    try {
        return target.request().post(Entity.json(new Text(content)), tokenClass);
    } catch (javax.ws.rs.BadRequestException bre) {
        LOG.error(bre.getMessage());
    }
}

我还尝试让它返回T然后在分配返回的数组时将其称为Token []:

equality constraints: T
    upper bounds: T[],java.lang.Object

出现以下编译错误:

inference variable T#1 has incompatible bounds
    equality constraints: T#2
    upper bounds: T#2[],Object
where T#1, T#2 are type-variables:
    T#1 extends Object declared in method <T#1>post(Entity<?>,Class<T#1>)
    T#2 extends Token declared in method <T#2>execPost(WebTarget,String,Class<T#2>)

虽然编译器错误描述性较差,但Netbeans说:

{{1}}

2 个答案:

答案 0 :(得分:1)

签名可以是

private <T extends Token> T[] execPost(WebTarget target, String content, Class<T> tokenClass) {

请注意,在这种情况下,您传递数组中的类型,而不是数组类型。

答案 1 :(得分:0)

虽然它可能优雅也可能不优雅,但这种方法有效:

private <T extends Token> T[] execPost(WebTarget target, String content, Class<T[]> tokenClass) {
    T[] arr = null;
    try {
        arr = target.request().post(Entity.json(new Text(content)), tokenClass);
    } catch (javax.ws.rs.BadRequestException bre) {
        LOG.error(bre.getMessage());
    }
    return arr;
}

以下是对上述方法的调用:

Token[] profileLocationTokens = execPost(target, profileLocationText, Token.ProfileLocationToken[].class);
Token[] statusTextTokens = execPost(target, statusText, Token.StatusTextToken[].class);
Token[] profileDescriptionTokens = execPost(target, profileDescriptionText, Token.ProfileDescriptionToken[].class);

上面的评论中有一个问题,即新创建的方法返回的数组中的元素是否真的是Token.Subclass或Token的实例。我按如下方式测试了返回的数组:

if (statusTextTokens.length != 0 && statusTextTokens[0] instanceof Token.StatusTextToken) {
    LOG.info("Instance of StatusTextToken");
}

if (profileLocationTokens.length != 0 && profileLocationTokens[0] instanceof Token.ProfileLocationToken) {
    LOG.info("Instance of ProfileLocationToken");
}

if (profileDescriptionTokens.length != 0 && profileDescriptionTokens[0] instanceof Token.ProfileDescriptionToken) {
    LOG.info("Instance of ProfileDescriptionToken");
}

在每种情况下,都会生成日志输出。