我有一个返回JSON的Api。响应采用某种格式,可以放入名为ApiResult的对象中,并包含Context <T>
和int代码。
ApiResult以通用方式声明,例如ApiResult<SomeObject>
我想知道如何让GSON将传入的JSON字符串转换为ApiResult<T>
到目前为止,我有:
Type apiResultType = new TypeToken<ApiResult<T>>() { }.getType();
ApiResult<T> result = gson.fromJson(json, apiResultType);
但是这仍然会返回将Context转换为LinkedHashMap(我假设它是GSON的回归)
答案 0 :(得分:5)
你必须知道T会是什么。传入的JSON基本上只是文本。 GSON不知道你希望它成为什么对象。如果JSON中有一些东西可以用来创建你的T实例,你可以这样做:
public static class MyJsonAdapter<X> implements JsonDeserializer<ApiResult<X>>
{
public ApiResult<X> deserialize( JsonElement jsonElement, Type type, JsonDeserializationContext context )
throws JsonParseException
{
String className = jsonElement.getAsJsonObject().get( "_class" ).getAsString();
try
{
X myThing = context.deserialize( jsonElement, Class.forName( className ) );
return new ApiResult<>(myThing);
}
catch ( ClassNotFoundException e )
{
throw new RuntimeException( e );
}
}
}
我正在使用字段“_class”来决定我的X需要什么,并通过反射实例化它(类似于PomPom的例子)。你可能没有这么明显的领域,但是你必须有一些方法来查看JsonElement,并根据它应该是什么类型的X来决定。
此代码是类似我之前与GSON类似的黑客版本,请参阅第184行:https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java
答案 1 :(得分:1)
你必须为Gson提供T
的类型。由于gson不知道应该应用什么适配器,它只是返回一个数据结构。
您必须提供通用,例如:
Type apiResultType = new TypeToken<ApiResult<String>>() { }.getType();
如果只在运行时知道T的类型,我会使用一些棘手的东西:
static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception {
Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class);
constr.setAccessible(true);
ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[] { gen }, null);
return TypeToken.get(paramType);
}
您的电话会是(但用变量替换String.class
):
Type apiResultType = getGenToken(ApiResult.class, String.class);
答案 2 :(得分:1)
我的解决方案是使用org.json和Jackson
以下是将json对象包装到数组中,将对象转换为列表以及将json字符串转换为类型的方法。
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public <T> List<T> parseJsonObjectsToList(JSONObject parentJson, String key, Class<T> clazz) throws IOException {
Object childObject = parentJson.get(key);
if(childObject == null) {
return null;
}
if(childObject instanceof JSONArray) {
JSONArray jsonArray = parentJson.getJSONArray(key);
return getList(jsonArray.toString(), clazz);
}
JSONObject jsonObject = parentJson.getJSONObject(key);
List<T> jsonList = new ArrayList<>();
jsonList.add(getObject(jsonObject.toString(), clazz));
return jsonList;
}
public <T> List<T> getList(String jsonStr, Class clazz) throws IOException {
ObjectMapper objectMapper = OBJECT_MAPPER;
TypeFactory typeFactory = objectMapper.getTypeFactory();
return objectMapper.readValue(jsonStr, typeFactory.constructCollectionType(List.class, clazz));
}
public <T> T getObject(String jsonStr, Class<T> clazz) throws IOException {
ObjectMapper objectMapper = OBJECT_MAPPER;
return objectMapper.readValue(jsonStr, clazz);
}
// To call
parseJsonObjectsToList(creditReport, JSON_KEY, <YOU_CLASS>.class);
答案 3 :(得分:0)
我使用JacksonJson库,与GSon非常相似。可以通过这种方式将json字符串转换为某种泛型类型对象:
String data = getJsonString();
ObjectMapper mapper = new ObjectMapper();
List<AndroidPackage> packages = mapper.readValue(data, List.class);
在您的情况下,使用GSON可能这是正确的方法:
ApiResult<T> result = gson.fromJson(json, ApiResult.class);