【发布时间】:2021-01-12 18:50:21
【问题描述】:
在我的 spring boot 项目中,我注意到了一个奇怪的 Jackson 行为。我在互联网上搜索,找到了该怎么做,但还没有找到为什么。
UserDto:
@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 的实例(尽管至少存在一个 Creator):无法从 Object 值反序列化(没有基于委托或属性的 Creator)
问题的解决方案是在 TagDto 类中添加零参数构造函数。
为什么 Jackson 需要无参数构造函数在 TagDto 中进行反序列化,而与 UserDto 一起工作得很好?
使用相同的方法添加两者。 我的 Tag 和 User 实体都带有注释
@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.RELEASE 和 Jackson v2.11.2。
【问题讨论】:
-
Jackson 默认不会使用带参数的构造函数,您需要通过
@JsonCreator注释告诉它这样做。默认情况下,它会尝试使用您的类中不存在的无参数构造函数。 -
@Thomas 那么 UserDto 如何正常工作?
-
这是个好问题。我不是 Lombox 专家,所以我不得不猜测,但一个原因可能是
TagDto只有一个可能导致问题的属性。有时这些库存在或导致错误,例如 this one,因此最好提供有关您正在使用的版本的更多信息。 -
你能添加完整的代码吗? @Entity 类的外观如何?你到底是怎么存储的? Jackson 可能会在适当的时候尝试使用 AllArgsConstructor。杰克逊可能对一个实体使用所有参数,而对另一个实体使用无参数。这取决于您如何实例化这些 DTO。尝试删除 Lombok 注释并提供您自己的构造函数。然后在其中添加一些打印语句,然后自己查看-称为-when。
-
我仍然看不到如何您将实体转换为 DTO,您如何添加它们。请提供minimal reproducible example,并告诉我们——您究竟何时/何地有错误?当您转换为 DTO 时,很可能,对吧?此外,您的
User课程缺少某些部分。
标签: java json spring-boot jackson lombok