json 反序列化, 获取字段的泛型类型

阅读:813
作者:majingjing
发布:2020-05-06 13:12:13

现在开发中基本都使用json了, json的解析框架也是很多, 非常流行并且强烈推荐的还是 jackson 框架

该框架的出色之处我就不在列举了, 最最重要的是可以自定义序列化和反序列化的处理器

但是在项目中总会遇到各种特殊的解析或泛解析场景, 如题说所的获取字段类型的泛型类型

示例:

@Getter
@Setter
public class MyExpression<T> {

    private Class<T> clz;
    private T t;
    private String expr;

    public MyExpression() {
    }

    public MyExpression(String expr) {
        this.expr = expr;
    }

    public MyExpression(Class<T> clz, String expr) {
        this.clz = clz;
        this.expr = expr;
    }
}
@Getter
@Setter
public class MyReward implements Serializable {

    private static final long serialVersionUID = 2670751308594930008L;
    private int id;
    private String name;
    private String name2;
    private MyExpression<Boolean> aaa;
    private MyExpression<Long> bbb;
    private MyExpression<Boolean> ccc;

}
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(MyExpression.class,new MyExpressionSerializer());
simpleModule.addDeserializer(MyExpression.class, new MyExpressionDeserializer());
//simpleModule.addDeserializer(String.class, new StringDeserializer());
mapper.registerModule(simpleModule);

如上代码, 我们想在解析的时候能够获取到 MyExpression<T> 这个T 到底是 Boolean 或是 Long等具体类型

我们在序列化的时候可以将 对象字段直接变成 字符串

public class MyExpressionSerializer extends JsonSerializer<MyExpression> {

    @Override
    public void serialize(MyExpression value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        String expr = value.getExpr();
        gen.writeString(expr);
    }
}

同样, 我们需要将对应的json字符串,转换成 对象, 常规的泛序列化是只可以转换出具体的 内容, 但是无法获得具体的泛型类型 ?
参考网址: https://github.com/FasterXML/jackson-databind/issues/2711

@Slf4j
public class MyExpressionDeserializer extends JsonDeserializer<MyExpression>
        implements ContextualDeserializer {

    private Class clz;

    @Override
    public MyExpression deserialize(JsonParser jp, DeserializationContext context) throws IOException {
        String expr = "deserialize---" + clz + " " + jp.getText().trim();
        System.out.println(expr);

        return new MyExpression<>(clz, expr);
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        Class<?> rawClass = property.getType().containedTypeOrUnknown(0).getRawClass();
        System.out.println(rawClass);

        return new MyExpressionDeserializer(rawClass);
    }


    public MyExpressionDeserializer() {
    }

    public MyExpressionDeserializer(Class clz) {
        this.clz = clz;
    }
}

通过 实现 ContextualDeserializer 来实现泛型的获取


总结: 通过如上的示例代码, 我们可以在解析的时候维护我们所需要的参数, 这就给我们的解析工作带来了非常大的灵活性. 基本可以完成任何操作.

优化 可以将泛型类型存储到上下文中

@Slf4j
public class MyExpressionDeserializer extends JsonDeserializer<MyExpression> implements ContextualDeserializer {

    @Override
    public MyExpression deserialize(JsonParser jp, DeserializationContext context) throws IOException {
        String expr = jp.getText().trim();
        Object attribute = context.getAttribute(attribuateKey(jp.getParsingContext().getCurrentValue().getClass(),jp.getParsingContext().getCurrentName()));
        return new MyExpression<>((Class) attribute, expr);
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        Class<?> rawClass = property.getType().containedTypeOrUnknown(0).getRawClass();
        ctxt.setAttribute(attribuateKey(property.getMember().getDeclaringClass(),property.getName()), rawClass);
        return this;
    }

    private String attribuateKey(Class clz, String name) {
        return String.format("%s#%s", clz.getName(), name);
    }
}