当前位置: 首页 > 知识库问答 >
问题:

无法反序列化具有最终字段bu Jackson的最简单对象

饶承宣
2023-03-14

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

我知道答案应该很简单,但这是最常见的情况,应该从盒子里起作用,不是吗?

共有2个答案

常培
2023-03-14

在java中,final属性必须在构造函数中设置,并且只能稍后读取。但jackson稍后会尝试更改该属性。因此不能使用jackson填充最后一个字段。

堵乐
2023-03-14

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

如果你不用龙目岛,

  • @JsonCreator注释希望Jackson调用的构造函数
  • @JsonProperty注释构造函数参数。如果要跳过此操作,可以添加useParameterNamesModule扩展名

例:

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))注释类来完成。

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

包含以下更改的代码段:

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>
 类似资料:
  • 这是密码 输出量 我的问题是: 为什么jackson在完成构建后修改了没有setter的私有final字段?如果这是有意的,我该如何关闭它 非常感谢。

  • 问题内容: 在Java中进行序列化后,是否可以将字段设置为任何非默认值?我的用例是一个缓存变量- 这就是为什么。我也有一个习惯,即不要更改字段(即,地图的内容已更改,但对象本身保持不变)。但是,这些属性似乎是矛盾的- 尽管编译器允许这样的组合,但除反序列化之后,我无法将字段设置为任何值。 我尝试了以下操作,但没有成功: 简单的字段初始化(如示例所示):这是我通常所做的,但是在未序列化之后似乎没有发

  • 问题内容: 我正在尝试使用JSON(使用simplejson)序列化python对象列表,并收到以下错误:对象“不可JSON序列化”。 该类是一个简单的类,其字段只有整数,字符串和浮点数,并且从一个父超类继承相似的字段,例如: foo,bar是我上面提到的简单类型。唯一棘手的事情是,ChildClass有时具有一个字段,该字段引用另一个对象(类型不是ParentClass或ChildClass)。

  • 问题内容: 我想知道下面的代码是否有意义,因为编译器会警告“空白的最终字段对象可能尚未初始化”。有更好的方法吗? 问题答案: 我将字段定为final,并强制构造函数将值向上传递:

  • 问题内容: 使用JSON定义的样子,为了将其反序列化为对象,我需要在我的类上创建一个名为“ event”的属性,这是一个C#关键字。还有另一种方法可以告诉它字段名称是什么? 这是JSON的示例: {event:123 data:{“ data”:“ 0D0401”,“ ttl”:“ 60”,“ published_at”:“ 2014-04-16T18:04:42.446Z”,“ id”:“ 48

  • 问题内容: 我有一个定义不可变值类型的类,现在需要对其进行序列化。不变性来自构造函数中设置的最终字段。我已经尝试过序列化,并且它可以工作(令人惊讶的是?)-但我不知道如何进行。 这是课程的一个例子 鉴于该类没有no arg构造函数,如何实例化它并设置最终字段? (顺便说一句,我注意到了该类,尤其是因为IDEA并未为此类生成“ no serialVersionUID”检查警告,但尚未为我刚刚使其可序