José Nobre
José Nobre

Reputation: 5027

No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator

I am trying to consume an API using Retrofit and Jackson to deserialize. I am getting the onFailure error No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator.

Upvotes: 371

Views: 649349

Answers (30)

Abd Abughazaleh
Abd Abughazaleh

Reputation: 5535

I soved by adding :

@Configuration
public class ExternalApiConfiguration {
    @Bean
    public Encoder feignFormEncoder() {
        return new JacksonEncoder();
    }

    @Bean
    public Decoder feignDecoder() {
        return new JacksonDecoder();
    }
}

Upvotes: 0

Yuxing Xie
Yuxing Xie

Reputation: 51

You can use @JsonProperty to resolve the issue in most case just like above answers,but when your object to deserialize is in another library which is imported by maven or gradle repository,you can't change the source code.In this case,you can use annotation like @JsonDeserialize(converter = GeoJsonPointConverter.class)

public class Person {
  //GeoJsonPoint is a mongoDB object that provided by springframework
  //GeoJsonPoint doesn't have default constructor.
  @JsonDeserialize(converter = GeoJsonPointConverter.class)
  private GeoJsonPoint point;
  // getter & setter & other codes
}

public class GeoJsonPointConverter extends 
  StdConverter<Map<String,Double>,GeoJsonPoint> {
    @Override
    public GeoJsonPoint convert(Map<String,Double> value) {
        double x = value.get("x");
        double y = value.get("y");
        return new GeoJsonPoint(x,y);
    }
}

Your income json string looks like:

{point:{x:112.551243,y:28.274283}}

I think this is a more flexible way to resolve this issue.

Upvotes: 0

Mihael Mihov
Mihael Mihov

Reputation: 151

This was mentioned already but not fully explained. With Lombok 1.14 and later you can addlombok.anyConstructor.addConstructorProperties=true to the lombok.config file located at the root directory of your project. If you have this and your POJO annotated with lombok

   @Builder
   @Getter

It will work because under the hood Lombok annotates the Builder's constuctor with @java.beans.ConstructorProperties() like here: enter image description here

By having the @java.beans.ConstructorProperties({param1, param2 ...}) annotation each parameter of your buider's constructor will be exposed via its getter, i.e, getCar(), getBrand() etc. This information is enough for Jackson to serialize your POJO properly via the getters.

Upvotes: 2

ZZ 5
ZZ 5

Reputation: 1964

If you use Kotlin and value class like this:

value class SomeId(val value: String) {
    override fun toString(): String = value
}

Then it won't work, even if you're going to nest this class within other e.g.

data class MyClass(val someId: SomeId)

There's open ticket about this, but it has been opened in 2018, so probably it won't be fixed. Instead you'll have to use primitive type instead so in this case

data class MyClass(val someId: String)

Upvotes: 0

Bek
Bek

Reputation: 8471

Reason: This error occurs because Jackson Library doesn't know how to create your model which doesn't have an empty constructor and the model contains a constructor with parameters that didn't annotate its parameters with @JsonProperty("field_name"). By default Java compiler creates an empty constructor if you didn't add a constructor to your class.

Solution: Add an empty constructor to your model or annotate constructor parameters with @JsonProperty("field_name")

If you use a Kotlin data class then also can annotate with @JsonProperty("field_name") or register jackson module kotlin to ObjectMapper.

You can create your models using http://www.jsonschema2pojo.org/.

Upvotes: 368

Salami  Korede
Salami Korede

Reputation: 439

I'm using Lombok. I got the error because I did not put @NoArgsConstructor in my model class.

Upvotes: 13

Fede Mika
Fede Mika

Reputation: 2261

I got here searching for this error:

No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator

Nothing to do with Retrofit but if you are using Jackson this error got solved by adding a default constructor to the class throwing the error. More here: https://www.baeldung.com/jackson-exception

Most relevant bits from the link above:

"This exception is thrown if Jackson can't access the constructor. When we try to deserialize a JSON String, JsonMappingException: No Suitable Constructor Found is thrown. To solve this problem, we just add a default constructor:

    public Foo() {
        super();
    }

Now when we deserialize, the process will work just fine."

Upvotes: 117

Oleg Poltoratskii
Oleg Poltoratskii

Reputation: 806

If you use lombok you can use @Jacksonized annotation.

You don't need setters - this annotation works fine with @Value.

You don't need @NoArgsConstructor - you can use @Builder or just @RequiredArgsConstructor.

Upvotes: 13

Karan Khanna
Karan Khanna

Reputation: 2137

For classes where we don't have a default construct, example when working with immutable objects, Jackson by default will not be able to deserialize JSON to the object. We can resolve this using some annotations like @JsonCreator which can help Jackson to know how to deserialize a given JSON.

A sample code will look like:

package com.test.hello;

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

public class Payment {

    private final Card card;

    private final Amount amount;

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public Payment(@JsonProperty("card") Card card, @JsonProperty("amount") Amount amount) {
       this.card = card;
       this.amount = amount;
    }

    public Card getCard() {
       return card;
    }

    public Amount getAmount() {
        return amount;
    }
}

Upvotes: 4

vitiello.antonio
vitiello.antonio

Reputation: 393

In my case the problem occurred only in the build type release and was due to the obscuring of some classes in the '\dto' folder which contains the stubs. To solve I added the following rules in the proguard-rules.pro file:

-keep public class com.your.app_package.dto.** { *; }

-keep @**annotation** class * {*;}

#Preserve JacksonXml (PUBLIC_ONLY crash fix)
-keepattributes *Annotation*,EnclosingMethod,Signature
-keepnames class com.fasterxml.jackson.** { *; }
-dontwarn com.fasterxml.jackson.databind.**
-keep class org.codehaus.** { *; }
-keepclassmembers public final enum com.fasterxml.jackson.annotation.JsonAutoDetect$Visibility {
    public static final com.fasterxml.jackson.annotation.JsonAutoDetect$Visibility *; }

Upvotes: 0

shruthi
shruthi

Reputation: 91

by adding @NoArgsConstructor , it will fix the issue. Because compiler will add the default constructor if we have not provided any constructor, but if we have added any parameterized constructor and missed to add NoArgsConstructor we will get this exception. We should compulsorily add the default Constructor.

Upvotes: 3

Alexey Bril
Alexey Bril

Reputation: 543

I'm adding my answer, because I myself, due to my inattention, encountered this error.

Accidentally introduced the wrong serializer through the import of a static object and for a long time could not understand what was the reason. Maybe this will help someone else.

// Wrong serializer via static object import
import static org.keycloak.util.JsonSerialization.mapper;

Be careful.

Upvotes: 0

SKO
SKO

Reputation: 50

I also faced the exception in Kotlin. If you're still having problem after applying KotlinModule, you might (though not quite probably) have value class somewhere.

Upvotes: 0

MichalPr
MichalPr

Reputation: 538

I am using Quarkus, Jackson and Lombok. So I solved this issue by adding @Jacksonized attribute on model class. So all attributes are:

@Jacksonized //missing
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ...

Upvotes: 20

Be carefull with Lombok, expecially with @Builder.

what fixed the issue for me was :

   @JsonDeserialize(builder = X.XBuilder.class)
       class X{
          @JsonPOJOBuilder(withPrefix = "")
          public static class XBuilder{

          }
}

I hope it will make your life easier

Upvotes: 3

Nguyễn Dương
Nguyễn Dương

Reputation: 263

I got the same error and after I added a constructor without parameters and then the problem was solved.

enter image description here

Upvotes: 4

firstpostcommenter
firstpostcommenter

Reputation: 2921

Bek's answer is correct.

But in-case someone is trying to use immutable class in restcontroller i.e they are using lombok's @value then you need to add lombok.anyConstructor.addConstructorProperties=true

You can create a file named lombok.config in the same location where the root pom.xml is present and add this line into the file

https://stackoverflow.com/a/56022839/6700081

Upvotes: 3

sadhna
sadhna

Reputation: 536

Just need to add @NoArgsConstructor and it works.

Upvotes: 6

CodingBee
CodingBee

Reputation: 1199

Add Constructor in class OR if you are using pojo add @NoArgsConstructor @AllArgsConstructor

Also include JsonProperty - @JsonProperty("name") private List<Employee> name;

Upvotes: 1

Harsh Gundecha
Harsh Gundecha

Reputation: 1197

I got the same error and the problem was that my model didn't implement Serializable, so check this as well, might help since this is also one of the reason.

Upvotes: 0

Vishal
Vishal

Reputation: 1414

Encountered the same error in below Usecase.

I tried to hit the Rest(Put mapping) end point using sprint boot(2.0.0 Snapshot Version) without having default constructor in respective bean.

But with latest Spring Boot versions(2.4.1 Version) the same piece of code is working without error.

so the bean default constructor is no longer needed in latest version of Spring Boot

Upvotes: 0

Manjunath Joshi
Manjunath Joshi

Reputation: 11

If you are using LOMBOK. Create a file lombok.config if you don't have one and add this line.

lombok.anyconstructor.addconstructorproperties=true

Upvotes: 1

Madis M&#228;nni
Madis M&#228;nni

Reputation: 388

My cause of issue seems very uncommon to me, not sure if anybody else gets the error under same condition, I found the cause by diffing previous commits, here you go :

Via my build.gradle I was using these 2 compiler options, and commenting out this line fixed the issue

//compileJava.options.compilerArgs = ['-Xlint:unchecked','-Xlint:deprecation']

Upvotes: 0

Elias Meireles
Elias Meireles

Reputation: 1058

I had this issue and i fixed with the code below.

@Configuration
open class JacksonMapper {

    @Bean
    open fun mapper(): ObjectMapper {
        val mapper = ObjectMapper()
        ...

        mapper.registerModule(KotlinModule())
        return mapper
    }
}

Upvotes: 4

Ousama
Ousama

Reputation: 2800

I solved this issue by adding a no argument constractor. If you are using Lombok, you only need to add @NoArgsConstructor annotation:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class User {
    private Long userId;
    private String shortName;
}

Upvotes: 10

Charles  Chen
Charles Chen

Reputation: 105

Just want to point out that this answer provides a better explanation.
Basically you can either have @Getter and @NoArgConstructor together
or let Lombok regenerates @ConstructorProperties using lombok.config file,
or compile your java project with -parameters flags,
or let Jackson use Lombok's @Builder

Upvotes: 1

Yoni Gibbs
Yoni Gibbs

Reputation: 7016

You need to use jackson-module-kotlin to deserialize to data classes. See here for details.

The error message above is what Jackson gives you if you try to deserialize some value into a data class when that module isn't enabled or, even if it is, when the ObjectMapper it uses doesn't have the KotlinModule registered. For example, take this code:

data class TestDataClass (val foo: String)

val jsonString = """{ "foo": "bar" }"""
val deserializedValue = ObjectMapper().readerFor(TestDataClass::class.java).readValue<TestDataClass>(jsonString)

This will fail with the following error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `test.SerializationTests$TestDataClass` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)

If you change the code above and replace ObjectMapper with jacksonObjectMapper (which simply returns a normal ObjectMapper with the KotlinModule registered), it works. i.e.

val deserializedValue = jacksonObjectMapper().readerFor(TestDataClass::class.java).readValue<TestDataClass>(jsonString)

I'm not sure about the Android side of things, but it looks like you'll need to get the system to use the jacksonObjectMapper to do the deserialization.

Upvotes: 83

peterzinho16
peterzinho16

Reputation: 989

Extending Yoni Gibbs's answer, if you are in an android project using retrofit and configure serialization with Jackson you can do these things in order to deserialization works as expected with kotlin's data class.

In your build gradle import:

implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.+"

Then, your implementation of retrofit:

val serverURL = "http://localhost:8080/api/v1"

val objectMapper = ObjectMapper()
objectMapper.registerModule(KotlinModule())
//Only if you are using Java 8's Time API too, require jackson-datatype-jsr310
objectMapper.registerModule(JavaTimeModule())

Retrofit.Builder()
    .baseUrl(serverURL)
    .client(
        OkHttpClient.Builder()
           .readTimeout(1, TimeUnit.MINUTES)//No mandatory
            .connectTimeout(1, TimeUnit.MINUTES)//No mandatory
            .addInterceptor(UnauthorizedHandler())//No mandatory
            .build())
    .addConverterFactory(
                JacksonConverterFactory.create(objectMapper)
            )
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

Data class:

@JsonIgnoreProperties(ignoreUnknown = true)
data class Task(val id: Int,
                val name: String,
                @JsonSerialize(using = LocalDateTimeSerializer::class)
                @JsonDeserialize(using = LocalDateTimeDeserializer::class)
                val specificDate: LocalDateTime?,
                var completed: Boolean,
                val archived: Boolean,
                val taskListId: UUID?

Upvotes: 4

silver_fox
silver_fox

Reputation: 1287

If you're using Lombok on a POJO model, make sure you have these annotations:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor

It could vary, but make sure @Getter and especially @NoArgsConstructor.

Upvotes: 124

miradham
miradham

Reputation: 2345

I could resolve this problem in Kotlin with help of @JacksonProperty annotation. Usage example for above case would be:

import com.fasterxml.jackson.annotation.JsonProperty
...
data class Station(
     @JacksonProperty("repsol_id") val repsol_id: String,
     @JacksonProperty("name") val name: String,
...

Upvotes: 0

Related Questions