I am attempting to work through a tutorial from Programmer Bruce that is supposed to allow the deserialization of polymorphic JSON.
The complete list can be found here Programmer Bruce tutorials (Great stuff btw)
I have worked through the first five with no problems but I have hit a snag on the last one (Example 6), which of course is the one I really need to get working.
I am getting the following error at compile time
The method readValue(JsonParser, Class) in the type ObjectMapper is not applicable for the arguments (ObjectNode, Class)
and it's being caused by the chunk of code
public Animal deserialize( JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectMapper mapper = (ObjectMapper) jp.getCodec(); ObjectNode root = (ObjectNode) mapper.readTree(jp); Class<? extends Animal> animalClass = null; Iterator<Entry<String, JsonNode>> elementsIterator = root.getFields(); while (elementsIterator.hasNext()) { Entry<String, JsonNode> element=elementsIterator.next(); String name = element.getKey(); if (registry.containsKey(name)) { animalClass = registry.get(name); break; } } if (animalClass == null) return null; return mapper.readValue(root, animalClass); } }
Specifically by the line
return mapper.readValue(root, animalClass);
Has anyone run into this before and if so, was there a solution?
I'd appreciate any help anyone can give Thanks in advance Jon D.
You can use this schema when defining XML Type hierarchies by using only the base XML Types. The XML schema defines XML Types that inherit from each other. In the JSON, an object carries no additional information about the type.
databind. ObjectMapper ) is the simplest way to parse JSON with Jackson. 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.
How to deserialize Date from JSON using Jackson. In order to correct deserialize a Date field, you need to do two things: 1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method.
@JsonProperty can change the visibility of logical property using its access element during serialization and deserialization of JSON. @JsonAlias defines one or more alternative names for a property to be accepted during deserialization.
How to control which fields get serialized/deserialized by Jackson and which fields get ignored. Control your JSON output with Jackson 2 by using a Custom Serializer. 2. Standard Deserialization Let's start by defining 2 entities and see how Jackson will deserialize a JSON representation to these entities without any customization:
We have type information, and the default JSON (de)serializer can deserialize objects for us. So, instead of manually deserializing every property, we can call into the JsonSerializer.Deserialize()method: return JsonSerializer.Deserialize(ref readerAtStart, targetType, options) as ApiFieldType;
Building a custom JsonConverter Kudos to the Microsoft Docs team for providing an example of polymorphic deserialization! This example supports deserializing a type hierarchy of Customer|Employee : Person. However, the example JsonConverteris really built around the shape of those Customerand Employeetypes.
A Truck instance is mapped to the named type Truck for example, And It runs a JUnit which checks the serialization / deserialization produces exactly the same object. If we take a look at the produced Json, it looks like the following: Jackson has added a @type attribute to each vehicle json.
As promised, I'm putting an example for how to use annotations to serialize/deserialize polymorphic objects, I based this example in the Animal
class from the tutorial you were reading.
First of all your Animal
class with the Json Annotations for the subclasses.
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) @JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "Dog"), @JsonSubTypes.Type(value = Cat.class, name = "Cat") } ) public abstract class Animal { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Then your subclasses, Dog
and Cat
.
public class Dog extends Animal { private String breed; public Dog() { } public Dog(String name, String breed) { setName(name); setBreed(breed); } public String getBreed() { return breed; } public void setBreed(String breed) { this.breed = breed; } } public class Cat extends Animal { public String getFavoriteToy() { return favoriteToy; } public Cat() {} public Cat(String name, String favoriteToy) { setName(name); setFavoriteToy(favoriteToy); } public void setFavoriteToy(String favoriteToy) { this.favoriteToy = favoriteToy; } private String favoriteToy; }
As you can see, there is nothing special for Cat
and Dog
, the only one that know about them is the abstract
class Animal
, so when deserializing, you'll target to Animal
and the ObjectMapper
will return the actual instance as you can see in the following test:
public class Test { public static void main(String[] args) { ObjectMapper objectMapper = new ObjectMapper(); Animal myDog = new Dog("ruffus","english shepherd"); Animal myCat = new Cat("goya", "mice"); try { String dogJson = objectMapper.writeValueAsString(myDog); System.out.println(dogJson); Animal deserializedDog = objectMapper.readValue(dogJson, Animal.class); System.out.println("Deserialized dogJson Class: " + deserializedDog.getClass().getSimpleName()); String catJson = objectMapper.writeValueAsString(myCat); Animal deseriliazedCat = objectMapper.readValue(catJson, Animal.class); System.out.println("Deserialized catJson Class: " + deseriliazedCat.getClass().getSimpleName()); } catch (Exception e) { e.printStackTrace(); } } }
Output after running the Test
class:
{"@type":"Dog","name":"ruffus","breed":"english shepherd"}
Deserialized dogJson Class: Dog
{"@type":"Cat","name":"goya","favoriteToy":"mice"}
Deserialized catJson Class: Cat
Hope this helps,
Jose Luis
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