[英]How to create default constructor for immutable class
我喜欢根据本文使我的对象不可变(为什么对象必须不可变) 。
但是,我正在尝试使用Jackson Object Mapper解析对象。 我最初得到的是JsonMappingException: No suitable constructor found for type [simple type, class ]: cannot instantiate from JSON object.
如前所述我可以修复它在这里 ,通过提供一个默认的构造,使我场的非决赛。
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@AllArgsConstructor
// @NoArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Data
public class School {
@NonNull
private final String schoolId;
@NonNull
private final String schoolName;
}
为了克服这个问题,我应该遵循什么良好的编程风格? 唯一的解决方法是使我的对象可变吗?
我可以使用不使用默认构造函数的其他映射器吗?
您可以使用Jackson工厂(用@JsonCreator注释的方法)从地图上读取字段并调用您的非默认构造函数:
class School {
//fields
public School(String id, String name) {
this.schoolId = id;
this.schoolName = name;
}
@JsonCreator
public static School create(Map<String, Object> object) {
return new School((String) object.get("schoolId"),
(String) object.get("schoolName"));
}
//getters
}
杰克逊将使用JSON的Map
版本调用create
方法。 这有效地解决了问题。
我相信您的问题是寻找Jackson解决方案,而不是寻求新的模式/风格。
@Value
制作不可变的数据类 @JsonProperty("name-of-property")
注释所有字段 lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
添加到您的lombok.config
,将其复制到生成的构造函数中 @JsonCreator
注释的全参数构造@JsonCreator
例:
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
class School {
@JsonProperty("schoolId")
String schoolId;
@JsonProperty("schoolName")
String schoolName;
}
使用@JsonCreator
注释的静态工厂方法有一个imo更好的替代方法,该方法为所有Elements具有构造函数(无论如何,这是不可变类的要求)。 注释与 @JsonCreator
也注释了所有参数@JsonProperty
是这样的:
class School {
//fields
@JsonCreator
public School(
@JsonProperty("id") String id,
@JsonProperty("name") String name) {
this.schoolId = id;
this.schoolName = name;
}
//getters
}
这些是@JsonCreator
批注为您提供的选项。 它在其文档中像这样描述它们:
- 没有参数的JsonProperty批注的单参数构造函数/工厂方法:如果是这样,则这就是所谓的“委托创建者”,在这种情况下,Jackson首先将JSON绑定到参数的类型,然后调用creator。 这通常与JsonValue(用于序列化)结合使用。
- 构造函数/工厂方法,其中每个参数都用JsonProperty或JacksonInject注释,以指示要绑定的属性的名称
在某些情况下,甚至可能不需要显式指定参数名称。 有关@JsonCreator
的文档进一步指出:
还要注意,除非您使用可以检测参数名称的扩展模块之一,否则所有JsonProperty批注都必须指定实际名称(“ default”不为空字符串)。 这是因为8之前的默认JDK版本无法存储和/或从字节码中检索参数名称。 但是对于JDK 8(或使用诸如Paranamer之类的帮助程序库,或诸如Scala或Kotlin之类的其他JVM语言),指定名称是可选的。
另外这也将与龙目岛版本的工作很好1.18.3
或向上,在这里你可以添加lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
您lombok.config
,因此有它的复制JsonProperty
注释构造,假设您确实用它注释了所有字段(无论如何,imo都应该这样做)。 要将@JsonCreator
-annotation放在构造函数上,可以使用实验性onX功能 。 对不可变数据类使用@Value
的@Value
,您的DTO可能看起来像这样(未经测试):
@Value
//@AllArgsConstructor(onConstructor = @__(@JsonCreator)) // JDK7 or below
@AllArgsConstructor(onConstructor_ = @JsonCreator) // starting from JDK8
class School {
@JsonProperty("schoolId")
String schoolId;
@JsonProperty("schoolName")
String schoolName;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.