java - Deserializar un tipo genérico con Jackson
android guice (2)
Estoy tratando de hacer una clase que use el Jackson para deserializar los POJO.
Se parece a esto...
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));
}
}
Tengo 2 preguntas sobre esta implementación.
La primera es que estoy pasando el tipo de clase a los métodos para que el asignador de objetos conozca el tipo que debe deserializar. ¿Hay alguna forma mejor de usar genéricos?
También en el método get estoy lanzando un objeto devuelto por objectMapper a T. Esto parece una forma particularmente desagradable de hacerlo ya que tengo que lanzar T aquí y luego también tengo que convertir el tipo de objeto del método que lo está llamando.
Estoy usando Roboguice en este proyecto, por lo que sería bueno si pudiera cambiar el tipo mediante inyección y luego anotar el objeto que el Tipo genérico lo necesito para devolver. Leí acerca de TypeLiteral y me pregunto si podría resolver este problema.
La primera es que estoy pasando el tipo de clase a los métodos para que el asignador de objetos conozca el tipo que debe deserializar. ¿Hay alguna forma mejor de usar genéricos?
Desafortunadamente no, y esto se debe a borrado de tipo.
También en el método get estoy lanzando un objeto devuelto por objectMapper a T. Esto parece una forma particularmente desagradable de hacerlo ya que tengo que lanzar T aquí y luego también tengo que convertir el tipo de objeto del método que lo está llamando.
Haz esto en su lugar:
@Override
public T get(String content, Class<T> clazz) throws IOException {
return objectMapper.readValue(content, clazz);
}
Estoy usando Roboguice en este proyecto, por lo que sería bueno si pudiera cambiar el tipo mediante inyección y luego anotar el objeto que el Tipo genérico lo necesito para devolver. Leí acerca de TypeLiteral y me pregunto si podría resolver este problema.
Realmente no entiendo lo que quieres lograr, pero como necesitas pasar la clase de todos modos, ¿todavía es posible?
Así que creo que lo descubrí al final. Comente si ve algo mal con lo que estoy haciendo.
La interfaz se define así ...
public interface Deserialiser<T> {
T get(String content) throws IOException;
List<T> getList(String content) throws IOException;
}
La implementación de la interfaz es así ...
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));
}
}
Ato los 2 como ...
bind(new TypeLiteral<Deserialiser<User>>(){}).annotatedWith(Names.named("user")).to(new TypeLiteral<DeserialiserImp<User>>(){});
Entonces todo lo que necesito hacer para usarlo es esto ...
@Inject
@Named("user")
private Deserialiser<User> deserialiserImp;
public void test(String userString) {
User user = deserialiserImp.get(UserString);
}
Este patrón también podría funcionar bien si la clase es una clase abstracta para usar en un objeto DAO
Este artículo me ayudó