背景

AResult A结果
BResult B结果
AbstractResult 结果基类

问题现象

在存入mongo时结果将会以List<AbstractResult> 序列化存入mongo,但是在取出结果时出现了问题。

通过mongo取出数据后,希望还原成为List<AbstractResult> ,于是通过反序列化来还原格式,此时出现问题,因为AbstractResult是抽象类,在进行反序列化时,无法反序列化成为对应的类。于是反序列化出来的List内元素全是null

解决思路一

本文的解决思路是编写ParserConfig类,类中复写getDeserializer(Type type)方法,并在JSON.parseObject时作为参数传入,该方法是用来根据类名来返回具体的反序列化方法的,通过复写该方法,在遇到Type为AbstractResult.class时,就可以返回指定的子类的反序列化方法,如

ParserConfig parserConfig = new ParserConfig() {
     @Override
     public ObjectDeserializer getDeserializer(Type type) {
            if (type == ActionConfig.class) {
                return super.getDeserializer(LimitActionConfig.class);
             }
             return super.getDeserializer(type);
     }
};

BResult方法或者AResult方法。尝试该解决思路,发现在整个list都是同一种子类时可以实现正常的反序列化,将整个List反序列化为AResult或者BResult。

解决思路二

上面的解决方法虽然能够成功,但是并不能解决实际遇到的问题,因为实际需要进行反序列化的List中的类型不是统一的,而是AResult和BResult同时存在的,所以必须有更加精确的反序列化方法。

网上没有类似问题的解决思路,于是只能翻阅源码查找解决思路。在查看了大量源码之后,找到了解决方案。

本解决方案借鉴了思路一的方法,在遇到Type为AbstractResult.class时,返回我自己编写的自定义的反序列化方法。代码如下

private static final ParserConfig parserConfig = new ParserConfig() {
    @Override
    public ObjectDeserializer getDeserializer(Type type) {
        if (type == AbstractResult.class) {
            return new AbstractResultDeserializer();
        }
        return super.getDeserializer(type);
    }
};

其中AbstractResultDeserializer的源码如下

public class AbstractResultDeserializer implements ObjectDeserializer {
    public static final String CHARACTERISTIC = "characteristic";
    @Override
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object object) {
        String text = (String) parser.input; //需要反序列化的文本
        int begin = ((JSONScanner) parser.lexer).pos()+1;//当前反序列化进行到的位置
        text = text.substring(begin,findEndPoint(text,begin));
        if (text.contains(CHARACTERISTIC)){
            AbstractResult AResult = 
               parser.getConfig().getDeserializer(AResult.class).deserialze(parser,type, 
               object);
            return (T) AResult;
         }else {
            AbstractResult BResult =
               parser.getConfig().getDeserializer(BResult.class).deserialze(parser, 
               type, object);
            return (T) BResult;
         }
    }

   @Override
   public int getFastMatchToken() {
          return 0;
   }

   public static Integer findEndPoint(String text , int begin){
        int stack =0;
        int t;
        for (t = begin; t < text.length(); t++) {
            char ch = text.charAt(t);
            if (ch  == '{'){
                stack++;
            }
            if (ch == '}'){
                if (stack == 0){
                    break;
                }else {
                    stack--;
                }
            }
        }
        return t;
   }
}

自定义反序列化的具体反序列过程就是通过重写deserialze()方法实现,下面介绍一下方法内的变量和函数

CHARACTERISTIC AResult类中特有的变量名称

text  反序列化的总文本

begin List反序列化进行到的位置

findEndPoint()该函数能找到当前反序列化类在文本中的结束位置

该自定义反序列化主要逻辑为

1.从整体List需要反序列化的文本中分割出当前类的文本

2.判断文本中是否存在AResult类中特有的变量名称

3.若存在则调用AResult的反序列方法

4.若不存在则调用BResult的反序列方法