【问题标题】:nested generic parameter as a method parameter - Java嵌套泛型参数作为方法参数 - Java
【发布时间】:2016-01-09 22:22:33
【问题描述】:

基于这个问题How to get a class instance of generics type T 我实现了以下类:

public class OkJsonConverter<T> {

    final Class<T> typeParameterClass;

    public OkJsonConverter(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    protected T processJson(String json) throws OkClientException {
        T object = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode jsonNode = objectMapper.readTree(json);

            if (jsonNode.get("error_code") != null) {
                Error error = objectMapper.treeToValue(jsonNode, Error.class);
                throw new OkClientException("API returned error", error);
            } else {
                object = objectMapper.treeToValue(jsonNode, typeParameterClass);
            }
        } catch (IOException e) {
            throw new OkClientException("unable to process json", e);
        }
        return object;
    }

}

我可以将这个类与泛型参数一起使用,例如:

return new OkJsonConverter<User>(User.class).processJson(response.getBody());

但现在我正在努力如何让它使用像这样的嵌套泛型参数List&lt;Method&gt;

此代码不起作用:

 return new OkJsonConverter<List<Method>>(List<Method>.class).processJson(response.getBody());

请帮助更改此代码以使其正常工作。

【问题讨论】:

    标签: java generics jackson java-8


    【解决方案1】:

    Java 没有任何方法可以将该类型表示为Class。你能得到的最接近的近似值是(Class&lt;List&lt;Method&gt;&gt;) (Class) List.class,但这只是证明你只是在看一个不知道其元素类型的基本List

    不清楚这是否适用于您的 JSON 转换器,但应该在您使用的转换器的文档中指定,它必须自己处理这个问题,因为这是 Java 中的一个普遍问题,当您正在尝试反思泛型类型。

    【讨论】:

    • 感谢您的回答。我正在尝试将您的建议应用于我的代码,但现在没有任何成功..
    • Java 有一个way 来表示参数化类型,Jackson 例如uses this technique
    • @user3707125,是的,这是真的;这就是为什么我澄清“以任何方式将该类型表示为Class。”
    • 同意,但他没有问如何将类型表示为Class - 他问如何传递泛型类型信息。而且您在回答中没有提到存在主要序列化/反序列化库支持的现有解决方案,而这可能向作者展示了解决问题的方法。
    • @user3707125 我得到的印象是他们使用的是外部 JSON 序列化工具,我在 Google 上找不到,而且无法判断它是否接受 TypeToken 之类的东西。我建议检查它的文档,如果它完全支持它,我认为它会提到一个类似 TypeToken 的东西,或者解决这个问题的一些替代方法。
    【解决方案2】:

    最后,感谢user3707125,我找到了实现这一点的方法:

    idierL更正

    public class OkJsonConverter {
    
    private static final String ERROR_CODE_FIELD_NAME = "error_code";
    
    protected <T> T readTreeToValue(String json, TypeReference<T> valueTypeRef) throws OkClientException {
        T object = null;
    
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode jsonNode = objectMapper.readTree(json);
    
            if (jsonNode.has(ERROR_CODE_FIELD_NAME)) {
                Error error = objectMapper.treeToValue(jsonNode, Error.class);
                throw new OkClientException("Ok API returned error", error);
            } else {
                JavaType type = objectMapper.getTypeFactory().constructType(valueTypeRef);
                object = objectMapper.convertValue(jsonNode, type);
            }
        } catch (IOException e) {
            throw new OkClientException("Unable to process JSON", e);
        }
    
        return object;
    }
    

    }

    现在,以下代码可以正常工作:

    List<Method> result = new OkJsonConverter().readTreeToValue(response.getBody(), new TypeReference<List<Method>>() {});
    

    【讨论】:

    • 请注意,您的解决方案根本不是类型安全的(如您的 @SuppressWarnings 所示):即使 JSON 实际上包含 List&lt;String&gt;,这也可以工作,您只会在运行时注意到它当您尝试对result 进行操作时,您将获得ClassCastException。作为一般规则,不惜一切代价避免此类抑制警告,因为您几乎肯定会在某些时候遇到麻烦。
    • 感谢您的评论。不幸的是,我现在没有更好的
    • 其实有一个……只需将未经检查的演员表和treeToValue 调用替换为objectMapper.convertValue(jsonNode, type)
    猜你喜欢
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    相关资源
    最近更新 更多