javajacksonobjectmapper

Deserialise the JSON into custom object enclosed in optional


I have 2 classes as such

class Parent {

   private final Optional<Child> child;
  
   @JsonCreator
   Parent(@JsonProperty("child") Optional<Child> child) {
         this.child = child;
   }
}

class Child {

   private final Optional<String> name;

   @JsonCreator
   Child(@JsonProperty("name")Optional<String> name){
     this.name = name;
   }

}

The json that I intend to deserialize into the Parent class looks like below:

{
  "child" : {
     "name" : "abc"
  }
}

To deserialize itself I am using the ObjectMapper:

ObjectMapper mapper = new ObjectMapper()
                .registerModule(new Jdk8Module());

However at runtime getting the exception below:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.util.Optional` (no Creators, like default constructor, exist): cannot deserialize from Object value

A lot of answer on stack suggest the use of registerModule like this one. Am I missing something in the use of registerModule?


Solution

  • I think the problem lies somewhere else. Optionals are not quite intended to be a class parameters. They should be used as a method return values:

    Of course, people will do what they want. But we did have a clear intention when adding this feature, and it was not to be a general purpose Maybe or Some type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors. The key here is the focus on use as a return type.

    Source: https://blog.joda.org/2014/11/optional-in-java-se-8.html

    So I think you should focus on serializing/deserializing the null values, and use optionals only as a return value from getter like this:

    class Parent {
    
       private final Child child;
      
       @JsonCreator
       Parent(Child child) {
             this.child = child;
       }
    
       Optional<Child> getChild() {
          return Optional.ofNullable(child);
       }
    }
    
    class Child {
    
       private final String name;
    
       @JsonCreator
       Child(String name){
         this.name = name;
       }
    
       Optional<String> getName() {
          return Optional.ofNullable(name);
       }
    
    }
    

    If you really want to mark the property that it could be a null, then you may use @Nullable annotation from org.jetbrains package. Then, if you use Intellij Idea for coding, it would check for suspicious code fragments that may lead to NullPointerExcetpion.

    Source: https://www.jetbrains.com/help/idea/annotating-source-code.html#contract-annotations