Jackson定制序列化和反序列化 [英] Jackson custom serialization and deserialization

查看:233
本文介绍了Jackson定制序列化和反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法找出用杰克逊实现自定义序列化/反序列化的正确方法. 我有很多类(〜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.BeanSerializerModifiercom.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆