Java 如何使用 ObjectMapper 在没有默认构造函数的情况下反/序列化不可变对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30568353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to de/serialize an immutable object without default constructor using ObjectMapper?
提问by Michal
I want to serialize and deserialize an immutable object using com.fasterxml.Hymanson.databind.ObjectMapper.
我想使用 com.fasterxml.Hymanson.databind.ObjectMapper 序列化和反序列化一个不可变对象。
The immutable class looks like this (just 3 internal attributes, getters and constructors):
不可变类看起来像这样(只有 3 个内部属性、getter 和构造函数):
public final class ImportResultItemImpl implements ImportResultItem {
private final ImportResultItemType resultType;
private final String message;
private final String name;
public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
super();
this.resultType = resultType;
this.message = message;
this.name = name;
}
public ImportResultItemImpl(String name, ImportResultItemType resultType) {
super();
this.resultType = resultType;
this.name = name;
this.message = null;
}
@Override
public ImportResultItemType getResultType() {
return this.resultType;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public String getName() {
return this.name;
}
}
However when I run this unit test:
但是,当我运行此单元测试时:
@Test
public void testObjectMapper() throws Exception {
ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
System.out.println("serialized: " + serialized);
//this line will throw exception
ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}
I get this exception:
我得到这个例外:
com.fasterxml.Hymanson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
at
... nothing interesting here
This exception asks me to create a default constructor, but this is an immutable object, so I don't want to have it. How would it set the internal attributes? It would totally confuse the user of the API.
这个异常要求我创建一个默认构造函数,但这是一个不可变对象,所以我不想拥有它。它如何设置内部属性?它会完全混淆 API 的用户。
So my question is:Can I somehow de/serialize immutable objects without default constructor?
所以我的问题是:我可以在没有默认构造函数的情况下以某种方式反/序列化不可变对象吗?
采纳答案by Sergei Petunin
To let Hymanson know how to create an object for deserialization, use the @JsonCreator
and @JsonProperty
annotations for your constructors, like this:
要让 Hymanson 知道如何为反序列化创建对象,请为构造函数使用@JsonCreator
和@JsonProperty
注释,如下所示:
@JsonCreator
public ImportResultItemImpl(@JsonProperty("name") String name,
@JsonProperty("resultType") ImportResultItemType resultType,
@JsonProperty("message") String message) {
super();
this.resultType = resultType;
this.message = message;
this.name = name;
}
回答by tkruse
You can use a private default constructor, Hymanson will then fill the fields via reflection even if they are private final.
您可以使用私有的默认构造函数,Hymanson 将通过反射填充字段,即使它们是私有的 final。
EDIT: And use a protected/package-protected default constructor for parent classes if you have inheritance.
编辑:如果您有继承,请为父类使用受保护/包保护的默认构造函数。
回答by Vladyslav Diachenko
The first answer of Sergei Petunin is right. However, we could simplify code with removing redundant @JsonProperty annotations on each parameter of constructor.
Sergei Petunin 的第一个答案是正确的。但是,我们可以通过删除构造函数的每个参数上的冗余 @JsonProperty 注释来简化代码。
It can be done with adding com.fasterxml.Hymanson.module.paramnames.ParameterNamesModule into ObjectMapper:
可以通过将 com.fasterxml.Hymanson.module.paramnames.ParameterNamesModule 添加到 ObjectMapper 中来完成:
new ObjectMapper()
.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))
(Btw: this module is registered by default in SpringBoot. If you use ObjectMapper bean from HymansonObjectMapperConfiguration or if you create your own ObjectMapper with bean Hymanson2ObjectMapperBuilder then you can skip manual registration of the module)
(顺便说一句:这个模块默认在 SpringBoot 中注册。如果您使用 HymansonObjectMapperConfiguration 中的 ObjectMapper bean,或者如果您使用 bean Hymanson2ObjectMapperBuilder 创建自己的 ObjectMapper,那么您可以跳过该模块的手动注册)
For example:
例如:
public class FieldValidationError {
private final String field;
private final String error;
@JsonCreator
public FieldValidationError(String field,
String error) {
this.field = field;
this.error = error;
}
public String getField() {
return field;
}
public String getError() {
return error;
}
}
and ObjectMapper deserializes this json without any errors:
和 ObjectMapper 反序列化这个 json 没有任何错误:
{
"field": "email",
"error": "some text"
}