2013-07-17 22 views
7

Ho un Api che restituisce JSON. La risposta è in un formato che può rientrare in un oggetto chiamato ApiResult e contiene un codice Context <T> e un codice int.Converti stringa JSON in oggetto generico in JAVA (con GSON)

ApiResult viene dichiarato in modo generico, ad es. ApiResult<SomeObject>

vorrei sapere come ottenere GSON per convertire il JSON String in arrivo per ApiResult<T>

Finora ho:

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

Ma questo restituisce comunque converte il contesto per un LinkedHashMap invece (che presumo sia ciò a cui GSON ricade)

risposta

1

È necessario fornire a GSON il tipo di T. Siccome gson non sa quale adattatore dovrebbe essere applicato, semplicemente restituisce una struttura dati.

vostro devono fornire il generico, come:

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

Se tipo di T è nota solo in fase di esecuzione, io uso qualcosa di complicato:

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); 
    } 

La chiamata sarebbe (ma sostituendo String.class con una variabile):

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

così prendo che T è di tipo stringa nel tuo esempio . Ma non ho una stringa ma una T. Come cambierà l'ultima affermazione (l'incarico)? – Yannis

+0

Sì, stavo assumendo che tu abbia un 'Classe ' var da impostare al posto di 'String.class' (in' getGenToken'). Ma forse questo non si applica al tuo caso. – PomPom

4

Devi sapere cosa T sta per essere. Il JSON in arrivo è fondamentalmente solo testo. GSON non ha idea di quale oggetto desideri che diventi. Se c'è qualcosa in quel JSON che è possibile indizio off di creare l'istanza T, si può fare qualcosa di simile:

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); 
     } 
    } 
} 

sto usando un campo "_class" per decidere quello che il mio X ha bisogno di essere e istanzialo tramite riflessione (simile all'esempio di PomPom). Probabilmente non hai un campo così ovvio, ma ci deve essere un modo per te di guardare JsonElement e decidere in base a che tipo di X dovrebbe essere.

Questo codice è una versione modificata di qualcosa di simile che ho fatto con GSON un po 'indietro, vedi linea 184+ a: https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java

+0

Controllerò il codice e ho il sospetto che dovessi fare qualcosa di simile a te suggerito ma lo stesso codice (o simile) in .NET funziona. Ciò significa che devo modificare un'API generica per soddisfare una lingua specifica? .NET può trovare in fase di esecuzione cosa sia T senza che io debba avere un campo _class speciale in un json. – Yannis

+0

Senza conoscere il codice .NET, non ho idea di come funzioni. T non ha valore di classe, quindi .NET non saprebbe quale classe usare a meno che qualcosa non lo dica. –

0

Io uso biblioteca JacksonJson, molto simile a GSON. E 'possibile convertire la stringa JSON a qualche oggetto tipo generico in questo modo:

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

Forse questo è il modo corretto con il GSON nel tuo caso:

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