简体   繁体   English

Jackson定制序列化和反序列化

[英]Jackson custom serialization and deserialization

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. 我有许多类(〜50),它们带有应被序列化/反序列化而不是原始的原始字段。 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"
}

all serializations and deserializations are very similar, I just need to add a suffix after the integer (C, pages, meters, etc..) 所有序列化和反序列化都非常相似,我只需要在整数之后添加一个后缀(C,页面,米等)。

A straightforward way to do this is to put a pair of @JsonSerialize / @JsonDeserialize annotation to each such field and implement them. 一种简单的方法是在每个这样的字段中放置一对@JsonSerialize / @JsonDeserialize批注并实现它们。 But i will end up with 100 very similar serializers / deserializers. 但是我最终会得到100个非常相似的序列化器/解串器。

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. 我考虑过将自定义批注添加到每个字段,例如@Units("Degree")@Units("Meters") ,并实现一个SerializationProvider ,该SerializationProvider程序将基于批注值以通用方式创建序列化程序。 But I didn't find a place where the information about the property annotations is available. 但是我没有找到有关属性注释信息的地方。

Idea with Unit annotation is really good. Unit注释的想法真的很好。 We need to only add custom com.fasterxml.jackson.databind.ser.BeanSerializerModifier and com.fasterxml.jackson.databind.ser.BeanPropertyWriter implementations. 我们只需要添加自定义com.fasterxml.jackson.databind.ser.BeanSerializerModifiercom.fasterxml.jackson.databind.ser.BeanPropertyWriter实现。 Let's create first our annotation class: 首先创建我们的注释类:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Unit {
    String value();
}

POJO model could look like below: 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);
    }
}

Using SimpleModule we can register it and use with 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));
    }
}

prints: 打印:

{
  "user" : {
    "height" : "10 m"
  },
  "food" : {
    "temperature" : "50 C"
  },
  "house" : {
    "width" : "10 m"
  }
}

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 : 我们需要实现自定义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;
    }
}

and example deserialiser for 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);
    }
}

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());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM