2012-07-25 32 views
11

Ho postato la domanda in modo errato. Sto postando correttamente la domanda qui ...Jackson - Deserialize Variabile della classe generica

Sto ricevendo una stringa JSON come risposta HTTP. Conosco la struttura di esso. È il seguente:

public class Json<T> { 
    public Hits<T> hits; 
} 
public class Hits<T> { 
    public int found; 
    public int start; 
    public ArrayList<Hit<T>> hit; 
} 
public class Hit<T> { 
    public String id; 
    public Class<T> data; 
} 

Il campo "dati" può appartenere a qualsiasi classe. Lo saprò solo in fase di esecuzione. Lo prenderò come parametro. Questo è il modo in cui sto deserializzando.

public <T> void deSerialize(Class<T> clazz) { 
    ObjectMapper mapper = new ObjectMapper(); 
    mapper.readValue(jsonString, new TypeReference<Json<T>>() {}); 
} 

ma sto ottenendo un errore -

non può accedere java.lang.class.Class privato() da java.lang.Class. Impossibile impostare l'accesso. Impossibile rendere un costruttore java.lang.Class accessibile

+0

Perché duplicare la questione (vedi http://stackoverflow.com/questions/11664894/jackson-deserialize-using-generic-class/11681540)? – StaxMan

+0

vedere http://stackoverflow.com/questions/17400850/is-jackson-really-unable-to-deserialize-json-into-a-generic-type – lisak

risposta

1

Stai serializzando e deserializzando l'oggetto Class in JSON? Magari tenerlo come String in Hit e creare getter aggiuntivo che lanci Class.forName, ad es.

public class Hit { 
    public String id; 
    public String data; 
    public Class<?> getDataClass() throws Exception { 
     return Class.forName(data); 
    } 
} 
+0

Ho modificato completamente la domanda, ti invitiamo a rispondere? – gnjago

+1

L'errore che hai ottenuto dice: "Voglio instatinare un nuovo oggetto Class ma non posso eseguire' new Class() 'perché il costruttore è privato". Per di più non ha senso. Si prega di inserire una stringa JSON di esempio. Allora sarà molto più facile suggerire una soluzione. Sono abbastanza sicuro che la serializzazione/deserializzazione della proprietà di tipo Class sia un percorso errato. –

0

Deserialize classe generica variabile

...

Come faccio a dire a Jackson? Gson farà qualcosa di meglio?

The Gson user guide includes a section su esattamente quello che ho capito che stai cercando di realizzare, anche se quell'esempio documentato potrebbe essere ancora incompleto.

In a blog post, I covered in more detail the solution using Gson 1.7.1. Di seguito è riportato l'esempio di codice pertinente.

Simili (ma più coinvolte) soluzioni che usano Jackson (1.8.2) sono anche dimostrate e descritte nello stesso post del blog. (I diversi approcci ed esempi usano centinaia di righe di codice, in modo da li ho omesse reinserire qui.)

public class GsonInstanceCreatorForParameterizedTypeDemo 
{ 
public static void main(String[] args) 
{ 
    Id<String> id1 = new Id<String>(String.class, 42); 

    Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, 
    new IdInstanceCreator()).create(); 
    String json1 = gson.toJson(id1); 
    System.out.println(json1); 
    // actual output: {"classOfId":{},"value":42} 
    // This contradicts what the Gson docs say happens. 
    // With custom serialization, as described in a 
    // previous Gson user guide section, 
    // intended output may be 
    // {"value":42} 

    // input: {"value":42} 
    String json2 = "{\"value\":42}"; 

    Type idOfStringType=new TypeToken<Id<String>>(){}.getType(); 
    Id<String> id1Copy = gson.fromJson(json2, idOfStringType); 
    System.out.println(id1Copy); 
    // output: classOfId=class java.lang.String, value=42 

    Type idOfGsonType = new TypeToken<Id<Gson>>() {}.getType(); 
    Id<Gson> idOfGson = gson.fromJson(json2, idOfGsonType); 
    System.out.println(idOfGson); 
    // output: classOfId=class com.google.gson.Gson, value=42 
} 
} 

class Id<T> 
{ 
private final Class<T> classOfId; 
private final long value; 

public Id(Class<T> classOfId, long value) 
{ 
    this.classOfId = classOfId; 
    this.value = value; 
} 

@Override 
public String toString() 
{ 
    return "classOfId=" + classOfId + ", value=" + value; 
} 
} 

class IdInstanceCreator implements InstanceCreator<Id<?>> 
{ 
@SuppressWarnings({ "unchecked", "rawtypes" }) 
public Id<?> createInstance(Type type) 
{ 
    Type[] typeParameters = 
    ((ParameterizedType) type).getActualTypeArguments(); 
    Type idType = typeParameters[0]; 
    return new Id((Class<?>) idType, 0L); 
} 
} 
10

dovrai costruire JavaType in modo esplicito, se di tipo generico è solo dinamicamente disponibili:

// do NOT create new ObjectMapper per each request! 
final ObjectMapper mapper = new ObjectMapper(); 

public Json<T> void deSerialize(Class<T> clazz, InputStream json) { 
    return mapper.readValue(json, 
     mapper.getTypeFactory().constructParametricType(Json.class, clazz)); 
} 
+0

Questo non funziona dalla mia esperienza, potrebbe essere un bug però: https://github.com/FasterXML/jackson-databind/issues/254 – lisak

+0

bug di riferimento ha avuto altro problema (s) - Risoluzione di tipo generico, come mostrato sopra funzionerà, ma non affronterà altri possibili problemi. – StaxMan

+0

Sì, mi scuso, è stato risolto qui http://stackoverflow.com/questions/17400850/is-jackson-really-unable-to-deserialize-json-into-a-generic-type – lisak

2

Esempio interfaccia deserializzazione generica:

public interface Deserializable<T> { 
    static final ObjectMapper mapper = new ObjectMapper(); 

    @SuppressWarnings("unchecked") 
    default T deserialize(String rawJson) throws IOException { 
     return mapper.readValue(rawJson, (Class<T>) this.getClass()); 
    } 
} 
0

stringa JSON che ha bisogno di essere deserializzati dovrà contenere le informazioni sul tipo su PARAMETRI er T.
Dovrai inserire annotazioni Jackson su ogni classe che può essere passata come parametro T alla classe Json in modo che le informazioni sul tipo di parametro T possano essere lette/scritte nella stringa JSON da Jackson.

Supponiamo che T possa essere una classe che estende la classe astratta Result.

public class Json<T extends Result> { 
    public Hits<T> hits; 
} 

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 
@JsonSubTypes({ 
     @JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"), 
     @JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")}) 
public abstract class Result { 

} 

public class ImageResult extends Result { 

} 

public class NewsResult extends Result { 

} 

Una volta che ogni della classe (o la loro supertipo comune) che può essere passato come parametro T è annotato, Jackson includerà informazioni sui parametri T in JSON.Tale JSON può quindi essere deserializzato senza conoscere il parametro T in fase di compilazione.
Questo Jackson documentation link parla della deserializzazione polimorfica ma è utile fare riferimento anche a questa domanda.

Problemi correlati