在我的Spring开机项目中,我注意到了杰克逊奇怪的行为。我在网上搜索了一下,找到了该做什么,但还没找到原因。
用户收件人:
@Setter
@Getter
@AllArgsConstructor
public class UserDto {
private String username;
private String email;
private String password;
private String name;
private String surname;
private UserStatus status;
private byte[] avatar;
private ZonedDateTime created_at;
}
添加新用户效果很好。
TagDto:
@Setter
@Getter
@AllArgsConstructor
public class TagDto {
private String tag;
}
尝试添加新标记以错误结束:
com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造TagDto的实例(尽管至少存在一个创建者):无法从对象值反序列化(没有基于委托或属性的创建者)
该问题的解决方案是向TagDto类添加零参数构造函数。
为什么Jackson在TagDto中进行反序列化时不需要arg构造函数,而在UserDto中工作得很好?
使用相同的方法添加两者。我的标签和用户实体都用
@Entity
@Setter
@Getter
@NoArgsConstructor
并具有所有args构造函数:
@Entity
@Setter
@Getter
@NoArgsConstructor
public class User extends AbstractModel {
private String username;
private String password;
private String email;
private String name;
private String surname;
private UserStatus status;
@Lob
private byte[] avatar;
@Setter(AccessLevel.NONE)
private ZonedDateTime created_at;
public User(final String username, final String password, final String email, final String name, final String surname) {
this.username = username;
this.password = password;
this.email = email;
this.name = name;
this.surname = surname;
this.created_at = ZonedDateTime.now();
}
}
@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Tag extends AbstractModel {
private String tag;
}
@MappedSuperclass
@Getter
public abstract class AbstractModel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
实体生成:
@PostMapping(path = "/add")
public ResponseEntity<String> add(@Valid @RequestBody final D dto) {
this.abstractModelService.add(dto);
return new ResponseEntity<>("Success", HttpStatus.CREATED);
}
public void add(final D dto) {
//CRUD repository save method
this.modelRepositoryInterface.save(this.getModelFromDto(dto));
}
@Override
protected Tag getModelFromDto(final TagDto tagDto) {
return new Tag(tagDto.getTag());
}
@Override
protected User getModelFromDto(final UserDto userDto) {
return new User(userDto.getUsername(), userDto.getPassword(), userDto.getEmail(), userDto.getName(), userDto.getSurname());
}
解析JSON时出错
{"tag":"example"}
通过邮递员localhost:8081/tag/add,返回
{
"timestamp": "2020-09-26T18:50:39.974+00:00",
"status": 400,
"error": "Bad Request",
"message": "",
"path": "/tag/add"
}
我正在使用Lombok v1.18.12和Spring boot 2.3.3。Jackson v2.11.2的发布。
TL;DR:解决方案已经结束。
Jackson支持多种创建Pojo的方法。以下列出了最常见的方法,但可能不是一个完整的列表:
>
不使用参数构造函数创建实例,然后调用setter方法来分配属性值。
public class Foo {
private int id;
public int getId() { return this.id; }
@JsonProperty
public void setId(int id) { this.id = id; }
}
指定JsonProperty是可选的,但可以用于微调映射,以及诸如JsonIgnore、JsonAnyGetter等注释。。。
使用带参数的构造函数创建实例。
public class Foo {
private int id;
@JsonCreator
public Foo(@JsonProperty("id") int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
为构造函数指定@JsonCreator
是可选的,但我认为如果有多个构造函数,则需要指定。为参数指定@JsonProperty
是可选的,但如果类文件中不包括参数名,则需要指定属性(-parameters
编译器选项)。
参数意味着属性是必需的。可以使用setter方法设置可选属性。
使用工厂方法创建实例。
public class Foo {
private int id;
@JsonCreator
public static Foo create(@JsonProperty("id") int id) {
return new Foo(id);
}
private Foo(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
使用String
构造函数从文本值创建实例。
public class Foo {
private int id;
@JsonCreator
public Foo(String str) {
this.id = Integer.parseInt(id);
}
public int getId() {
return this.id;
}
@JsonValue
public String asJsonValue() {
return Integer.toString(this.id);
}
}
当POJO具有简单的文本表示时,这很有用,例如,局部日期是具有3个属性(年、月、月)的POJO,但通常最好序列化为单个字符串(yyyy-MM-dd格式)
@JsonValue
标识序列化期间要使用的方法,而@JsonCreator
标识反序列化期间要使用的构造函数/工厂方法。
注意:这也可以用于使用JSON值而不是字符串的单值构造,但这种情况非常罕见。
好的,这就是背景信息。对于问题中的示例来说,
UserDto
之所以有效,是因为只有一个构造函数(因此不需要JsonCreator)和许多参数(因此不需要JsonProperty)。
但是,对于
TagDto
,只有一个没有任何注释的单参数构造函数,因此Jackson将该构造函数分类为类型#4(来自我上面的列表),而不是类型#2。
这意味着它期望POJO是一个值类,其中封闭对象的JSON将是
{...,"tag":"value",...}
,而不是{...,"tag":{"tag":"example"},...}
。
为了解决这个问题,您需要通过在构造函数参数上指定
@JsonProperty
来告诉Jackson构造函数是属性初始化构造函数(#2),而不是值类型构造函数(#4)。
这意味着您不能让Lombok为您创建构造函数:
@Setter
@Getter
public class TagDto {
private String tag;
public TagDto(@JsonProperty("tag") String tag) {
this.tag = tag;
}
}
我在我的项目中使用FasterXML/Jackson Databind已经有一段时间了,一切都很顺利,直到我发现这篇文章并开始使用这种方法对没有@JsonProperty注释的对象进行序列化。 问题是,当我有一个接受多个参数并使用@JsonCreator注释装饰这个构造函数时,Jackson会抛出以下错误: 我已经创建了一个小项目来说明这个问题,我试图对这个类进行序列化: 反序列化代码如下: 我已
问题内容: 另一个问题,但与此相关:使用Jackson来 反序列化JSON-为什么JsonMappingException“没有合适的构造函数”? 这次我遇到了另一个错误,即Jackson解串器抱怨类ProtocolContainer中没有“单字符串构造器/工厂方法”。 但是,如果我添加一个单字符串构造函数,如下所示: 异常确实消失了,但是我希望存在的所有异常都为“空”,即其所有属性都处于其初始状
问题内容: 我正在尝试使用杰克逊对物体进行去电 我有这个例外: 我知道这正在发生,因为这是我的构造函数: 因此,我的构造函数接收到HttpResponse参数,但我没有传递它,但我不知道该怎么做。我不能用一个空的构造函数过度计费,因为我需要以这种方式接收HttpResponse对象。当我调用readValue()方法时,有什么方法可以传递此构造函数参数?或者在这种情况下最好的选择是什么?我感谢您的
问题内容: 我正在使用Jackson示例代码对POJO进行反序列化: 这行抛出一个NoSuchMethodError: 我不明白 问题答案: 我猜您的Jackson JAR不同步。本类是JAR,和类是在。 确保它们都是相同的版本。
我在spring-boot项目中使用Jackson和hibernate: 并将其添加到转换器中: 我使用facebook网络钩子在Messenger中重新获取关于新消息的信息: 有效负载参数是一个字符串,但jackson转换器无法对其进行反序列化: W.S.M.S.DefaultHandlerExceptionResolver:未能读取HTTP消息:org.springframework.HTTP
问题内容: 我有一个杰克逊问题。 有没有一种方法可以反序列化可能具有两种类型的属性,对于某些对象,它看起来像这样 然后对于其他人则显示为空数组,即 任何帮助表示赞赏! 谢谢! 问题答案: Jackson目前没有内置配置来自动处理这种特殊情况,因此必须进行自定义反序列化处理。 以下是这种自定义反序列化的外观示例。 (您可以使用DeserializationConfig.Feature.ACCEPT_