【问题标题】:java jackson parse object containing a generic type objectjava jackson解析包含泛型对象的对象
【发布时间】:2012-10-26 13:51:38
【问题描述】:

我有以下问题。

我必须将一个 json 请求解析为一个包含泛型类型字段的对象。

编辑

我已经使用常规类类型进行了一些测试(所以我在用泛型替换它之前让它工作)。现在解析单个元素效果很好。

问题是当我需要从该类中解析出一个列表对象时。

所以我必须以某种方式通知杰克逊,我的 T 是 list 类型,而不仅仅是 AlbumModel。

这是我尝试过的。

 @Override
    public ListResponseModel<AlbumModel> parse(String responseBody) throws Exception {
    JavaType type = mapper.getTypeFactory().constructParametricType(ResponseModel.class,
        AlbumModel.class);
    return mapper.readValue(responseBody,
        mapper.getTypeFactory().constructParametricType(ResponseModel.class, type));
    }

但上面的代码不起作用。这种情况的解决方案是什么?

我在 ListResponseModel 中的泛型类型定义如下:List&lt;T&gt; data

成功如下:

public class BaseResponseModel<T> {

    @JsonProperty("data")
    private T data;

    @JsonProperty("paginations")
    private PaginationModel pagination;
}

到目前为止,我有以下代码,但它总是解析成哈希。

public class ResponseParser extends BaseJacksonMapperResponseParser<ResponseModel<AlbumModel>> {

    public static final String TAG = ResponseParser.class.getSimpleName();

    @Override
    public ResponseModel<AlbumModel> parse(String responseBody) throws Exception {
        return mapper.readValue(responseBody,
                mapper.getTypeFactory().constructParametricType(ResponseModel.class, AlbumModel.class));
    }
}

public abstract class BaseJacksonMapperResponseParser<T> implements HttpResponseParser<T> {

    public static final String TAG = BaseJacksonMapperResponseParser.class.getSimpleName();

    public static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.disable(Feature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.enable(Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
    }

}

【问题讨论】:

    标签: java json parsing generics jackson


    【解决方案1】:

    我同意 eugen 的回答,但只是想稍微扩展一下。第一步是重构你的 parse 方法,让它接受第二个参数。您需要调用者传入一个 TypeReference 实例,而不是在您的方法中分配类型引用。

    public BaseResponseModel<T> parse(String responseBody, TypeReference<T> ref) throws Exception {
        return mapper.readValue(responseBody, ref);
    }
    

    不幸的是,您的 sn-p 没有显示调用 parse 的代码 - 所以我会编造一些东西:

    BaseResponseParser<Collection<Person>> parser = new BaseResponseParser<Collection<Person>>();
    BaseResponseModel<Collection<Person>> result = parser.parse(jsonText, new TypeReference<Collection<Person>>(){});
    

    请注意,在这种情况下编译 TypeReference 实例时,它是对我们期望的真实具体类的类型引用。

    您可以在运行时传递一个 Class 做同样的事情,但是 TypeReference 更强大一些,因为它甚至在类型 T 是一个泛型集合时也可以工作。 TypeReference 实现中有一些神奇之处,可以让它保留通常会被删除的类型信息。

    [更新]

    更新为使用Collection&lt;Person&gt;。注意 - 据我所知,List&lt;Whatever&gt; 也应该可以工作,但我仔细检查了一个项目,我使用杰克逊反序列化集合。基类 Collection 确实有效,所以我坚持使用它。

    【讨论】:

    • 好的,我开始明白了。我使用单个对象完成了这项工作,但我无法为列表执行此操作。你能提供更多的意见吗?感谢您迄今为止的努力。
    • 好的,我已经成功了。与此类似,但您证明了一点。多谢。我唯一讨厌的是我必须发送 .class 并定义通用参数,我最终会得到类似 new Parser(AlbumModel.class) 的东西
    【解决方案2】:

    您的类型 T 将在运行时“擦除”,因此 Jackson 不知道 T 的真正类型是什么,并将其反序列化为 Map。您的解析方法需要第二个参数,即 Class&lt;T&gt; clazzTypeReference&lt;T&gt;java.lang.reflect.Type

    编辑

    TypeReference 神奇的小解释。当您执行 new XX() {} 时,您正在创建一个匿名类,因此如果它是一个具有类型变量的类(如果您愿意,可以进行参数化), new X&lt;List&lt;Y&gt;&gt;() {}, 您将能够检索 @987654325 @ 作为运行时的 java 类型。就像你做过的一样:

    abstract class MyGenericClass<T> {}
    class MySpecializedClass extends MyGenericClass<List<Y>> {}
    

    【讨论】:

      【解决方案3】:

      由于您使用的是 Jackson,您可能需要创建自定义 JsonDeserializer 或 JsonSerializer,具体取决于您是在处理响应还是请求。我已经用 Dates 做到了这一点,因为在我的回复中我想要一个标准视图。我不是 100% 肯定它会与通用字段一起工作。这是我正在做的一个例子:

      public class DateSerializer extends JsonSerializer<Date> {
      
          private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZ");
      
          @Override
          public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
              String dateString = dateFormat.format(value);
              jgen.writeString(dateString);
          }
      
      }
      

      然后我就像这样将它添加到我的班级:

      @JsonSerialize(using = DateSerializer.class)
      public Date getModifiedDate() {
          return modifiedDate;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-12
        • 1970-01-01
        • 2019-12-07
        • 2016-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多