json 反序列化, 获取字段的泛型类型
分类:项目问题
阅读:20
作者:皇太极
发布:2020-05-06 13:12:13

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

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

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

示例:

  1. @Getter
  2. @Setter
  3. public class MyExpression<T> {
  4. private Class<T> clz;
  5. private T t;
  6. private String expr;
  7. public MyExpression() {
  8. }
  9. public MyExpression(String expr) {
  10. this.expr = expr;
  11. }
  12. public MyExpression(Class<T> clz, String expr) {
  13. this.clz = clz;
  14. this.expr = expr;
  15. }
  16. }
  1. @Getter
  2. @Setter
  3. public class MyReward implements Serializable {
  4. private static final long serialVersionUID = 2670751308594930008L;
  5. private int id;
  6. private String name;
  7. private String name2;
  8. private MyExpression<Boolean> aaa;
  9. private MyExpression<Long> bbb;
  10. private MyExpression<Boolean> ccc;
  11. }
  1. ObjectMapper mapper = new ObjectMapper();
  2. SimpleModule simpleModule = new SimpleModule();
  3. simpleModule.addSerializer(MyExpression.class,new MyExpressionSerializer());
  4. simpleModule.addDeserializer(MyExpression.class, new MyExpressionDeserializer());
  5. //simpleModule.addDeserializer(String.class, new StringDeserializer());
  6. mapper.registerModule(simpleModule);

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

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

  1. public class MyExpressionSerializer extends JsonSerializer<MyExpression> {
  2. @Override
  3. public void serialize(MyExpression value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
  4. String expr = value.getExpr();
  5. gen.writeString(expr);
  6. }
  7. }

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

  1. @Slf4j
  2. public class MyExpressionDeserializer extends JsonDeserializer<MyExpression>
  3. implements ContextualDeserializer {
  4. private Class clz;
  5. @Override
  6. public MyExpression deserialize(JsonParser jp, DeserializationContext context) throws IOException {
  7. String expr = "deserialize---" + clz + " " + jp.getText().trim();
  8. System.out.println(expr);
  9. return new MyExpression<>(clz, expr);
  10. }
  11. @Override
  12. public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
  13. Class<?> rawClass = property.getType().containedTypeOrUnknown(0).getRawClass();
  14. System.out.println(rawClass);
  15. return new MyExpressionDeserializer(rawClass);
  16. }
  17. public MyExpressionDeserializer() {
  18. }
  19. public MyExpressionDeserializer(Class clz) {
  20. this.clz = clz;
  21. }
  22. }

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


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

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

  1. @Slf4j
  2. public class MyExpressionDeserializer extends JsonDeserializer<MyExpression> implements ContextualDeserializer {
  3. @Override
  4. public MyExpression deserialize(JsonParser jp, DeserializationContext context) throws IOException {
  5. String expr = jp.getText().trim();
  6. Object attribute = context.getAttribute(attribuateKey(jp.getParsingContext().getCurrentValue().getClass(),jp.getParsingContext().getCurrentName()));
  7. return new MyExpression<>((Class) attribute, expr);
  8. }
  9. @Override
  10. public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
  11. Class<?> rawClass = property.getType().containedTypeOrUnknown(0).getRawClass();
  12. ctxt.setAttribute(attribuateKey(property.getMember().getDeclaringClass(),property.getName()), rawClass);
  13. return this;
  14. }
  15. private String attribuateKey(Class clz, String name) {
  16. return String.format("%s#%s", clz.getName(), name);
  17. }
  18. }