11

Jackson framework provides annotation based approach to emit the type information during serialization process.

I do not want to use @JsonSubTypes annotation in my super class(Animal).

Instead I want to tell my SubClasses i.e Dog and Elephant that Animal is their parent.

Is there any approach to do so without using annotation in Animal class.

If yes, please provide example of to do the same if possible.

Following is case which I am trying to resolve.JSON which "test" receives, contains "type" field as "dog" or "elephant".

I want to register these two classes as subtypes of "Animal" class but don't want to use @JsonSubTypes in Animal.

Any help would be appreciated. Thanks in advance.

@JsonTypeInfo( use = JsonTypeInfo.Id.NAME,  include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class Animal(){
      private String sound;
      private String type;

     //getters and setters

}

@JsonTypeName("dog")
Class Dog extends Animal(){
     //some attributes.
     //getters and setters
}

@JsonTypeName("elephant")
Class Elephant extends Animal(){
     //some attributes.
     //getters and setters
}


@Controller
public class MyController {

    //REST service
    @RequestMapping( value = "test")
    public  @ResponseBody String save(@RequestBody  Animal animal){

    System.out.println(animal.getClass());
    return success;

    }
}
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
user3153309
  • 151
  • 1
  • 6
  • You can register your subtypes by calling the objectMapper.registerSubtypes(Dog.class, Elephant.class) method. Is that you are looking for? – Alexey Gavrilov Jul 08 '14 at 12:58
  • Thank you Alexey.Please can u support your answer with some example. – user3153309 Jul 08 '14 at 13:03
  • I tried with objectMapper.registerSubtypes(Dog.class, Elephant.class)but it did not work . – user3153309 Jul 08 '14 at 13:28
  • http://stackoverflow.com/questions/10329706/json-deserialization-into-another-class-hierarchy-using-jackson – Peter Jul 08 '14 at 13:28
  • @user3153309 please show the code that did not work – Alexey Gavrilov Jul 08 '14 at 13:30
  • 2
    I included ObjectMapper mapper = new ObjectMapper(); mapper.registerSubtypes(Dog.class,Elephant.class); in "save" method (REST service) in MyController class. – user3153309 Jul 08 '14 at 13:49
  • You need to customize the instance of the ObjectMapper which is used for your controller. Check out this question: http://stackoverflow.com/questions/7854030/configurating-objectmapper-in-spring – Alexey Gavrilov Jul 08 '14 at 15:09
  • I have a scenario where at runtime a new class which extends Animal @JsonTypeName("cat") Class Cat extends Animal(){ //some attributes. //getters and setters } – user3153309 Jul 09 '14 at 05:05
  • Thanks for your help.I am not able to understand, why I need to customize ObjectMapper because I am not doing any kind of mapping between classes and serializer . – user3153309 Jul 09 '14 at 05:39
  • Do I need to add one more class that extends JsonSerializer? – user3153309 Jul 09 '14 at 05:42
  • @user3153309 I'm sorry that I'm not very helpful but can you please update your question explaining what you are trying to achieve and showing you JSON. – Alexey Gavrilov Jul 09 '14 at 12:40
  • Actually I have a case where user can add new class(Class Cat extends Animal) which extends Animal class at runtime. I need to tell this class that Widget class is its parent but not allowed to make any changes in Widget class.So I cannot add @JsonSubTypes.Type(value = Cat.class, name = "cat") on Widget Class.I need some way where this kind of information should be present only on subClasses and on SuperClass. – user3153309 Jul 09 '14 at 12:58
  • Not tested, but there is a very similar topic about your needs here : http://www.studytrails.com/java/json/java-jackson-Serialization-polymorphism.jsp – André Blaszczyk Nov 03 '15 at 20:00
  • Requesting you guys to check my answer and let me know your feedback. – SyntaX Nov 13 '15 at 05:13

2 Answers2

4

This answer will help in achieving what you want, but in a slightly different way. Create a separate class with necessary configuration and register it as the serialization/deserialization configuration class for Animal class as below:

Configuration Class:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @Type(value = Elephant.class, name = "cat"),
    @Type(value = Dog.class, name = "dog") })
abstract class PolymorphicAnimalMixIn {
    //Empty Class
}

To serialize or deserialize:

ObjectMapper mapper = new ObjectMapper();
mapper.getDeserializationConfig().addMixInAnnotations(Animal.class, PolymorphicAnimalMixIn.class);  
mapper.getSerializationConfig().addMixInAnnotations(Animal.class, PolymorphicAnimalMixIn.class);

//Sample class with collections of Animal
class Zoo {  
  public Collection<Animal> animals;  
}

//To deserialize
Animal animal = mapper.readValue("string_payload", Zoo.class);

//To serialize
Animal animal = mapper.writeValueAsString(zoo);

Reference credit: example 5

SyntaX
  • 2,090
  • 17
  • 30
1

You can use the Moonwlker library.

With it, you can create an ObjectMapper like this:

ObjectMapper objectMapper = new ObjectMapper();

 MoonwlkerModule module =
   MoonwlkerModule.builder()
     .fromProperty("type").toSubclassesOf(Animal.class)
     .build();

 objectMapper.registerModule(module);

And then use that mapper to (de)serialize. The Moonwlker website contains more details and configuration options.

bertilmuth
  • 276
  • 1
  • 11