I'm trying to deserialize a Json array to an ArrayList of objects. I have found some documentation on what i'm trying to do, but I'm getting an error on compile.
Here is how I'm trying to approach it with Jackson 2.2.2:
ArrayList<Friends> list = objectMapper.readValue(result, new TypeReference<ArrayList<Friends>>() {});
The error I get is:
The method readValue(String, Class<T>) in the type ObjectMapper is not applicable for the arguments (String, new TypeReference<ArrayList<Friends>>(){})
I'm guessing some of the references I have been reading is based on an older version of Jackson. How can this be accomplished in Jackson 2.2 +
Try the following:
JavaType type = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Friends.class);
ArrayList<Friends> friendsList = objectMapper.readValue(result, type);
Note that I pulled this from the following answer: Jackson and generic type reference
As of Jackson 1.3 (a while back) they recommend you use TypeFactory.
EDIT
On further inspection, what you have above is working for me... I'm able to pass in a TypeReference sub class to readValue and everything works correctly. Are you sure you have the right type of TypeReference imported? Usually those types of errors are from accidentally importing the wrong type (some other library might have a TypeReference class).
Related
I am parsing JSON string from a byte-array and casting it as an object.
How do I determine the class of the object?
Object objDeserialized = gson.fromJson(jsonFromString, Object.class);
//It could be type Message or RoomDetail
gson.fromJson(jsonFromString, Object.class);
In general, this won't work because of Object.class. Gson prohibits overriding the Object class deserialization and uses ObjectTypeAdapter (see the primary Gson constructor as of Gson 2.8.0 and probably much earlier):
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);
If you want to use Object.class, you have to cast the result to either a primitive wrapper, null, or a List<E> or Map<K,V> -- and make some sort of analysis yourself. The rationale behind it is that you must know the result class in advance to make sure you're getting a proper deserialized object.
The best thing you can do here is making your custom parent super-type (does not really matter if it's a class or an interface), say class Message extends Base and class RoomDetail extends Base, and then registering a JsonDeserializer<Base> implementation to a GsonBuilder which can attempt to detect the real type of the Base instance. After that you can do:
gson.fromJson(jsonSource, Base.class);
See more:
Polymorphic objects deserialization:
How to parse dynamic json in android with retrofit 2 using annotations
How do I parse a nested JSON array of object with a custom Gson deserializer?
Json response parser for Array or Object
Google Gson extras, never been published as artifacts, but may be an inspiration point for you:
https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
If you do not know the type of the JSON you want to parse you could use the JsonParser from the Gson lib to parse the JSON instead of the Gson class directly. e.g.
JsonParser parser = new JsonParser(jsonFromString);
JsonObject obj = parser.parse().getAsJsonObject();
You could then look at the properties of the JsonObject you have created to see what it is. e.g.
if (obj.has("somePropertyNameIKnownIsAMemberOfRoomDetail")) {
RoomDetail roomDetail = gson.fromJson(jsonFromString, RoomDetail.class);
} else {
Message message = gson.fromJson(jsonFromString, Message.class);
}
So, I've got a String that is the result of a toJson method I've implemented on a class, and have confirmed in my test code that it is the correct Json representation of my class. My goal is to turn this String into a JsonObject and pass it to a constructor, using Gson. However, I'm running into an odd problem.
This is the code I'm calling:
Gson gson = new Gson();
JsonObject jObj = gson.fromJson(jsonString, JsonObject.class);
I have used literally this exact same snippet of code before in many places in my project, for other classes, and it has worked fine. I even copied one of those functional snippets of code into this test class and tried it. However, every version I try results in the same thing--jObj is an empty set of brackets.
I don't understand how it's happening. I've confirmed that jsonString has all the fields it should need. Why is Gson returning an empty JsonObject? No exceptions are being thrown.
Ok so i know this is a little old but I had the same exact issue. The resolution was changing the jar file. I had a similar code sample working in another project but then I was experiencing the exact same problem in another. Well the problem was an older gson-2.1.jar. Updated the problem application to the matching gson-2.3.1.jar and all was working. Hope this helps.
From your comment that says the string is {"varName":1, "otherVarName":2, "thirdVarName":3.4}, looks like the serialized object was a Map. You may need to specify the type token:
gson.fromJson(jsonString, new TypeToken<Map<K,V>>() {}.getType());
where K and V are the key and value types of the map. If it is not a Map, specify whatever class the jsonString was obtained from.
For my case, I was accidentally using the following initializer in my dagger module.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()
I removed the setFieldNamingPolicy and it worked.
I had this issue as well.
I was using
return gson.fromJson(response, JsonObject::class.java)
And I was receiving an object with only the default values populated.
I had to explicitly define the serialized names for each property in my JsonObject class that was different from how it was named in the json response.
For example, if in the json I was parsing the field name was "total_score', but my JsonObject had a field named "totalProperty", I had to use the #SerialedName annotation to define the relationship.
#SerializedName("total_score")
val TotalScore : Int = 0
In my spring(mvc) web application, I am using org.codehaus.jackson.map.ObjectMapper in my scala code to map my json to scala objects using case classes. My Json String is an array of json objects objects. so I am using:
val user = mapper.readValue(myJson, classOf[List[MyClass]])
This line throws an error:
Exception in thread "main"
org.codehaus.jackson.map.JsonMappingException: Can not construct
instance of scala.collection.immutable.List, problem: abstract types
can only be instantiated with additional type inform
Am I using it right or is there any other way?
The problem is the Java type erasure. classOf[List[MyClass]] at runtime is the same as classOf[List[_]]. That is why Jackson cannot know, which types of the elements to create.
Luckily Jackson does support parsing with the JavaType, which describes the types themselves.
Here a simple sample in Java:
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class);
mapper.readValue(myJson, type);
Because of type erasure, the parameterized type of the List is lost at runtime.
Instead, use the Scala module for Jackson and you can simply do:
mapper.readValue(myJson, new TypeReference[List[MyClass]])
So long as the Scala module has been registered - this means a Scala List will be created.
I used Jackson to serialize a Map<Class<?>, BaseClass>. There are multiple subclasses of BaseClass, and each one is properly annotated to be serialized/deserialized by Jackson.
Is it possible to invoke ObjectMapper.readValue(file, Subclass.class) and get a Subclass instance back?
If so, how do I avoid this exception?
com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class java.lang.Class<java.lang.Object>]
at com.fasterxml.jackson.databind.deser.DeserializerCache._handleUnknownKeyDeserializer(DeserializerCache.java:578)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findKeyDeserializer(DeserializerCache.java:168)
at com.fasterxml.jackson.databind.DeserializationContext.findKeyDeserializer(DeserializationContext.java:404)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.createContextual(MapDeserializer.java:231)
at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:581)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:369)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.findDeserializer(StdDeserializer.java:842)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:514)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:292)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:241)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:381)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3154)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3047)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2100)
Shouldn't Jackson know how to deserialize Class<?> since it is a core JDK type?
UPDATE: I found https://stackoverflow.com/a/13954871/14731 which discusses how to implement Polymorphism in Jackson. That answers question #1 but leaves us with questions #2 and #3.
UPDATE2: Interesting. I found ClassSerializer.java but there is no corresponding ClassDeserializer.java in https://github.com/FasterXML/jackson-databind/tree/master/src/main/java/com/fasterxml/jackson/databind/deser/std
UPDATE3: Filed a bug report: https://github.com/FasterXML/jackson-databind/issues/630
This is a known bug that should be fixed in version 2.5.0: https://github.com/FasterXML/jackson-databind/issues/630
I found some strange behavior of the Jackson JSON Processor library and i am curious whether this is intentional or a bug. Please have a look at the code below:
#JsonTypeInfo(use = Id.NAME)
public class Nut {}
…
ObjectMapper mapper = new ObjectMapper();
Nut nut = new Nut();
Object object = new Nut();
Nut[] nuts = new Nut[] { new Nut() };
Object[] objects = new Object[] { new Nut() };
System.out.println(mapper.writeValueAsString(nut));
System.out.println(mapper.writeValueAsString(object));
System.out.println(mapper.writeValueAsString(nuts));
System.out.println(mapper.writeValueAsString(objects));
Output:
{"#type":"Nut"}
{"#type":"Nut"}
[{"#type":"Nut"}]
[{}]
What i expect (and want) is the following:
{"#type":"Nut"}
{"#type":"Nut"}
[{"#type":"Nut"}]
[{"#type":"Nut"}] // <<< type information included
Do i miss something or should i file a bug report?
This is expected behavior. When traversing an object graph for serialization, Jackson uses the declared type of an object when determining what type information to include. The elements in objects have declared type Object, which you haven't told Jackson to include any type information for.
Jackson only looks at the runtime type of the top-level argument to writeValueAsString, because the method argument has type Object; it's not possible in Java to know the declared type of an object passed as an argument to a method (even with generics, thanks to type erasure), so your first two examples (writeValueAsString(nut) and writeValueAsString(object) are effectively identical).
More information here: http://jackson-users.ning.com/forum/topics/mapper-not-include-type-information-when-serializing-object-why