使用新的记录类时无法反序列化

2022-09-04 02:46:16

我正在尝试看看我是否可以用Java 14中的新Record类替换我现有的Pojos。但无法做到这一点。收到以下错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造的实例(不存在创建者,如默认构造):无法从 Object 值反序列化(没有基于委托或基于属性的创建者)com.a.a.Post

我得到的错误是说记录没有构造函数,但从我所看到的,记录类在后台处理它,相关的getter也在后台设置(不是getters,而是id()title()等等,没有get前缀)。是不是因为Spring还没有采用最新的Java 14记录?请指教。谢谢。

我在Spring Boot版本2.2.6中使用Java 14来执行此操作。

以下工作使用通常的POJO。

邮政类

public class PostClass {
    private int userId;
    private int id;
    private String title;
    private String body;

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

调用休息服务的方法,现在工作,因为我正在使用上面的POJO。

public PostClass[] getPosts() throws URISyntaxException {
    String url = "https://jsonplaceholder.typicode.com/posts";
    return template.getForEntity(new URI(url), PostClass[].class).getBody();
}

但是,如果我切换到跟随我使用记录的位置,我会收到上述错误。

新记录类。

public record Post(int userId, int id, String title, String body) {
}

将方法更改为使用失败的记录。

public Post[] getPosts() throws URISyntaxException {
    String url = "https://jsonplaceholder.typicode.com/posts";
    return template.getForEntity(new URI(url), Post[].class).getBody();
}

编辑:

尝试将构造函数按如下方式添加到记录 Post 中,并出现相同的错误:

public record Post(int userId, int id, String title, String body) {
    public Post {
    }
}

public record Post(int userId, int id, String title, String body) {
    public Post(int userId, int id, String title, String body) {
        this.userId = userId;
        this.id = id;
        this.title = title;
        this.body = body;
    }
}

答案 1

使用一些 Jackson 注释是可能的,这会导致 Jackson 使用字段而不是 getter。仍然远不如Java 14之前的类(没有龙目岛或类似的解决方案)那么冗长。

record Foo(@JsonProperty("a") int a, @JsonProperty("b") int b){
}

这可能有效,因为根据 https://openjdk.java.net/jeps/359

如果声明批注适用于记录组件、参数、字段或方法,则允许在记录组件上使用声明批注。适用于任何这些目标的声明注释将传播到任何受授权成员的隐式声明中。

另请参阅:何时使用@JsonProperty属性,以及它的用途是什么?

也可以使用@JsonAutoDetect

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
record Bar(int a, int b){
}

如果将对象映射器配置为全局使用字段可见性,则不需要在类级别进行此注记。

另请参阅:如何指定 jackson 仅使用字段 - 最好是全局字段

例:

public class Test {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper om = new ObjectMapper();
        System.out.println(om.writeValueAsString(new Foo(1, 2)));  //{"a":1,"b":2}
        System.out.println(om.writeValueAsString(new Bar(3, 4)));  //{"a":3,"b":4} 
    }

    record Foo(@JsonProperty("a") int a, @JsonProperty("b") int b){
    }

    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
    record Bar(int a, int b){
    }
}

该功能还有一个Github问题:https://github.com/FasterXML/jackson-future-ideas/issues/46


推荐