321

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.

Noumenon
  • 5,099
  • 4
  • 53
  • 73
José Nobre
  • 4,407
  • 6
  • 20
  • 40
  • 2
    You appear to not be using the Jackson Module for Kotlin, which works with data classes that have no default constructor as yours does not. Check out that module and see if you have any problems after. – Jayson Minard Nov 08 '18 at 02:40
  • Please change accepted answer. – Noumenon Oct 31 '20 at 05:21
  • The reason for this is that Jackson (JSON deserialization library used by Spring WebClient) tries to deserialize into a class that has a non-default constructor only and in this case it cannot know which parameters to use for JSON attributes. This is only possible with debugging symbols present and some extra Jackson module (see other answers below). The normal way for Jackson in this case is to use `@JsonCreator` annotation on this non-default construtor in the class to deserialize. – Krzysztof Tomaszewski Nov 16 '22 at 08:32

32 Answers32

308

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/.

Saikat
  • 14,222
  • 20
  • 104
  • 125
Bek
  • 7,790
  • 4
  • 18
  • 31
  • 10
    The reason this works is because they aren't data classes. – mkki Aug 02 '19 at 23:12
  • 5
    This is the solution. But which way is better? Creating a empy constructor in general or adding the JSON property? – O. Schnieders Dec 18 '20 at 19:41
  • 4
    @Maximus I think there is no difference in performance( if you mean better in performance). Creating an empty constructor is easier than adding annotation on each parameter. – Bek Dec 19 '20 at 07:57
  • What if I can't modify the class I'm trying to deserialize? Is there any way to make this work? Is a custom deserializer the only option? – thomas.schuerger Jun 24 '21 at 13:44
  • What if I cannot edit the class? For example, I want to deserialize spring's Pair. Can I create a custom deserialization method outside of the Pair class? – dpelisek Jul 08 '21 at 10:44
  • I was added both the empty constructor and/or jsonproperty annnotation. But didnt work. The interesting think is works with debug variant but dont work with release variant – withoutOne Jan 26 '22 at 13:10
  • I have found the error, maybe it will may minifed option or proguard – withoutOne Jan 26 '22 at 13:14
  • This solution worked. Also totally agree with you @Bek as I had no concern regarding performance. – Lam Do Mar 16 '22 at 03:38
  • Thank you, using `jacksonObjectMapper()` fixed the issue – TomasZ. Feb 23 '23 at 13:45
  • Had this issue on a Kotlin project, where, using a field named 'name' in a data class was also failing, I annotated the field with @JsonProperty("name"), which resolved it. – Albert Scholtz May 16 '23 at 08:49
113

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."

Fede Mika
  • 2,211
  • 2
  • 19
  • 18
  • 25
    If you want your object to be immutable, you would not want to create a default constructor. Adding `@JsonCreator` or `@ConstructorProperties({"prop1Name", "propr2Name"})` on constructor solves the error above. – Kirill Nov 30 '19 at 07:45
  • 4
    If you are using Lobok and @Data, make sure your fields are not final otherwise empty constructor is not possible. So this doesn't work: `@Data static class LoginResponse { private final String token, message; private final int status; }` But this works: `@Data static class LoginResponse { private String token, message; private int status; }` – Vladtn Dec 27 '19 at 09:21
  • 1
    Can you please add some brief details from this article? As it is it is technically a link-only answer but judging by the score this has clearly helped people. I don't want to see this get deleted over something so petty. – Captain Man Jan 21 '22 at 21:28
  • Done, hope that helps. – Fede Mika Mar 03 '23 at 10:33
101

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.

Pol Ortiz
  • 461
  • 6
  • 14
silver_fox
  • 1,057
  • 1
  • 5
  • 4
  • 8
    `@NoArgsConstructor` was what solved my situation. My full anotations are `@Data @AllArgsConstructor @NoArgsConstructor @Entity @JsonInclude(Include.NON_DEFAULT)` – davide Feb 20 '20 at 15:35
  • 6
    `@Data` is equivalent to `@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode` So may be only `@NoArgsConstructor` is needed – 54l3d Mar 06 '20 at 14:34
  • @54l3d `@Data` will not include `@RequiredArgsConstructor` if you specify another constructor annotation along with it. – payne Apr 16 '20 at 14:56
  • 6
    Just wanted to point that you saved my day :), I was missing the @NoArgsConstructor annotation all this time. – Pol Ortiz Apr 20 '20 at 12:09
  • 3
    Both `@NoArgsConstructor` and `@AllArgsConstructor` were needed in my case. Thanks! – Fatmajk Mar 29 '22 at 10:04
  • The `@NoArgsConstructor` and `@AllArgsConstructor` helped to resolve this. – Nigel Thomas Sep 06 '22 at 06:47
  • I think when using `@Builder`, if `@NoArgsConstructer` is also used, then _that_ is when `@AllArgsConstructor` must also be used. If no `@Builder`, then no `@AllArgsConstructor` needed (just `@NoArgsConstructor`). – cellepo Jun 09 '23 at 02:20
  • But I think just additionally [using `@Jacksonized`](https://stackoverflow.com/a/75176148/1357094) instead, is the simplest :) – cellepo Jun 09 '23 at 02:26
73

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.

Gama11
  • 31,714
  • 9
  • 78
  • 100
Yoni Gibbs
  • 6,518
  • 2
  • 24
  • 37
  • Have updated the answer with more info. I wonder if, although you have the module registered, the code which is doing the deserialization isn't explicitly using the `jacksongObjectMapper`? I'm just assuming it is related to this, because the error message you're getting is exactly what Jackson gives you when that object mapper isn't used. – Yoni Gibbs Nov 07 '18 at 14:54
  • Can I pass you the repository for you to take a look? – José Nobre Nov 07 '18 at 14:58
  • Go for it. Though I've never done any Android stuff so don't get your hopes up :-) I just answered this because I happened to come across exactly this problem the other day in some server-side Kotlin code. – Yoni Gibbs Nov 07 '18 at 14:59
  • 10
    The issue is definitely related to not using this module and using a data class. So, you need to register the module on the object mapper that is being used by the system. Find in your frameworks that you are using where you can modify the configuration of the object mapper to call `mapper.registerModule(KotlinModule())` @jose – Jayson Minard Nov 08 '18 at 02:42
  • 5
    José and Jayson writing about json :-D – programaths Aug 06 '19 at 12:54
  • Does this apply to non-kotlin, i.e. Java 8 applications too? – Janac Meena Mar 06 '20 at 16:30
  • @JanacMeena, the solution in this answer is specific to Kotlin, but the error itself can potentially occur when deserializing to Java classes, if they are set up in some particular way (e.g. maybe only having a private constructor, or something like that, I haven't tried so not sure). – Yoni Gibbs Apr 02 '20 at 06:38
  • I am using Quarkus, with Kotlin, and rest api endpoint body using data class object. Adding the jackson-module-kotlin solved the issue. – Yazid Oct 14 '21 at 01:17
17

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 ...
MichalPr
  • 468
  • 6
  • 9
  • 1
    @Jacksonized always works with @Builder(Lambok) so add both of those to work. in my case my request body was having only on request entity named iBan. so when i tried to retrive data from request it was calling noargs constructor... in result i was unable to fetch payload data... – Muahmmad Tayyib Nov 26 '22 at 23:59
13

I know this is an old post, but for anyone using Retrofit, this can be useful useful.

If you are using Retrofit + Jackson + Kotlin + Data classes, you need:

  1. add implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2' to your dependencies, so that Jackson can de-serialize into Data classes
  2. When building retrofit, pass the Kotlin Jackson Mapper, so that Retrofit uses the correct mapper, ex:
    val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()

    val retrofit = Retrofit.Builder()
          ...
          .addConverterFactory(JacksonConverterFactory.create(jsonMapper))
          .build()

Note: If Retrofit is not being used, @Jayson Minard has a more general approach answer.

HAT
  • 331
  • 3
  • 8
13

I had a similar issue (using Jackson, lombok, gradle) and a POJO without no args constructor - the solution was to add

lombok.anyConstructor.addConstructorProperties=true

to the lombok.config file

Dominik Minc
  • 191
  • 2
  • 6
  • This seems best if you're working with @Value...no extra annotations just to make your immutable classes deserializable. – Ilan Segal Aug 03 '23 at 17:06
11

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

TuGordoBello
  • 4,350
  • 9
  • 52
  • 78
Salami Korede
  • 339
  • 2
  • 9
10

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;
}
Ousama
  • 2,176
  • 3
  • 21
  • 26
8

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.

Oleg Poltoratskii
  • 667
  • 11
  • 10
  • And I think the [strict minimum](https://stackoverflow.com/a/69371859/1357094) when using `@Builder`, is for just `@Jacksonized` additionally (no others, like @Value, are strictly necessary). – cellepo May 16 '23 at 02:55
  • @cellepo could you please paraphrase your message? – Oleg Poltoratskii May 17 '23 at 15:21
  • 3
    When using `@Jacksonized` with `@Builder`, `@Value` is optional (maybe for other purposes) but not necessary for the Jackson-izing itself. – cellepo May 17 '23 at 17:29
6

I'm using rescu with Kotlin and resolved it by using @ConstructorProperties

    data class MyResponse @ConstructorProperties("message", "count") constructor(
        val message: String,
        val count: Int
    )

Jackson uses @ConstructorProperties. This should fix Lombok @Data as well.

Aaron Lee
  • 63
  • 1
  • 4
  • 1
    This is the only solution that works for me in a aws lambda + kotlin situation. – GJ. May 04 '21 at 02:14
6

As the error mentioned the class does not have a default constructor.

Adding @NoArgsConstructor to the entity class should fix it.

Gayan Weerakutti
  • 11,904
  • 2
  • 71
  • 68
6

Just need to add @NoArgsConstructor and it works.

TuGordoBello
  • 4,350
  • 9
  • 52
  • 78
sadhna
  • 486
  • 1
  • 5
  • 9
4

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?
peterzinho16
  • 919
  • 1
  • 15
  • 18
  • 1
    I am using Spring + Kotlin for Backend, and I resolved this problem with the KotlinModule(), thanks. – Caio Jul 14 '20 at 22:24
4

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

firstpostcommenter
  • 2,328
  • 4
  • 30
  • 59
4

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;
    }
}
Karan Khanna
  • 1,947
  • 3
  • 21
  • 49
3

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
    }
}
Elias Meireles
  • 898
  • 8
  • 12
3

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

enter image description here

3

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

2

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.

Sanket Shah
  • 4,352
  • 3
  • 21
  • 41
shruthi
  • 61
  • 3
1

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

Charles Chen
  • 21
  • 1
  • 3
1

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

lombok.anyconstructor.addconstructorproperties=true
1

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

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

CodingBee
  • 1,011
  • 11
  • 8
0

If you are using Unirest as the http library, using the GsonObjectMapper instead of the JacksonObjectMapper will also work.

<!-- https://mvnrepository.com/artifact/com.konghq/unirest-object-mappers-gson -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-object-mappers-gson</artifactId>
    <version>2.3.17</version>
</dependency>
Unirest.config().objectMapper = GsonObjectMapper()
Clement
  • 4,491
  • 4
  • 39
  • 69
0

When you are using Lombok builder you will get the above error.

 @JsonDeserialize(builder = StationResponse.StationResponseBuilder.class)
 public class StationResponse{
   //define required properties 
 }     

 @JsonIgnoreProperties(ignoreUnknown = true)
 @JsonPOJOBuilder(withPrefix = "")
 public static class StationResponseBuilder {}

Reference : https://projectlombok.org/features/Builder With Jackson

MohanaRao SV
  • 1,117
  • 1
  • 8
  • 22
0

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,
...
miradham
  • 2,285
  • 16
  • 26
0

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']
xenlo
  • 761
  • 1
  • 7
  • 21
Madis Männi
  • 168
  • 1
  • 5
0

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

Kms
  • 1,082
  • 2
  • 11
  • 27
0

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.

Harsh Gundecha
  • 1,139
  • 9
  • 16
  • Hard to believe. Actually `Serializable` marker interface is not used by Jackson deserializer. I often see people do not understand the reasons for adding `Serializable` marker interface, which is mainly some result of EJB times and some confusion introduced by Hibernate/JPA requirements on embedded keys (where `Serializable` is required). – Krzysztof Tomaszewski Nov 16 '22 at 08:28
0

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.

SKO
  • 32
  • 5
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31260592) – Abhishek Dutt Mar 15 '22 at 05:48
  • @AbhishekDutt clarified my answer – SKO Mar 16 '22 at 08:08
0

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.

Alexey Bril
  • 479
  • 4
  • 14
0

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 *; }
vitiello.antonio
  • 323
  • 3
  • 12