Java 使用新记录类时无法反序列化
我试图看看是否可以用Java14中的新记录类替换现有的POJO。但我们不能这样做。获取以下错误: com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法 构造Java 使用新记录类时无法反序列化,java,spring,spring-boot,java-14,java-record,Java,Spring,Spring Boot,Java 14,Java Record,我试图看看是否可以用Java14中的新记录类替换现有的POJO。但我们不能这样做。获取以下错误: com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法 构造com.a.a.Post的实例(无创建者,如默认值 构造,存在):无法从对象值(无委托)反序列化- (或基于属性的创建者) 我得到的错误是记录没有构造函数,但从我看到的记录类在后台处理它,并且相关的getter也在后台设置(不是getter,而是id()title()
com.a.a.Post
的实例(无创建者,如默认值
构造,存在):无法从对象值(无委托)反序列化-
(或基于属性的创建者)
我得到的错误是记录没有构造函数,但从我看到的记录类在后台处理它,并且相关的getter也在后台设置(不是getter,而是id()title()等等,没有get前缀)。是不是因为Spring还没有采用最新的Java14记录?请给我一些建议。谢谢
我在SpringBootVersion2.2.6中使用Java14实现了这一点
下面使用常用的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;
}
}
方法调用rest服务,该服务现在可以工作,因为我正在使用上述POJO
public PostClass[] getPosts() throws URISyntaxException {
String url = "https://jsonplaceholder.typicode.com/posts";
return template.getForEntity(new URI(url), PostClass[].class).getBody();
}
但如果我切换到使用record的地方,我就会得到上面的错误
新唱片班
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();
}
编辑:
尝试按如下方式向记录栏添加构造函数,但出现相同错误:
public record Post(int userId, int id, String title, String body) {
public Post {
}
}
或
编译器为记录生成构造函数和其他访问器方法 就你而言
public final class Post extends java.lang.Record {
public Post(int, int java.lang.String, java.lang.String);
public java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int userId();
public int id();
public java.lang.String title();
public java.lang.String body();
}
在这里,您可以看到没有需要的默认构造函数。您使用的构造函数是一个紧凑的构造函数
public Post {
}
您可以将默认/无参数构造函数定义为
public record Post(int userId, int id, String title, String body) {
public Post() {
this(0,0, null, null);
}
}
但是Jackson使用Getter和setter来设置值。因此,简而言之,您不能使用Record映射响应
编辑为PSA:as of.某些Jackson注释可能会导致Jackson使用字段而不是getter。仍然比Java14之前的类(没有Lombok或类似的解决方案)要简单得多 这可能是因为: 允许在记录组件上使用声明注释(如果 适用于记录组件、参数、字段或方法。 适用于任何这些目标的声明注释 传播到任何授权成员的隐式声明 另见: 也可以使用
@jsonautodect
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
record Bar(int a, int b){
}
如果将Objectmapper配置为全局使用字段可见性,则不需要类级别上的此注释
另见:
例如:
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问题:- 为jackson使用参数名模块(确保编译器设置了-parameters)或将`@JsonProperty(“name”)添加到记录中的每个字段
- 将
添加到构造函数中。我无法判断继承是否能正常工作,因此您可能必须显式声明构造函数并对其进行注释@JsonCreator
new ObjectMapper().registerModules(new ParameterNamesModule())
试一试
@JsonCreator record Value(String x);
或者类似的
record Value(String x) {
@JsonCreator
public Value(String x) {
this.x = x;
}
}
或者一路到
record Value(@JsonProperty("x") String x) {
@JsonCreator
public Value(@JsonProperty("x") String x) {
this.x = x;
}
}
这就是我让lombok和jackson的不可变POJO工作的方式,我不明白为什么记录不能在相同的格式下工作。我的设置是Jackson parameter names module,-parameters编译器标志,用于java8(我认为这不是像jdk9+)、构造函数上的@JsonCreator所必需的。使用此设置的真实类的示例
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
public final class Address {
private final String line1;
private final String line2;
private final String city;
private final String region;
private final String postalCode;
private final CountryCode country;
}
这是预定的杰克逊2.12
显示新的
Post
类,通过错误消息,我假设您没有无参数或默认构造函数。faik记录中的所有字段都是最终字段,这意味着它可能没有无参数/默认构造函数,这是jackson用来构建对象的。请参见上面提到的@Deadpool新的Post类->公共记录Post@123尝试添加构造函数(请参见上面的编辑部分)并获得相同的结果。我也面临同样的问题-您是否找到了解决此问题的正确方法?我已经尝试了您提到的建议选项。它抛出编译错误,说“非规范记录构造函数必须委托给另一个构造函数”。因此,简而言之,您不能使用记录映射响应。Jackson必须合并这些功能。它可能会在未来的版本中出现。记录是预览的,这是有原因的,所以我们可以提供反馈。也许如果有足够多的人抱怨记录没有遵循JavaBean命名约定,他们会改变它。例如,他们不太可能改变这一点。记录作为实现细节很有用,您以前使用Map.Entry
作为元组。
record Value(@JsonProperty("x") String x) {
@JsonCreator
public Value(@JsonProperty("x") String x) {
this.x = x;
}
}
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
public final class Address {
private final String line1;
private final String line2;
private final String city;
private final String region;
private final String postalCode;
private final CountryCode country;
}