无法使用Final Field Bu Jackson反序列化最简单的对象 [英] Can't deserialize simplest Object with final field bu Jackson

查看:152
本文介绍了无法使用Final Field Bu Jackson反序列化最简单的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只想序列化和反序列化简单的不可变对象,却不明白为什么我不能使用Jackson来完成

I just want to serialize and deserialize simple immutable object and don't understand why I can't do it using Jackson

import java.io.IOException;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Value;

public class TestApplication {

    @Value
    static class Test {
        private final String a;
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();

        String res = objectMapper.writeValueAsString(new Test("test"));
        System.out.println(res);

        System.out.println(objectMapper.readValue(res, Test.class));
    }
}

它失败,但出现以下异常:

It fails with exception:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.devchallange.rogatakopita.RogatakopitaApplication$Test` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"a":"test"}"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1032)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
    at com.devchallange.rogatakopita.RogatakopitaApplication.main(RogatakopitaApplication.java:29)

我知道答案应该很简单,但是就像最普通的情况那样,不是可以直接使用的吗?

I understand that answer should be easy but it's like the most common case that should work from the box isn't it?

推荐答案

在设计不可变类时,Jackson应该使用所有必需的参数调用构造函数.

When designing immutable classes, Jackson should invoke the constructor with all the required arguments.

如果您不使用lombok,则

If you were not using lombok,

  • 注释您希望Jackson用@JsonCreator调用的构造函数.
  • @JsonProperty注释构造函数参数.如果要跳过此操作,可以添加use ParameterNamesModule扩展名.
  • Annotate the constructor you want Jackson to invoke with @JsonCreator.
  • Annotate the constructor parameters with @JsonProperty. If you want to skip this, you can add use ParameterNamesModule extension.

示例:

static class Test {

    private final String a;

    public Test() {
        a = "default";
    }

    @JsonCreator // Jackson will use this constructor during deserialization
    public Test(@JsonProperty("a") String a) { // @JsonProperty can be skipped if you use ParameterNamesModule annotation
        this.a = a;
    }

    // Getter for A
}

Lombok的@Value注释仅生成一个单一的all-args构造函数,我们需要使用@JsonCreator进行注释.这可以通过用@AllArgsConstructor(onConstructor = @__(@JsonCreator))注释类来完成.

Lombok's @Value annotation produces only a single all-args constructor which we need to annotate with @JsonCreator. This can be done by annotating the class with @AllArgsConstructor(onConstructor = @__(@JsonCreator)).

由于构造函数是自动生成的,因此我们将无法使用@JsonProperty注释参数,因此,您将不得不使用ParameterNamesModule.

Since the constructor is auto-generated, we will not be able to annotate the parameters with @JsonProperty, so, you'll have to use ParameterNamesModule.

具有以下更改的代码段:

Code snippet with these changes:

public class TestApplication {

    @Value
    @AllArgsConstructor(onConstructor = @__(@JsonCreator))
    static final class Test {
        private final String a;
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new ParameterNamesModule());

        String res = objectMapper.writeValueAsString(new Test("test"));
        System.out.println(res);
        System.out.println(objectMapper.readValue(res, Test.class));
    }
}

以下是参数名称模块的maven依赖项.

Following is the maven dependency for parameter names module.

 <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
      <version>2.9.8</version>
      <scope>compile</scope>
 </dependency>

这篇关于无法使用Final Field Bu Jackson反序列化最简单的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆