Jackson定制序列化和反序列化 [英] Jackson custom serialization and deserialization
问题描述
我无法找出用杰克逊实现自定义序列化/反序列化的正确方法. 我有很多类(〜50),它们带有应被序列化/反序列化而不是原始的原始字段. 像:
i'm unable to figure out the proper way to implement the custom serialization/deserialization with jackson. I have many classes (~50) with primitive fields that should be serialized/deserialized not as primitives. like:
class User {
int height // this field should be serialized as "height": "10 m"
}
class Food {
int temperature // this field should be serialized as "temperature": "50 C"
}
class House {
int width // this field should be serialized as "width": "10 m"
}
所有序列化和反序列化都非常相似,我只需要在整数(C,页面,米等)之后添加一个后缀即可.
all serializations and deserializations are very similar, I just need to add a suffix after the integer (C, pages, meters, etc..)
一种简单的方法是在每个这样的字段中放置一对@JsonSerialize
/@JsonDeserialize
批注并实现它们.
但最终我会得到100个非常相似的序列化器/反序列化器.
A straightforward way to do this is to put a pair of @JsonSerialize
/@JsonDeserialize
annotation to each such field and implement them.
But i will end up with 100 very similar serializers / deserializers.
我考虑过将自定义注释添加到每个字段(例如@Units("Degree")
或@Units("Meters")
)到此类整数字段,并实现一个SerializationProvider
,它将基于注释值以通用方式创建序列化程序.
但是我找不到在哪里可以找到有关属性注释的信息.
I thought about adding custom annotation to each field, say @Units("Degree")
or @Units("Meters")
, to such integer fields and implement a SerializationProvider
that will create serializers in a generic way based on an annotation value.
But I didn't find a place where the information about the property annotations is available.
推荐答案
带有Unit
批注的想法真的很好.我们只需要添加自定义com.fasterxml.jackson.databind.ser.BeanSerializerModifier
和com.fasterxml.jackson.databind.ser.BeanPropertyWriter
实现.首先创建我们的注释类:
Idea with Unit
annotation is really good. We need to only add custom com.fasterxml.jackson.databind.ser.BeanSerializerModifier
and com.fasterxml.jackson.databind.ser.BeanPropertyWriter
implementations. Let's create first our annotation class:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Unit {
String value();
}
POJO
模型如下所示:
class Pojo {
private User user = new User();
private Food food = new Food();
private House house = new House();
// getters, setters, toString
}
class User {
@Unit("m")
private int height = 10;
// getters, setters, toString
}
class Food {
@Unit("C")
private int temperature = 50;
// getters, setters, toString
}
class House {
@Unit("m")
private int width = 10;
// getters, setters, toString
}
具有所有我们需要自定义的属性序列化:
Having all of that we need to customise property serialisation:
class UnitBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (int i = 0; i < beanProperties.size(); ++i) {
final BeanPropertyWriter writer = beanProperties.get(i);
AnnotatedMember member = writer.getMember();
Unit units = member.getAnnotation(Unit.class);
if (units != null) {
beanProperties.set(i, new UnitBeanPropertyWriter(writer, units.value()));
}
}
return beanProperties;
}
}
class UnitBeanPropertyWriter extends BeanPropertyWriter {
private final String unit;
protected UnitBeanPropertyWriter(BeanPropertyWriter base, String unit) {
super(base);
this.unit = unit;
}
@Override
public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
gen.writeFieldName(_name);
final Object value = (_accessorMethod == null) ? _field.get(bean) : _accessorMethod.invoke(bean, (Object[]) null);
gen.writeString(value + " " + unit);
}
}
使用SimpleModule
,我们可以注册它并与ObjectMapper
一起使用:
Using SimpleModule
we can register it and use with ObjectMapper
:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
SimpleModule unitModule = new SimpleModule();
unitModule.setSerializerModifier(new UnitBeanSerializerModifier());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(unitModule);
Pojo pojo = new Pojo();
System.out.println(mapper.writeValueAsString(pojo));
}
}
打印:
{
"user" : {
"height" : "10 m"
},
"food" : {
"temperature" : "50 C"
},
"house" : {
"width" : "10 m"
}
}
当然,您需要对其进行测试并处理所有极端情况,但以上示例显示了总体思路.以类似的方式,我们可以处理反序列化.我们需要实现自定义BeanDeserializerModifier
和一个自定义UnitDeserialiser
:
Of course, you need to test it and handle all corner cases but above example shows general idea. In the similar way we can handle deserialisation. We need to implement custom BeanDeserializerModifier
and one custom UnitDeserialiser
:
class UnitBeanDeserializerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
JsonDeserializer<?> jsonDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
if (jsonDeserializer instanceof StdScalarDeserializer) {
StdScalarDeserializer scalarDeserializer = (StdScalarDeserializer) jsonDeserializer;
Class scalarClass = scalarDeserializer.handledType();
if (int.class == scalarClass) {
return new UnitIntStdScalarDeserializer(scalarDeserializer);
}
}
return jsonDeserializer;
}
}
和int
的反序列化器示例:
class UnitIntStdScalarDeserializer extends StdScalarDeserializer<Integer> {
private StdScalarDeserializer<Integer> src;
public UnitIntStdScalarDeserializer(StdScalarDeserializer<Integer> src) {
super(src);
this.src = src;
}
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getValueAsString();
String[] parts = value.split("\\s+");
if (parts.length == 2) {
return Integer.valueOf(parts[0]);
}
return src.deserialize(p, ctxt);
}
}
以上实现只是一个示例,应该针对其他原始类型进行改进.我们可以使用简单的模块以相同的方式注册它.重复使用与序列化相同的方法:
Above implementation is just an example and should be improved for other primitive types. We can register it in the same way using simple module. Reuse the same as for serialisation:
unitModule.setDeserializerModifier(new UnitBeanDeserializerModifier());
这篇关于Jackson定制序列化和反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!