我无法找出使用杰克逊实现自定义序列化/反序列化的正确方法。我有很多类(〜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个
非常相似的 序列化器/反序列化器。
我想到了添加自定义注释的各个领域,说@Units("Degree")
或@Units("Meters")
,这样的整数字段和实施SerializationProvider
,将在基于注释值,一个通用的方法创建序列化。但是我找不到一个可以获取有关属性注释的信息的地方。
带Unit
注释的想法真的很好。我们只需要添加自定义com.fasterxml.jackson.databind.ser.BeanSerializerModifier
和com.fasterxml.jackson.databind.ser.BeanPropertyWriter
实现。首先创建我们的注释类:
@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
}
具有所有这些之后,我们需要自定义属性序列化:
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
:
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
:
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);
}
}
上面的实现只是一个例子,应该针对其他原始类型进行改进。我们可以使用简单的模块以相同的方式注册它。重复使用与序列化相同:
unitModule.setDeserializerModifier(new UnitBeanDeserializerModifier());
可以序列化/反序列化< code >映射吗 在这种特殊情况下,我知道总是,和 - 第三方类(我有序列化器和反序列化器),其他值是盒装原语。 有可能和杰克逊做这样的事吗?使用MapSerializer/MapDeserializer可以做到这一点吗?(我找不到任何例子)
I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器
我使用的是JAVA 1.6和Jackson 1.9.9我有一个枚举 我添加了一个@jsonValue,这似乎完成了它将对象序列化为:
问题内容: 我正在使用JAVA 1.6和Jackson 1.9.9我有一个枚举 我添加了一个@JsonValue,这似乎可以将对象序列化为: 但是当我尝试反序列化时,我得到了 我在这里想念什么? 问题答案: 如果你希望将枚举类与其JSON表示完全脱钩,则@xbakesx指出的序列化器/反序列化器解决方案是一个很好的解决方案。 另外,如果你喜欢一个独立的解决方案,则基于·和·注释的实现会更方便。 因
我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif
我在试着读我的。json文件。Is是一个车辆存储类。 这是错误: com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造的实例(尽管至少存在一个Creator):无法构造的实例(尽管至少存在一个Creator):没有字符串参数构造函数/工厂方法来从[Source:(File); line: 1,列: 1]处的字符串值反序列化