我有以下问题。
我必须将json请求解析为包含泛型类型字段的对象。
修改
我已经使用常规类类型进行了一些测试(因此我在使用泛型替换之前使其工作)。现在解析单个元素效果很好。
问题是当我需要从该类中解析出一个列表对象时。
所以我必须以某种方式通知杰克逊我的T是类型列表而不仅仅是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<T> 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);
}
}
答案 0 :(得分:5)
我同意eugen的回答,但只是想稍微扩展一下。第一步是重构你的parse方法,所以它需要第二个参数。您需要调用者传入TypeReference实例,而不是在方法中分配类型引用。
public BaseResponseModel<T> parse(String responseBody, TypeReference<T> ref) throws Exception {
return mapper.readValue(responseBody, ref);
}
不幸的是,你的代码段没有显示调用解析的代码 - 所以我会做点什么:
BaseResponseParser<Collection<Person>> parser = new BaseResponseParser<Collection<Person>>();
BaseResponseModel<Collection<Person>> result = parser.parse(jsonText, new TypeReference<Collection<Person>>(){});
请注意,在这种情况下编译TypeReference实例时,它是对我们期望的真实具体类的类型引用。
你可以在运行时传入一个类做同样的事情,但是TypeReference更强大,因为它甚至可以在类型T是泛型集合时使用。 TypeReference实现中有一些神奇之处,它允许它保留通常会被删除的类型信息。
[更新]
已更新以使用Collection<Person>
。注意 - 据我所知,List<Whatever>
也应该有效,但我仔细检查了一个项目,我使用jackson来反序列化集合。基类收集肯定有效,所以我坚持下去。
答案 1 :(得分:2)
您的类型T将在运行时被“擦除”,因此Jackson不知道T的真实类型是什么,并将其反序列化为Map。您的解析方法需要第二个参数,即Class<T> clazz
或TypeReference<T>
或java.lang.reflect.Type
。
修改强>
关于TypeReference魔力的小解释。当您执行新的XX() {} 时,您正在创建一个匿名类,因此如果它是一个带有typevariables的类(如果您愿意,可以参数化),则可以检索新的X<List<Y>>() {},
List<Y>
在运行时作为java类型。它与您完成的非常相似:
abstract class MyGenericClass<T> {}
class MySpecializedClass extends MyGenericClass<List<Y>> {}
答案 2 :(得分:0)
由于你正在使用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;
}