I am trying to make a class that uses the Jackson to deserialize POJO's.
It looks like this...
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));
}
}
I have 2 questions about this implementation.
The first is that I am passing the class type into the methods so the objectmapper knows the type that should deserialize. Is there a better way using generics?
Also in the get method I am casting an object returned from the objectMapper to T. This seems particularly nasty way of doing it as I have to cast T here and then I have to also cast the object type from the method which is calling it.
I am using Roboguice in this project so it would be nice if I could change the type through injection and then annotate the object which the Generic type I need it to return. I read about TypeLiteral and wondering if it could solve this problem?
Class TypeReference<T> This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used.
Jackson is a powerful and efficient Java library that handles the serialization and deserialization of Java objects and their JSON representations. It's one of the most widely used libraries for this task, and runs under the hood of many other frameworks.
The Jackson ObjectMapper can parse JSON from a string, stream or file, and create a Java object or object graph representing the parsed JSON. Parsing JSON into Java objects is also referred to as to deserialize Java objects from JSON. The Jackson ObjectMapper can also create JSON from Java objects.
Jackson allows you to read JSON into a tree model: Java objects that represent JSON objects, arrays and values. These objects are called things like JsonNode or JsonArray and are provided by Jackson.
The first is that I am passing the class type into the methods so the objectmapper knows the type that should deserialize. Is there a better way using generics?
Unfortunately not, and this is because of type erasure.
Also in the get method I am casting an object returned from the objectMapper to T. This seems particularly nasty way of doing it as I have to cast T here and then I have to also cast the object type from the method which is calling it.
Do this instead :
@Override
public T get(String content, Class<T> clazz) throws IOException {
return objectMapper.readValue(content, clazz);
}
I am using Roboguice in this project so it would be nice if I could change the type through injection and then annotate the object which the Generic type I need it to return. I read about TypeLiteral and wondering if it could solve this problem?
I don't really understand what you want to achieve, but since you need to pass the class anyways, is that still possible ?
So I think I figured it out in the end. Please comment if you see something wrong with what I am doing.
The interface is defined like so...
public interface Deserialiser<T> {
T get(String content) throws IOException;
List<T> getList(String content) throws IOException;
}
The implementation of the interface is like this...
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));
}
}
I bind the 2 like so..
bind(new TypeLiteral<Deserialiser<User>>(){}).annotatedWith(Names.named("user")).to(new TypeLiteral<DeserialiserImp<User>>(){});
Then all I need to do to use it is this...
@Inject
@Named("user")
private Deserialiser<User> deserialiserImp;
public void test(String userString) {
User user = deserialiserImp.get(UserString);
}
This pattern could also work well if the class as an abstract class to use in a DAO object
This article helped me
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With