Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jackson何时不需要参数构造函数进行反序列化?_Java_Json_Spring Boot_Jackson_Lombok - Fatal编程技术网

Java Jackson何时不需要参数构造函数进行反序列化?

Java Jackson何时不需要参数构造函数进行反序列化?,java,json,spring-boot,jackson,lombok,Java,Json,Spring Boot,Jackson,Lombok,在我的春季长靴项目中,我注意到杰克逊有一种奇怪的行为。我在互联网上搜索,找到了该做什么,但还没有找到原因 用户地址: @Setter @Getter @AllArgsConstructor public class UserDto { private String username; private String email; private String password; private String name; private String

在我的春季长靴项目中,我注意到杰克逊有一种奇怪的行为。我在互联网上搜索,找到了该做什么,但还没有找到原因

用户地址:

@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;
}
添加一个新用户就可以了

标记:

@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());
    }

通过邮递员本地主机发送:8081/tag/add,返回

{
    "timestamp": "2020-09-26T18:50:39.974+00:00",
    "status": 400,
    "error": "Bad Request",
    "message": "",
    "path": "/tag/add"
}
我在Jackson v2.11.2中使用Lombok v1.18.12和Spring boot 2.3.3.RELEASE;医生:解决方案就在最后

Jackson支持多种创建POJO的方法。以下列出了最常见的方法,但可能不是一个完整的列表:

  • 不使用参数构造函数创建实例,然后调用setter方法来分配属性值

    公共类Foo{
    私有int-id;
    public int getId(){返回this.id;}
    @JsonProperty
    public void setId(int id){this.id=id;}
    }
    
    指定是可选的,但可用于微调映射,以及诸如

  • 使用带参数的构造函数创建实例

    公共类Foo{
    私有int-id;
    @JsonCreator
    public Foo(@JsonProperty(“id”)int-id){
    this.id=id;
    }
    公共int getId(){
    返回此.id;
    }
    }
    
    为构造函数指定是可选的,但我认为如果有多个构造函数,则必须指定。为参数指定
    @JsonProperty
    是可选的,但如果类文件中未包含参数名,则命名属性时需要指定该参数(
    -parameters
    编译器选项)

    这些参数意味着这些属性是必需的。可以使用setter方法设置可选属性

  • 使用工厂方法创建实例

    公共类Foo{
    私有int-id;
    @JsonCreator
    公共静态Foo-create(@JsonProperty(“id”)int-id){
    返回新的Foo(id);
    }
    私人Foo(int-id){
    this.id=id;
    }
    公共int getId(){
    返回此.id;
    }
    }
    
  • 使用
    String
    构造函数从文本值创建实例

    公共类Foo{
    私有int-id;
    @JsonCreator
    公共Foo(字符串str){
    this.id=Integer.parseInt(id);
    }
    公共int getId(){
    返回此.id;
    }
    @JsonValue
    公共字符串asJsonValue(){
    返回整数.toString(this.id);
    }
    }
    
    当POJO具有简单的文本表示时,这非常有用,例如,
    LocalDate
    是具有3个属性(
    year
    month
    dayOfMonth
    )的POJO,但通常最好将其序列化为单个字符串(
    yyyy-MM-dd
    格式)。标识序列化期间要使用的方法,
    @JsonCreator
    标识反序列化期间要使用的构造函数/工厂方法

    注意:这也可以用于使用JSON值而不是
    字符串
    的单值构造,但这种情况非常罕见

  • 好的,这就是背景资料。对于问题中的示例来说,
    UserDto
    之所以有效,是因为只有一个构造函数(因此不需要
    @JsonCreator
    )和许多参数(因此不需要
    @JsonProperty

    但是,对于
    TagDto
    只有一个没有任何注释的单参数构造函数,因此Jackson将该构造函数分类为类型4(从我上面的列表中),而不是类型2

    这意味着它期望POJO是一个值类,其中封闭对象的JSON是
    {…,“tag”:“value”,…}
    ,而不是
    {…,“tag”:{“tag”:“example”}

    要解决此问题,您需要通过在构造函数参数上指定
    @JsonProperty
    来告诉Jackson构造函数是属性初始化构造函数(#2),而不是值类型构造函数(#4)

    这意味着您不能让Lombok为您创建构造函数:

    @Setter
    @吸气剂
    公共类TagDto{
    私有字符串标签;
    公共标记到(@JsonProperty(“标记”)字符串标记){
    this.tag=tag;
    }
    }
    
    Jackson默认情况下不会使用带参数的构造函数,您需要告诉它在注释中这样做。默认情况下,它会尝试使用类中不存在的无参数构造函数。@Thomas UserDto如何正常工作?这是个好问题。我不是Lombox专家,所以我不得不猜测,但一个原因可能是
    TagDto
    只有一个属性可能会导致问题。有时这些库会出现或导致错误,例如,提供有关您正在使用的版本的更多信息可能会更好。您可以添加完整的代码吗?@Entity类看起来怎么样?你到底是怎么储存的?如果合适,Jackson可能会尝试使用AllArgsConstructor。可能是Jackson对一个实体使用了所有参数,而对另一个实体没有使用任何参数。这取决于如何实例化这些DTO。尝试删除Lombok注释并提供自己的构造函数。然后在这些文件中添加一些print语句,然后自己查看它(称为when)。我仍然看不到如何将实体转换为DTO,以及如何添加它们。请提供并告诉我们-您何时/何地出现错误?当您转换为DTO时,很可能是这样,对吗?还有,你的鳕鱼
    {
        "timestamp": "2020-09-26T18:50:39.974+00:00",
        "status": 400,
        "error": "Bad Request",
        "message": "",
        "path": "/tag/add"
    }