Java 使用GSON或Jackson将JSON反序列化为具有泛型参数的类
我从服务器收到的响应如下所示:Java 使用GSON或Jackson将JSON反序列化为具有泛型参数的类,java,generics,jackson,gson,Java,Generics,Jackson,Gson,我从服务器收到的响应如下所示: { "timestamp" : 1, "some other data": "blah", "result" : { ... } } 各种各样的电话。我想在客户端做的是: class ServerResponse<T> { long timestamp; T result; } class服务器响应{ 长时间戳; T结果; } 然后与GSON或Jackson进行反序列化。由于类型擦除,我无法这样做。我用
{
"timestamp" : 1,
"some other data": "blah",
"result" : {
...
}
}
各种各样的电话。我想在客户端做的是:
class ServerResponse<T> {
long timestamp;
T result;
}
class服务器响应{
长时间戳;
T结果;
}
然后与GSON或Jackson进行反序列化。由于类型擦除,我无法这样做。我用这样的子类欺骗了它:
class SpecificResponse extends ServerRequest<SpecificType> {}
class SpecificResponse扩展了ServerRequest{}
但这需要一堆无用的类。谁有更好的办法
我还需要能够处理结果是数组的情况。在这种情况下,典型的类型擦除解决方案是使用匿名类来维护超类信息,以便与反射一起使用 Jackson提供了类型以及使用它的重载 在您的示例中,您将使用
ServerResponse response = objectMapper.readValue(theJsonSource, new TypeReference<ServerResponse<SpecificType>>() {});
然后,启用
确定强制非数组是否可接受的功能
(在JSON中)用于Java集合的值(数组、,
java.util.Collection
)类型。如果启用,集合反序列化程序将
尝试处理非数组值,就好像它们周围有“隐式”值一样
JSON数组
我支持使用
@Pillar
解决方案Jackson
,因为它非常严格。2行代码
下面是Gson版本,其工作方式相同,但您需要自定义反序列化程序和一些反射来实现这一点
public static class CustomDeserializer implements JsonDeserializer<ServerResponse> {
@Override
public ServerResponse deserialize(JsonElement je, Type respT,
JsonDeserializationContext jdc) throws JsonParseException {
Type t = (respT instanceof ParameterizedType) ?
((ParameterizedType) respT).getActualTypeArguments()[0] :
Object.class;
JsonObject jObject = (JsonObject) je;
ServerResponse serverResponse = new ServerResponse();
//can add validation and null value check here
serverResponse.timestamp = jObject.get("timestamp").getAsLong();
JsonElement dataElement = jObject.get("result");
if (dataElement != null) {
if (dataElement.isJsonArray()) {
JsonArray array = dataElement.getAsJsonArray();
// can use ((ParameterizedType) respT).getActualTypeArguments()
// instead of new Type[]{t}
// if you 100% sure that you will always provide type
Type listT = ParameterizedTypeImpl.make(List.class, new Type[]{t}, null);
serverResponse.result = jdc.deserialize(array, listT);
} else if(dataElement.isJsonObject()) {
serverResponse.result = new ArrayList();
serverResponse.result.add(jdc.deserialize(dataElement, t));
}
}
return serverResponse;
}
}
公共静态类CustomDeserializer实现JsonDeserializer{
@凌驾
公共服务器响应反序列化(JsonElement je,类型respT,
JsonDeserializationContext(jdc)引发JsonParseException{
类型t=(参数化类型的响应实例)?
((ParameterizedType)respT).getActualTypeArguments()[0]:
对象类;
JsonObject jObject=(JsonObject)je;
ServerResponse ServerResponse=newserverresponse();
//可以在此处添加验证和空值检查
serverResponse.timestamp=jObject.get(“timestamp”).getAsLong();
JsonElement dataElement=jObject.get(“结果”);
if(数据元素!=null){
if(dataElement.isJsonArray()){
JsonArray数组=dataElement.getAsJsonArray();
//可以使用((ParameterizedType)respT.getActualTypeArguments()
//而不是新类型[]{t}
//如果您100%确定您将始终提供类型
类型listT=ParameteredTypeImpl.make(List.class,新类型[]{t},null);
serverResponse.result=jdc.deserialize(数组,listT);
}else if(dataElement.isJsonObject()){
serverResponse.result=new ArrayList();
serverResponse.result.add(jdc.deserialize(dataElement,t));
}
}
返回服务器响应;
}
}
用例与Jackson非常相似:
Gson gson = new GsonBuilder()
.registerTypeAdapter(ServerResponse.class, new CustomDeserializer())
.create();
ServerResponse<MyObject> s = gson.fromJson(json, new TypeToken<ServerResponse<MyObject>>(){}.getType())
Gson Gson=new GsonBuilder()
.registerTypeAdapter(ServerResponse.class,新的CustomDeserializer())
.create();
ServerResponse s=gson.fromJson(json,new-TypeToken(){}.getType())
TypeToken
在Gson中,在Jackson中TypeReference
。如果要将数组包装在ServerResponse
中,则数组将更为困难。某些框架允许您在客户端请求中指定类类型,从而具体化类型参数并使请求返回具体类型。寻找带有类参数的请求api的变体。@如果更简单的话,我很高兴有一个二级ServerArrayRequest,其中变量是List result。我不介意两个,我不希望有几十个。Jackson有一个功能,可以让你这样做,但是你的Java代码必须有一个列表。不幸的是,它不适用于数组情况,无论是t结果保存列表还是列表结果。不管是哪种情况,它都会给我一个结果中每个元素的列表。@Gabeschen对我来说很好,我认为我的问题仍然是擦除。我试图在泛型类本身中使用它——一个CustomVolleyRequest,其中Type是反序列化类型。因此,随着擦除,它再次成为一个对象。如果我能像上一节课一样通过考试。。。。我想我能做到,行得通。好的,所以每个请求调用1个boiler plate参数,而不是每个类型1个boiler place类。我认为这是一场胜利。大规模重构的时间到了
Gson gson = new GsonBuilder()
.registerTypeAdapter(ServerResponse.class, new CustomDeserializer())
.create();
ServerResponse<MyObject> s = gson.fromJson(json, new TypeToken<ServerResponse<MyObject>>(){}.getType())