没有像默认构造一样的创建者):不能从对象值反序列化(没有基于委托或属性的创建者

Posted

技术标签:

【中文标题】没有像默认构造一样的创建者):不能从对象值反序列化(没有基于委托或属性的创建者【英文标题】:No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator 【发布时间】:2019-04-11 00:01:35 【问题描述】:

我正在尝试使用一个使用 Retrofit 和 Jackson 来反序列化的 API。我收到了 onFailure 错误No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator

【问题讨论】:

您似乎没有使用适用于 Kotlin 的 Jackson 模块,该模块适用于没有默认构造函数的数据类,而您的则没有。检查那个模块,看看你之后是否有任何问题。 请更改接受的答案。 【参考方案1】:

原因: 发生此错误是因为 jackson 库不知道如何创建没有空构造函数的模型,并且该模型包含带有参数的构造函数,而该构造函数没有用@JsonProperty("field_name")。默认情况下,如果您没有将构造函数添加到类中,java 编译器会创建空构造函数。

解决方案: 向模型添加一个空的构造函数或使用 @JsonProperty("field_name") 注释构造函数参数

如果您使用 Kotlin 数据类,则也可以使用 @JsonProperty("field_name") 进行注释或将 jackson module kotlin 注册到 ObjectMapper

您可以使用http://www.jsonschema2pojo.org/ 创建模型。

【讨论】:

之所以有效是因为它们不是数据类。 这就是解决方案。但是哪种方式更好呢?一般是创建一个 empy 构造函数还是添加 JSON 属性? @Maximus 我认为性能没有区别(如果您的意思是性能更好)。创建一个空的构造函数比在每个参数上添加注释更容易。 如果我不能修改我试图反序列化的类怎么办?有什么办法可以使这项工作?自定义反序列化器是唯一的选择吗? 无法编辑课程怎么办?比如我想反序列化spring的Pair。我可以在 Pair 类之外创建自定义反序列化方法吗?【参考方案2】:

我来这里是为了寻找这个错误:

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

与 Retrofit 无关,但如果您使用 Jackson,则可以通过向引发错误的类添加默认构造函数来解决此错误。 更多内容:https://www.baeldung.com/jackson-exception

【讨论】:

如果你希望你的对象是不可变的,你不会想创建一个默认的构造函数。在构造函数上添加@JsonCreator@ConstructorProperties("prop1Name", "propr2Name") 即可解决上述错误。 如果您使用 Lobok 和 @Data,请确保您的字段不是最终的,否则无法使用空构造函数。所以这不起作用:@Data static class LoginResponse private final String token, message; private final int status; 但这有效:@Data static class LoginResponse private String token, message; private int status; @Vladtn -- 谢谢,这是我的问题;0 您能从这篇文章中添加一些简短的细节吗?因为它在技术上是一个仅限链接的答案,但从分数来看,这显然对人们有所帮助。我不想看到这篇文章因为如此琐碎的事情而被删除。【参考方案3】:

您需要使用jackson-module-kotlin 反序列化为数据类。详情请见here。

如果您在未启用该模块时尝试将某些值反序列化到数据类中,或者即使启用,当它使用的 ObjectMapper 没有 @ 时,上面的错误消息是 Jackson 给您的987654324@ 已注册。比如下面这段代码:

data class TestDataClass (val foo: String)

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

这将失败并出现以下错误:

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)

如果您更改上面的代码并将ObjectMapper 替换为jacksonObjectMapper(它只是返回一个注册了KotlinModule 的普通ObjectMapper),它就可以工作。即

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

我不确定 android 方面的情况,但您似乎需要让系统使用 jacksonObjectMapper 进行反序列化。

【讨论】:

已用更多信息更新了答案。我想知道,尽管您已经注册了模块,但进行反序列化的代码是否没有明确使用jacksongObjectMapper?我只是假设它与此有关,因为您收到的错误消息正是 Jackson 在不使用该对象映射器时给您的。 我可以把仓库传给你看看吗? 去吧。虽然我从来没有做过任何 Android 的东西,所以不要抱太大希望 :-) 我刚刚回答了这个问题,因为前几天我碰巧在一些服务器端 Kotlin 代码中遇到了这个问题。 这个问题肯定与不使用这个模块和使用数据类有关。因此,您需要在系统正在使用的对象映射器上注册该模块。在您正在使用的框架中查找您可以修改对象映射器的配置以调用mapper.registerModule(KotlinModule())@jose 何塞和杰森写关于 json 的文章:-D【参考方案4】:

如果您在 POJO 模型上使用 Lombok,请确保您有以下注释:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor

可能会有所不同,但请确保@Getter尤其是@NoArgsConstructor

【讨论】:

@NoArgsConstructor 解决了我的问题。我的完整注释是@Data @AllArgsConstructor @NoArgsConstructor @Entity @JsonInclude(Include.NON_DEFAULT) @Data 等价于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode 所以可能只需要@NoArgsConstructor @54l3d @Data 将不包括 @RequiredArgsConstructor 如果您同时指定另一个构造函数注释。 只是想指出你拯救了我的一天 :),我一直都错过了 @NoArgsConstructor 注释。 谢谢你,当我添加所有注释时,你拯救了我的一天【参考方案5】:

我知道这是一篇旧帖子,但对于任何使用 Retrofit 的人来说,这可能很有用。

如果你使用的是 Retrofit + Jackson + Kotlin + Data 类,你需要:

    implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2' 添加到您的依赖项中,以便Jackson 可以反序列化为数据类 在构建改造时,传递 Kotlin Jackson 映射器,以便改造使用正确的映射器,例如:
    val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()

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

注意:如果没有使用 Retrofit,@Jayson Minard 有一个更通用的方法答案。

【讨论】:

太棒了!我认为改造正在使用杰克逊的其他实例 我希望我能给你一些代表积分,因为你在加时赛的最后一分钟救了我!谢谢【参考方案6】:

我有一个类似的问题(使用 Jackson、lombok、gradle)和一个没有 args 构造函数的 POJO - 解决方案是添加

lombok.anyConstructor.addConstructorProperties=true

lombok.config 文件

【讨论】:

【参考方案7】:

我通过添加无参数构造器解决了这个问题。如果你使用的是Lombok,只需要添加@NoArgsConstructor注解即可:

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

【讨论】:

【参考方案8】:

正如错误中提到的,该类没有默认构造函数。

将@NoArgsConstructor 添加到实体类应该可以修复它。

【讨论】:

【参考方案9】:

我正在使用 Quarkus、Jackson 和 Lombok。所以我通过在模型类上添加@Jacksonized 属性解决了这个问题。 所以所有属性都是:

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

【讨论】:

【参考方案10】:

我在 Kotlin 中使用 rescu 并通过使用 @ConstructorProperties 解决了它

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

杰克逊使用@ConstructorProperties。这也应该修复 Lombok @Data。

【讨论】:

这是在 aws lambda + kotlin 情况下唯一适合我的解决方案。【参考方案11】:

只需添加@NoArgsConstructor即可。

【讨论】:

【参考方案12】:

扩展 Yoni Gibbs 的回答,如果您在一个使用 Jackson 的改造和配置序列化的 android 项目中,您可以执行这些操作,以便反序列化按预期与 kotlin 的数据类一起工作。

在您的构建 gradle 导入中:

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

那么,你的改造实施:

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()

数据类:

@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?

【讨论】:

我正在使用 Spring + Kotlin 作为后端,我用 KotlinModule() 解决了这个问题,谢谢。【参考方案13】:

我遇到了这个问题,我用下面的代码修复了。

@Configuration
open class JacksonMapper 

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

        mapper.registerModule(KotlinModule())
        return mapper
    

【讨论】:

【参考方案14】:

贝克的答案是正确的。

但如果有人试图在 restcontroller 中使用不可变类,即他们正在使用 lombok 的 @value,那么您需要添加 lombok.anyConstructor.addConstructorProperties=true

您可以在根 pom.xml 所在的同一位置创建一个名为 lombok.config 的文件,并将这一行添加到文件中

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

【讨论】:

【参考方案15】:

小心 Lombok,尤其是 @Builder。

对我来说解决问题的是:

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

          

我希望它能让你的生活更轻松

【讨论】:

【参考方案16】:

如果您使用的是 LOMBOK。 如果没有,请创建一个文件 lombok.config 并添加这一行。

lombok.anyconstructor.addconstructorproperties=true

【讨论】:

【参考方案17】:

在类中添加构造函数 要么 如果你使用 pojo 添加 @NoArgsConstructor @AllArgsConstructor

还包括 JsonProperty - @JsonProperty("name") private List&lt;Employee&gt; name;

【讨论】:

【参考方案18】:

我得到了同样的错误,在我添加了一个没有参数的构造函数之后问题就解决了。

【讨论】:

【参考方案19】:

如果您使用Unirest 作为http 库,使用GsonObjectMapper 代替JacksonObjectMapper 也可以。

<!-- 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()

【讨论】:

【参考方案20】:

当您使用 Lombok builder 时,您将收到上述错误。

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

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

参考:https://projectlombok.org/features/Builder 与杰克逊

【讨论】:

【参考方案21】:

我可以在 @JacksonProperty 注释的帮助下在 Kotlin 中解决这个问题。上述情况的用法示例是:

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

【讨论】:

【参考方案22】:

只想指出,answer 提供了更好的解释。 基本上你可以同时拥有@Getter@NoArgConstructor 或者让 Lombok 使用 lombok.config 文件重新生成 @ConstructorProperties, 或使用 -parameters 标志编译您的 java 项目, 或者让杰克逊使用龙目岛的@Builder

【讨论】:

【参考方案23】:

我的问题原因对我来说似乎很不常见,不确定其他人是否在相同的情况下得到错误,我通过比较以前的提交找到了原因,你去吧:

通过我的 build.gradle,我使用了这 2 个编译器选项,并且注释掉这一行解决了这个问题

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

【讨论】:

【参考方案24】:

在下面的用例中遇到了同样的错误。

我尝试使用 sprint boot(2.0.0 Snapshot Version) 来达到 Rest(Put mapping) 端点,而在各个 bean 中没有 default 构造函数。

但是对于最新的 Spring Boot 版本(2.4.1 版本),相同的代码可以正常运行。

所以 bean 默认构造函数在最新版本的 Spring Boot 中不再需要

【讨论】:

【参考方案25】:

我遇到了同样的错误,问题是我的 model 没有实现 Serializable,所以也检查一下,可能会有所帮助因为这也是原因之一

【讨论】:

【参考方案26】:

[Kotlin] 如果您在应用 KotlinModule 后仍然遇到问题,那么您可能(尽管不太可能)在某处有值类。现在我凌晨 4 点睡觉。

【讨论】:

这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review

以上是关于没有像默认构造一样的创建者):不能从对象值反序列化(没有基于委托或属性的创建者的主要内容,如果未能解决你的问题,请参考以下文章

反序列化错误 : 不能构造Dto的实例(尽管至少有一个Creator存在):不能从对象值反序列化。

没有从字符串值反序列化的字符串参数构造函数/工厂方法('2018-12-14')

Jackson MismatchedInputException(没有从字符串值反序列化的字符串参数构造函数/工厂方法)

Spring Boot:没有从字符串值反序列化的字符串参数构造函数/工厂方法

objectmapper.readValue() 失败并出现错误“没有从字符串值反序列化的字符串参数构造函数/工厂方法”

使用 Jackson 从 XML 到 POJO 的反序列化问题:没有从字符串值反序列化的字符串参数构造函数/工厂方法