Jackson deserialization fails after serializing an object using writeValueAsString
Asked Answered
N

5

9

Using the com.fasterxml.jackson.databind.ObjectMapper class(com.fasterxml.jackson.core:jackson-databind:2.9.5) I am trying to deserialize an object of the following class:

class MyClass {

    String name;

    MyClass(String name) {
        this.name = name;
    }
}

The code I am currently executing is the following:

    MyClass myClass = new MyClass("test");
    objectMapper.registerModule(new ParameterNamesModule())
        .registerModule(new Jdk8Module())
        .registerModule(new JavaTimeModule())
        .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
        .setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

    String text = objectMapper.writeValueAsString(myClass);
    objectMapper.readValue(text, MyClass.class);

which fails on the last line throwing the exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.pckge.MyClass (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"name":"test"}"; line: 1, column: 2]

My goal would be to configure the object mapper so to successfully deserialize the object without using annotations such as JsonCreator or JsonProperties on the constructor of MyClass:

  • Is this doable?
  • Which configuration I am missing?

Thanks a lot!

EDIT 1: Reply by @Dean solves the issue. However I would like to avoid to have the default constructor also.

Noelianoell answered 18/7, 2018 at 13:57 Comment(0)
D
12

Jackson uses Getter and Setters to set values. So you need to modify your class:

class MyClass {

    String name;

    MyClass(String name) {
      this.name = name;
   }

   MyClass(){}

   public void setName(String name) {
     this.name = name;
   }

  public String getName(String name) {
     return this.name;
  }
}
Dreiser answered 18/7, 2018 at 14:21 Comment(2)
This solves the issue. What if we do not want to create the default constructor?Noelianoell
Unfortunately it will require the default constructor.Dreiser
V
26

The proper way to solve this without a default constructor is to add JsonCreator and JsonProperty annotations to your class constructor.

class MyClass {

    String name;

    @JsonCreator
    MyClass(@JsonProperty("name") String name) {
        this.name = name;
    }
    ...
}
Vickey answered 23/10, 2018 at 18:27 Comment(1)
This should be the accepted answer. It's much better than adding NoArg constructor and public setters - the name field should be final!Fimble
D
12

Jackson uses Getter and Setters to set values. So you need to modify your class:

class MyClass {

    String name;

    MyClass(String name) {
      this.name = name;
   }

   MyClass(){}

   public void setName(String name) {
     this.name = name;
   }

  public String getName(String name) {
     return this.name;
  }
}
Dreiser answered 18/7, 2018 at 14:21 Comment(2)
This solves the issue. What if we do not want to create the default constructor?Noelianoell
Unfortunately it will require the default constructor.Dreiser
F
7

if you are using loombok remove the @Builder annotation of the class, was my problem

Frontier answered 12/8, 2019 at 15:29 Comment(0)
S
2

mine was to remove @Builder(Lombok) annotation from class and add @AllArgsConstructor and @NoArgsConstructor annotations, it worked

Shackle answered 30/9, 2021 at 4:14 Comment(1)
It also worked for me, but I cannot understand why, can you explain, please?Kight
P
0

I remove the @Builder(Lombok), it's worked, because @Builder create a private constructor.

Pentagrid answered 6/11, 2023 at 12:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.