2012-10-29 30 views
5

Sto cercando di creare una classe che utilizzi Jackson per deserializzare i POJO.Deserializzazione di un tipo generico con Jackson

Sembra che questo ...

public class DeserialiserImp<T> implements Deserialiser<T> { 

     protected ObjectMapper objectMapper = new ObjectMapper(); 

     @Override 
     public T get(String content, Class clazz) throws IOException { 
      return (T) objectMapper.readValue(content, clazz); 
     } 

     @Override 
     public List<T> getList(String content, Class clazz) throws IOException { 
      return objectMapper.readValue(content, TypeFactory.collectionType(ArrayList.class, clazz)); 
     } 

    } 

Ho 2 domande su questa implementazione.

Il primo è che sto passando il tipo di classe nei metodi in modo che objectmapper conosca il tipo che dovrebbe deserializzare. C'è un modo migliore di usare i farmaci generici?

Anche nel metodo get sto trasmettendo un oggetto restituito da objectMapper a T. Questo sembra un modo particolarmente sgradevole di farlo in quanto devo lanciare T qui e poi devo anche lanciare il tipo di oggetto dal metodo che lo sta chiamando

Sto usando Roboguice in questo progetto quindi sarebbe bello se potessi cambiare il tipo tramite l'iniezione e quindi annotare l'oggetto di cui il tipo generico di cui ho bisogno per tornare. Ho letto su TypeLiteral e mi chiedevo se poteva risolvere questo problema?

+0

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

risposta

5

Quindi penso di averlo capito alla fine. Per favore commenta se vedi qualcosa di sbagliato in quello che sto facendo.

L'interfaccia è definita in questo modo ...

public interface Deserialiser<T> { 

    T get(String content) throws IOException; 

    List<T> getList(String content) throws IOException; 
} 

L'implementazione dell'interfaccia è come questo ...

public class DeserialiserImp<T> implements Deserialiser<T> { 

    private ObjectMapper objectMapper = new ObjectMapper(); 
    private final Class<T> klass; 

    @Inject 
    public DeserialiserImp(TypeLiteral<T> type){ 
     this.klass = (Class<T>) type.getRawType(); 
    } 

    @Override 
    public T get(String content) throws IOException { 
     return objectMapper.readValue(content, klass); 
    } 

    @Override 
    public List<T> getList(String content) throws IOException { 
     return objectMapper.readValue(content, TypeFactory.collectionType(ArrayList.class, klass)); 
    } 

} 

Mi legano il 2 in questo modo ..

bind(new TypeLiteral<Deserialiser<User>>(){}).annotatedWith(Names.named("user")).to(new TypeLiteral<DeserialiserImp<User>>(){}); 

Poi tutto quello che devo fare per usarlo è questo ...

@Inject 
@Named("user") 
private Deserialiser<User> deserialiserImp; 

public void test(String userString) { 
    User user = deserialiserImp.get(UserString); 
} 

Questo modello potrebbe anche funzionare bene se la classe come una classe astratta da utilizzare in un oggetto DAO

This articolo mi ha aiutato

5

Il primo è che sto passando il tipo di classe nei metodi in modo che objectmapper conosca il tipo da deserializzare. C'è un modo migliore usando i farmaci generici?

Sfortunatamente no, e questo a causa della cancellazione del tipo.

Anche nel metodo get sto esprimono un oggetto restituito dal ObjectMapper a T. Ciò sembra particolarmente brutto modo di farlo, come ho dover lanciare T qui e poi devo lanciare anche il tipo di oggetto da il metodo che lo sta chiamando.

fare questo, invece:

@Override 
public T get(String content, Class<T> clazz) throws IOException { 
    return objectMapper.readValue(content, clazz); 
} 

Sto usando Roboguice in questo progetto quindi sarebbe bello se potessi modificare il tipo attraverso l'iniezione e quindi annotare l'oggetto il tipo generico Ne ho bisogno per tornare. Ho letto su TypeLiteral e chiedendomi se poteva risolvere questo problema?

Non capisco davvero cosa vuoi ottenere, ma dal momento che devi comunque passare la classe, è ancora possibile?

+0

Il mio punto sull'utilizzo TypeLiteral venire s da questa domanda http://stackoverflow.com/questions/3370641/how-does-guices-typeliteral-work Si dice che "Il trucco utilizzato qui è che le firme dei super-tipi generici sono memorizzate in sottoclassi e quindi sopravvivere cancellatura ". Sto sperando di non passare nel tipo. – jiduvah

+1

Ok capisco. Non vedo alcuna soluzione pratica qui, è necessario memorizzare il tipo da qualche parte (oggetto Class semplice come campo, usando TypeLiteral ecc ...) per recuperarlo in fase di runtime. Non penso che passare il tipo ogni volta sia un grosso problema, poiché è richiesto da tutte le librerie non riequilibrate. Sarei interessato a vedere un altro approccio però. –

+0

Beh, sto cercando di rendere il codice più pulito. Al momento passo il tipo come generico quando instanzia il deserialiserImp, devo passare nella classe nel metodo, quindi devo anche lanciare l'oggetto che ricevo. Quindi sono 3 volte che faccio riferimento al tipo. Sembra molto messoso – jiduvah

Problemi correlati