没有像默认构造一样的创建者):不能从对象值反序列化(没有基于委托或属性的创建者
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<Employee> 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() 失败并出现错误“没有从字符串值反序列化的字符串参数构造函数/工厂方法”