我无法找出使用杰克逊实现自定义序列化/反序列化的正确方法。我有很多类(〜50),它们带有应被序列化/反序列化而不是原始的原始字段。喜欢:
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,页面,米等)。
一种简单的方法是在每个这样的字段中添加一对@JsonSerialize/ @JsonDeserialize注释并实现它们。但是我最终会得到100个 非常相似的 序列化器/反序列化器。
@JsonSerialize
@JsonDeserialize
我想到了添加自定义注释的各个领域,说@Units("Degree")或@Units("Meters"),这样的整数字段和实施SerializationProvider,将在基于注释值,一个通用的方法创建序列化。但是我找不到一个可以获取有关属性注释的信息的地方。
@Units("Degree")
@Units("Meters")
SerializationProvider
带Unit注释的想法真的很好。我们只需要添加自定义com.fasterxml.jackson.databind.ser.BeanSerializerModifier和com.fasterxml.jackson.databind.ser.BeanPropertyWriter实现。首先创建我们的注释类:
Unit
com.fasterxml.jackson.databind.ser.BeanSerializerModifier
com.fasterxml.jackson.databind.ser.BeanPropertyWriter
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Unit { String value(); }
POJO 模型可能如下所示:
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 }
具有所有这些之后,我们需要自定义属性序列化:
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:
SimpleModule
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" } }
当然,您需要对其进行测试并处理所有极端情况,但以上示例显示了总体思路。以类似的方式,我们可以处理反序列化。我们需要实现custom BeanDeserializerModifier和一个custom UnitDeserialiser:
BeanDeserializerModifier
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:
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); } }
上面的实现只是一个例子,应该针对其他原始类型进行改进。我们可以使用简单的模块以相同的方式注册它。重复使用与序列化相同:
unitModule.setDeserializerModifier(new UnitBeanDeserializerModifier());