Converter JSON String para object genérico em JAVA (com GSON)

Eu tenho uma API que retorna JSON. A resposta está em algum formato que pode caber em um object chamado ApiResult e contém um Context e um código int.

ApiResult é declarado de maneira genérica, por exemplo, ApiResult

Gostaria de saber como fazer com que GSON converta o JSON String de input em ApiResult

Até agora eu tenho:

 Type apiResultType = new TypeToken<ApiResult>() { }.getType(); ApiResult result = gson.fromJson(json, apiResultType); 

Mas isso ainda retorna converte o Contexto em um LinkedHashMap (o que eu assumo é o que o GSON retorna)

Você tem que saber o que T vai ser. O JSON de input é fundamentalmente apenas texto. GSON não tem idéia de qual object você quer que ele se torne. Se houver algo nesse JSON que você possa entender para criar sua instância T, você pode fazer algo assim:

 public static class MyJsonAdapter implements JsonDeserializer> { public ApiResult 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 ); } } } 

Eu estou usando um campo “_class” para decidir o que o meu X precisa e instanciá-lo via reflection (similar ao exemplo da PomPom). Você provavelmente não tem um campo tão óbvio, mas tem que haver alguma maneira de você olhar para o JsonElement e decidir com base no que é o tipo de X que deve ser.

Este código é uma versão hackeada de algo semelhante que fiz com GSON há algum tempo, veja a linha 184+ em: https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java

Você tem que fornecer Gson o tipo de T Como o gson não sabe qual adaptador deve ser aplicado, ele simplesmente retorna uma estrutura de dados.

Você tem que fornecer o genérico, como:

 Type apiResultType = new TypeToken>() { }.getType(); 

Se o tipo de T é conhecido apenas em tempo de execução, eu uso algo complicado:

  static TypeToken getGenToken(final Class raw, final Class gen) throws Exception { Constructor 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); } 

Sua chamada seria (mas substituindo String.class por uma variável):

 Type apiResultType = getGenToken(ApiResult.class, String.class); 

Eu uso a biblioteca JacksonJson, bastante semelhante ao GSon. É possível converter a string json para algum tipo de object genérico desta maneira:

 String data = getJsonString(); ObjectMapper mapper = new ObjectMapper(); List packages = mapper.readValue(data, List.class); 

Talvez esta seja a maneira correta com GSON no seu caso:

 ApiResult result = gson.fromJson(json, ApiResult.class);