Gson实现接口自定义反序列化

 

在项目中同样遇到了对json字符串进行反序列化时,遇到了多态情况下,无法找到对应类,所以写这篇文章来mark一下

首先抛出原始代码,再给上解决方案~

原始代码:

原始json串:

{"type":"int","specs":{"min":"1","max":"12","unit":"aw","unitName":"饱和度","step":"1"}}

TslDataType对象,Type 为内部枚举类,TslSpecs为接口,对应枚举类类型的各个实现类

TslDataType:构造方法中type是通过tslSpecs的方法来给赋值的

import com.lbs.iot.beans.tsl.specs.TslSpecs;

public class TslDataType {
    private final Type type;

    private final TslSpecs specs;

    public TslDataType(TslSpecs specs) {
        this.type = specs.getType();
        this.specs = specs;
    }

    public Type getType() {
        return type;
    }

    public TslSpecs getSpecs() {
        return specs;
    }

    public  enum Type {
        INT("int"),
        TEXT("text"),
        DATE("date"),
        BOOL("bool"),
        ENUM("enum"),
        ARRAY("array"),
        FLOAT("float"),
        STRUCT("struct"),
        DOUBLE("double");

        private final String type;

        Type(String type) {
            this.type = type;
        }

        public String getType() {
            return type;
        }


    }

}

 

TslSpecs接口:

import com.lbs.iot.beans.tsl.schema.TslDataType;

public interface TslSpecs {

    TslDataType.Type getType();

}

并附上两个实现类代码:IntSpecs和TexSpecs

import com.lbs.iot.beans.tsl.schema.TslDataType;

public class IntSpecs implements TslSpecs {

    private final int min;
    private final int max;
    private final int step;

    public IntSpecs(int min, int max, int step) {
        this.min = min;
        this.max = max;
        this.step = step;
    }

    public IntSpecs() {
        this(Integer.MIN_VALUE, Integer.MAX_VALUE, 1);
    }

    public int getMin() {
        return min;
    }

    public int getMax() {
        return max;
    }

    public int getStep() {
        return step;
    }

    @Override
    public TslDataType.Type getType() {
        return TslDataType.Type.INT;
    }
}
import com.lbs.iot.beans.tsl.schema.TslDataType;

public class TextSpecs implements TslSpecs {

    private final int length;

    public TextSpecs(int length) {
        this.length = length;
    }

    public TextSpecs() {
        this(2048);
    }

    public int getLength() {
        return length;
    }

    @Override
    public TslDataType.Type getType() {
        return TslDataType.Type.TEXT;
    }
}

这种情况下,直接通过Gson的构建对象来反序列化是无法成功的,

会报错Unable to invoke no-args constructor for interface com.lbs.iot.beans.tsl.specs.TslSpecs,Registering an InstanceCreator with Gson for this type may fix this problem.

原因:这是因为反序列化的时候,遇到了TslSpecs接口,无法确定是那个实现类,所以无法实例化,所以才出现了上面的问题,

那么解决的办法就是,自定义反序列化,遇到此接口时能找到对应的实现类。

解决办法:

第一步,自定义TslDeserializer 类实现 JsonDeserializer<TslDataType>接口,并传入对象泛型。类里包含了构造方法,自定义注册方法,自定义反序列化处理方法

在deserialize方法中就能获取到对象对应的json块,然后根据json串中的type值就可以获取到提前注册到map中的对应的实现类(第二步构建Gson的时候会明白);

import com.google.gson.*;
import com.lbs.iot.beans.tsl.schema.TslDataType;
import com.lbs.iot.beans.tsl.specs.TslSpecs;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class TslDeserializer implements JsonDeserializer<TslDataType>
{
  String tslTypeElementName;
  Gson gson;
  Map<String, Class<? extends TslSpecs>> tslTypeRegistry;

  public TslDeserializer(String tslTypeElementName)
  {
    this.tslTypeElementName = tslTypeElementName;
    gson = new Gson();
    tslTypeRegistry = new HashMap<>(); // Java 7 required for this syntax.
  }

  public void registerSpecsType(String tslTypeName, Class<? extends TslSpecs> tslSpecs)
  {
    tslTypeRegistry.put(tslTypeName, tslSpecs);
  }

  @Override
  public TslDataType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    JsonObject tslDataObject = json.getAsJsonObject();
    JsonElement tslTypeElement = tslDataObject.get(tslTypeElementName);
    Class<? extends TslSpecs> tslSpecs = tslTypeRegistry.get(tslTypeElement.getAsString());
    TslSpecs specs = gson.fromJson(tslDataObject.get("specs"), tslSpecs);
    TslDataType dataType = new TslDataType(specs);
    return dataType;
  }
}

第二步,根据自定义TslDeserializer类,来构建Gson对象,

此处需要注意原始json串中的type值是关键,反序列化时是根据type值来与 tslDeserializer.registerSpecsType中的key来对应的,所以进行接口反序列化的时候,必定要有一个通用的key来进行区分,否则无法进行实现类的对应匹配,也就无法完成实例化

TslDeserializer tslDeserializer = new TslDeserializer("type");此行代码就是指定了根据Json串中那个字段来获取key,然后通过key值从自定义注册器中获取对应的class类进行实例化,然后再通过gosn的反序列化,即可实例化对象,然后返回对象即可~

//先创建对象,再根据type值进行注册,并映射对应的实现类
TslDeserializer tslDeserializer = new TslDeserializer("type");
        tslDeserializer.registerSpecsType("int", IntSpecs.class);
        tslDeserializer.registerSpecsType("text", TextSpecs.class);
        tslDeserializer.registerSpecsType("date", DateSpecs.class);
        tslDeserializer.registerSpecsType("bool", BoolSpecs.class);
        tslDeserializer.registerSpecsType("enum", EnumSpecs.class);
        tslDeserializer.registerSpecsType("array", ArraySpecs.class);
        tslDeserializer.registerSpecsType("float", FloatSpecs.class);
        tslDeserializer.registerSpecsType("struct", StructSpecs.class);
        tslDeserializer.registerSpecsType("double", DoubleSpecs.class);

//将tslDeserializer注册进TypeAdapter中去,遇到TslDataType.class时,就走自定义方法中
        Gson gson = new GsonBuilder()
                .serializeNulls()
                .registerTypeAdapter(TslDataType.class, tslDeserializer)
                .create();

第三步:直接 通过上面获取到的gosn对象,进行反序列化获取对象即可

TslDataType tslDataType = gson.fromJson(jsonData, TslDataType.class);

至此,基于Gson的接口反序列化也实现了。

此处重点是,所有的实现类都需要有一个相同的字段来进行标识区分。此json串中 type就担任此职能,一定要注意这一点~~~~!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值