【问题标题】:Cannot construct instance of `com.domain.User` (no Creators, like default constructor, exist): cannot deserialize from Object value无法构造“com.domain.User”的实例(不存在创建者,如默认构造函数):无法从对象值反序列化
【发布时间】:2022-01-05 15:07:59
【问题描述】:

我有一个控制器,它接受ObjectNode 作为@RequestBody

ObjectNode 代表带有一些用户数据的json

{
    "given_name":"ana",
    "family_name": "fabry",
    "email": "fabry@gmail.com",
    "password": "mypass",
    "gender": "FEMALE"
}

Controller.java

@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonNode createUser(@RequestBody ObjectNode user){
        return userService.addUser(user);
 }

我想让用户为ObjectNode 将其转换为Java POJO 将其保存到数据库并再次将其返回为JsonNode

UserServiceImpl.java

    private final UserRepository userRepository;
    private final UserMapper userMapper;

    @Override
    public JsonNode addUser(@RequestBody ObjectNode user) {
        try {
            return userMapper.fromJson(user)
                    .map(r -> {
                        final User created = userRepository.save(r);
                        return created;
                    })
                    .map(userMapper::toJson)
                    .orElseThrow(() -> new ResourceNotFoundException("Unable to find user"));
        } catch (RuntimeException re) {
            throw re;
        }
    }

ObjectNode 转换为POJO

我在我的UserMapper 课堂上这样做了:

public Optional<User> fromJson(ObjectNode jsonUser) {
  User user = objectMapper.treeToValue(jsonUser, User.class);
}

另外,将对象写入JsonNode 我这样做了:

public JsonNode toJson(User user) {
        ObjectNode node = objectMapper.createObjectNode();
        node.put("email", user.email);
        node.put("password", user.password);
        node.put("firstName", user.firstName);
        node.put("lastName", user.firstName);
        node.put("gender", user.gender.value);
        node.put("registrationTime", user.registrationTime.toString());
        return node;
}

User.java

@Document(collection = "user")
@Builder
@AllArgsConstructor
public class User {

    @Indexed(unique = true)
    public final String email;
    @JsonProperty("password")
    public final String password;
    @JsonProperty("firstName")
    public final String firstName;
    @JsonProperty("lastName")
    public final String lastName;
    @JsonProperty("gender")
    public final Gender gender;
    @JsonProperty("registrationTime")
    public final Instant registrationTime;

    public static User createUser(
            String email,
            String password,
            String firstName,
            String lastName,
            Gender gender,
            Instant registrationTime){
        return new User(email, password, firstName, lastName, gender, registrationTime);
    }
}

当我运行我的应用程序时,这是我收到的错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.domain.User` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

我已阅读有关该错误的信息,并且似乎发生此错误是因为 Jackson 库不知道如何创建一个没有空构造函数的模型,并且该模型包含一个带有参数的构造函数,我用它注释了它的参数@JsonProperty("fieldName")。但即使在应用@JsonProperty("fieldName") 之后,我仍然遇到同样的错误。

我已将 ObjecatMapper 定义为 Bean

    @Bean
    ObjectMapper getObjectMapper(){
        return new ObjectMapper();
    }

我在这里错过了什么?

【问题讨论】:

  • Jackson 需要创建者方法或无参数构造函数。由于您使用的是 Lombok,因此您可能无法使用 Jackson 注释对全参数构造函数进行注释。您可以尝试使用无参数构造函数吗?
  • 我使用的是不可变类,这就是为什么我不能应用无参数构造函数
  • 如果不能添加无参数构造函数,则手动添加全参数构造函数并使用@JsonCreator注解。
  • 我用@JsonProperty 注释了我的字段,这不一样吗?
  • 不,这无关。这里的问题是创建类的一个实例。 @JsonProperty 仅在之后使用。

标签: java pojo jsonnode


【解决方案1】:

我可以重现异常。然后我添加了一个全参数构造函数,每个参数都用正确的 @JsonProperty 注释。

@JsonCreator
public User( 
    @JsonProperty("email") String email,
    @JsonProperty("password") String password,
    @JsonProperty("firstName") String firstName,
    @JsonProperty("lastName") String lastName,
    @JsonProperty("gender") String gender,
    @JsonProperty("registrationTime") Instant registrationTime){
            super();
            this.email = email;
            this.password = password;
            this.firstName = firstName;
            this.lastName = lastName;
            this.gender = gender;
            this.registrationTime = registrationTime;
}

现在,它创建了实例,但我遇到了其他映射错误(无法识别的字段“given_name”),您应该能够解决这些错误。

【讨论】:

  • 好的,谢谢。是的,我现在确实喜欢你。但是我在这行代码node.put("registrationTime", user.registrationTime.toString()); 上从方法toJson 得到空指针异常,你知道我该如何处理吗?
  • 这可能是因为输入中没有registrationTime,所以null 正在字段中。如果 null 被传递给它,你可以在上面的构造函数中给它一个默认值。
  • 所以也许最好的办法是把它作为可选。
【解决方案2】:

注册 Jackson ParameterNamesModule,它将自动将 JSON 属性映射到相应的构造函数属性,因此将允许您使用不可变类。

【讨论】:

  • 当我将对象映射器定义为 bean 时,如何将其添加到 Bean 请参阅我的问题的更新
猜你喜欢
  • 2020-04-17
  • 2018-11-05
  • 2020-12-15
  • 2020-11-23
  • 2020-01-01
  • 2014-09-07
  • 1970-01-01
  • 2016-10-29
  • 2021-06-07
相关资源
最近更新 更多