【问题标题】:Can't deserialize simplest Object with final field bu Jackson无法反序列化最简单的对象与最终字段 bu Jackson
【发布时间】:2019-08-14 20:07:54
【问题描述】:

我只想序列化和反序列化简单的不可变对象,不明白为什么我不能使用 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));
    }
}

异常失败:

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)

我知道答案应该很简单,但这是最常见的情况,不是吗?

【问题讨论】:

标签: java jackson


【解决方案1】:

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

如果你没有使用龙目岛,

  • 使用 @JsonCreator 注释您希望 Jackson 调用的构造函数。
  • @JsonProperty注释构造函数参数。如果你想跳过这个,你可以添加使用ParameterNamesModule扩展。

例子:

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 注释只生成一个全参数构造函数,我们需要用@JsonCreator 进行注释。这可以通过使用 @AllArgsConstructor(onConstructor = @__(@JsonCreator)) 注释类来完成。

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

包含这些更改的代码 sn-p:

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 依赖项。

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

【讨论】:

    【解决方案2】:

    在 java 中,必须在构造函数中设置最终属性,并且只能在以后读取。 但是杰克逊稍后试图改变这个属性。因此,您不能使用 jackson 来填充 final 字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多