ObjectMapper can’t deserialize without default constructor after upgrade to Spring Boot 2

We Are Going To Discuss About ObjectMapper can’t deserialize without default constructor after upgrade to Spring Boot 2. So lets Start this Java Article.

ObjectMapper can’t deserialize without default constructor after upgrade to Spring Boot 2

  1. ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2

    Due to breaking changes in Lombok version 1.16.20 you need to set the following property in your lombok.config file (if you don't have this file you can create it in your project root):

  2. ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2

    Due to breaking changes in Lombok version 1.16.20 you need to set the following property in your lombok.config file (if you don't have this file you can create it in your project root):

Solution 1

Due to breaking changes in Lombok version 1.16.20 you need to set the following property in your lombok.config file (if you don’t have this file you can create it in your project root):

lombok.anyConstructor.addConstructorProperties=true

This is described in the Lombok changelog: https://projectlombok.org/changelog.

After that the @Value should be accepted again by Jackson.

You may be interested in following the related GitHub issue here, although it’s about @Data: https://github.com/rzwitserloot/lombok/issues/1563

Advertisements

Original Author Tobias Of This Content

Solution 2

One more way to solve this problem. Use Jackson parameter names module, which is included in spring boot 2 by default. After this Jackson can deserialize objects. But it works only if you have more than 1 property in object. In case of single property I receive following error message:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `SomeClassName` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Because of the following:

Marker annotation that can be used to define constructors and factory methods as one to use for instantiating new instances of the associated class.

NOTE: when annotating creator methods (constructors, factory methods), method must either be:

  • Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called “delegate creator”, in which case Jackson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue (used for serialization).
  • Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to

Also note that all JsonProperty annotations must specify actual name (NOT empty String for “default”) unless you use one of extension modules that can detect parameter name; this because default JDK versions before 8 have not been able to store and/or retrieve parameter names from bytecode. But with JDK 8 (or using helper libraries such as Paranamer, or other JVM languages like Scala or Kotlin), specifying name is optional.

To handle this case with Lombok I’ve used following workaround:

@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}
Advertisements

Original Author solomkinmv Of This Content

Solution 3

In case you have some final fields within your class and you would rather have Object creator to use specific constructor to deserialize your POJO along with @Data annotation, I suggest annotating the constructor with @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) and concrete required constructor parameters with @JsonProperty("<field_name>"). The example can be seen below:

package test.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.Date;

@Data
public class KafkaEventPojo {
    private final String executionId;
    private final String folder;
    private final Date created_at;

    private Date updated_at;
    // ... other params
    
    /**
     * Instantiates a new Kafka event pojo.
     *
     * @param executionId the execution or flow id of the event lifecycle
     * @param folder      the folder to be retrieved
     */
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public KafkaEventPojo(@JsonProperty("executionId") String executionId, @JsonProperty("folder") String folder) {
        this(executionId, folder, new Date(System.currentTimeMillis()));
    }

    private KafkaEventPojo(String executionId, String folder, Date date) {
        this.executionId = executionId;
        this.folder = folder;

        this.created_at = date;
        this.updated_at = date;
    }
    
    // ... other logic
}
Advertisements

Original Author mareck_ste Of This Content

Solution 4

I had this issue and the solution that worked for me what creating a default constructor without fields and the problem disappeared.

Advertisements

Original Author leeCoder Of This Content

Conclusion

Advertisements

So This is all About This Tutorial. Hope This Tutorial Helped You. Thank You.

Also Read,

Siddharth

I am an Information Technology Engineer. I have Completed my MCA And I have 4 Year Plus Experience, I am a web developer with knowledge of multiple back-end platforms Like PHP, Node.js, Python and frontend JavaScript frameworks Like Angular, React, and Vue.

Leave a Comment