Reputation: 553
How i can deserialize my object from json string, if i have only string name of my class, by canonical name invoke, and json string representation of object?
In other words, i need method like this:
public <T> T deserialize(String json, String className) {
// some code
}
We have class name and json string - and we need to deserialize json to java object.
I know how to deserialize json to object if i know the class of object, for example, we can use Jackson
:
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);
But in my task there is a different classes - it may be Cat.class
, Dog.class
, Car.class
and etc. And every class with different state. And i need universal method for deserializing.
I write something like:
public final class Utils implements Serializable {
private Utils () {
throw new AssertionError();
}
private static ObjectMapper objectMapper = new ObjectMapper();
public static String toJson(Object obj) {
String objectToJson;
try {
objectToJson = objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(String.format("Can't serialize object %s to JSON string", obj), e);
}
return objectToJson;
}
public static <T> T fromJson(String json, String className) throws ClassNotFoundException, IOException {
Class<?> clz = Class.forName(className);
return (T) objectMapper.readValue(json, clz);
}
}
And it works with example of car above, but with a warning cast exception
.
But maybe there is a better way?
Oh, and not all objects will be so simple. Some of them would encapsulate collections and other objects.
Upvotes: 0
Views: 2529
Reputation: 648
The problem stems from the compiler wanting to (virtually) make a different instance of this method for every type T that it is used on. However, there is nothing in the arguments to hang its hat on.
If the caller doesn't know what class to expect, other than a String representation of that class (which I'm assuming has been saved in the JSON as well?), what is he going to do with the result of this call? Since he doesn't know, he must be using it as simply Object, in which case the method might as well simply return Object.
If the caller does know the class, then he can pass in a Class as the argument, and you won't have any issues.
It occurred to me as writing this that ObectMapper must have a similar problem for some of its readValue methods, such as the one that accepts ResolvedType instead of Class. I notice that, in that class' source code, it includes /unchecked/
before the class. I"m not sure if that is to get around this issue or not, but it makes sense.
Upvotes: 1