javajsonjacksonvavr

Serialize and Deserialize Java object having vavr list


I have a Java object with vavr list.

@Value
@Builder(toBuilder = true)
public class Customer {

    private final List<Remark> remarks;

}

When I serialize the object objectwriter.writeValueAsString(currentDossier) and print the values then in the JSON output I see,

    { "remarks" : {
        "empty" : true,
        "lazy" : false,
        "async" : false,
        "traversableAgain" : true,
        "sequential" : true,
        "ordered" : false,
        "singleValued" : false,
        "distinct" : false,
        "orNull" : null,
        "memoized" : false
      } 
    }

where remarks is a vavr list field inside the object.

Now if I try to deserialize the same value into the object objectMapper.readValue(json, Customer.class) then I get error:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.vavr.collection.List` 
(no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: (String)"{"remarks" : {

Why is the seralized JSON text not working when trying to deserialze?

  @Test
  public void mapperForVavrList() throws JsonProcessingException {
    Customer cus = Customer.builder().remarks(List.empty()).build();

    ObjectWriter ow = new ObjectMapper()
      .writer().withDefaultPrettyPrinter();

    String json1 = ow.writeValueAsString(cus);

    log.info(json1);

    ObjectMapper objectMapper = new ObjectMapper();
    Customer cus2 = objectMapper.readValue(json1, Customer.class);

    log.info(cus2.toString());

  }

Is there any other way in the Java code to print vavr object in textual format and convert it back to POJO?


Solution

  • You can easily serialize/deserialize vavr objects to/from JSON with jackson. What you need to do is to register VavrModule on the instance of the ObjectMapper:

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

    To get VavrModule you need to add the dependency to vavr-jackson

    EDIT

    Here you can find a complete working example:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import io.vavr.collection.List;
    import io.vavr.jackson.datatype.VavrModule;
    import org.apache.commons.lang3.builder.ToStringBuilder;
    
    import java.io.IOException;
    
    class Lol2 {
    
        public static void main(String[] args) throws IOException {
            Customer c = new Customer();
            Remark r = new Remark();
            r.whatever = "whatever";
            c.remarks = List.of(r);
    
            ObjectMapper ow = new ObjectMapper();
            ow.registerModule(new VavrModule());
    
            System.out.println(c);
            String json = ow.writeValueAsString(c);
            System.out.println(json);
            Customer c2 = ow.readValue(json, Customer.class);
            System.out.println(c2);
    
        }
    }
    
    class Customer {
    
        List<Remark> remarks;
    
        public List<Remark> getRemarks() {
            return remarks;
        }
    
        public void setRemarks(List<Remark> remarks) {
            this.remarks = remarks;
        }
    
        @Override
        public String toString() {
            return new ToStringBuilder(this)
                .append("remarks", remarks)
                .toString();
        }
    }
    
    class Remark {
    
        String whatever;
    
        public String getWhatever() {
            return whatever;
        }
    
        public void setWhatever(String whatever) {
            this.whatever = whatever;
        }
    
        @Override
        public String toString() {
            return new ToStringBuilder(this)
                .append("whatever", whatever)
                .toString();
        }
    }