2

ClassA

public class ClassA {
   private String id;
   private Object rawData;
}

ClassB

public class ClassB {
   private String name;
}

ClassC

public class ClassC {
   String address;
}

Main Class

public class MainExample {
   public static void main( String[] args ) throws IOException {

      ObjectMapper mapper = new ObjectMapper(  );

      ClassB classB = new ClassB();
      //ClassC classC = new ClassC();
      ClassA classA = new ClassA();
      classA.setRawData(  classB );
      //classA.setRawData(  classC );

      if (classA.getRawData() instanceof ClassB) {
         System.out.println("true ");
      } else {
         System.out.println("false");
      }

      String classAString = mapper.writeValueAsString( classA );
      ClassA a = mapper.readValue( classAString, ClassA.class );

      if (a.getRawData() instanceof ClassB) {
         System.out.println("true ");
      } else {
         System.out.println("false");
      }
   }
}

why first if-else printing "TRUE" and second if-else printing "false"??

How can I check the type of rawData?

Pratap A.K
  • 4,337
  • 11
  • 42
  • 79
  • look at what `classAString` is, there is no more information regarding the type of `rawData` in it. And since you omit any type information on the java side as well (since you use `Object`) it is impossible for the mapper to map to a `ClassB` - why would / should it? There is no reason for it to create an instance of that type. – luk2302 Oct 09 '18 at 09:32

2 Answers2

6

mapper.writeValueAsString(classA) will serialise the instance into something similar to {"rawData":{}}.

While deserialising {} the default mapper would fail, because it treats {} as a non-serializable type. If you've configured SerializationFeature.FAIL_ON_EMPTY_BEANS to false before, you will have an empty Object created.

You might want to use mapper.enableDefaultTyping(); to include type information in JSON, and thereby deserialize into the correct types.

NOTE: use of Default Typing can be a potential security risk if incoming content comes from untrusted sources, and it is recommended that this is either not done, or, if enabled, use setDefaultTyping passing a custom TypeResolverBuilder implementation that white-lists legal types to use.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • thanks for highlighting risk. If you provide an example for TypeResolverBuilder it will be great. Is it fine to use setDefaultTyping without TypeResolverBuilder if the source is trusted (both sender and receiver belongs to same company)? – Pratap A.K Oct 09 '18 at 10:08
  • 1
    @PratapA.K: here's an example of `CustomTypeResolverBuilder `: https://stackoverflow.com/questions/12353774/how-to-customize-jackson-type-information-mechanism Yes, It's fine if the sources are safe. – Andrew Tobilko Oct 09 '18 at 10:22
  • @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, property="@class") private Object rawData; .........below also working. Is both are same? – Pratap A.K Oct 10 '18 at 04:51
  • @PratapA.K AFAIK, these annotations will be compound into `TypeResolverBuilder` for you – Andrew Tobilko Oct 10 '18 at 07:30
  • @PratapA.K but if you enable "default typing", it will override annotation behaviour – Andrew Tobilko Oct 10 '18 at 07:32
  • Thanks for the clarification – Pratap A.K Oct 10 '18 at 07:35
1

We can also use @JsonTypeInfo from jackson library to keep class information

import com.fasterxml.jackson.annotation.JsonTypeInfo;

public class ClassA {

   private String id;

   @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, property="@class")
   private Object rawData;
}

then both if-else prints "True".

Pratap A.K
  • 4,337
  • 11
  • 42
  • 79