都知道在ObjectBox
中,表关系在POJO中是用ToOne
或ToMany
对象来表示的。而当我们的业务场景中需要用到Json
数据进行转换时,这两个对象的存在则成为了一种麻烦。那么我们该怎么处理这两个对象在Json
数据序列化和反序列化的问题呢?
这里以Gson
为例(基础配置过程省略)
Entity.class
class Entity {
private String name;
private String value;
}
public void toJson(){
String json=new Json().toJson(new Entity());
}
public void fromJson(){
Entity entity=new Json().fromJson(json,Entity.class);
}
以上为Gson
最简单基础的应用。
但是当我们的POJO涉及到ObejctBox
的关联关系时,以上代码就不能解决问题了。
以下为建立了标间关系的Entity.class
和 Target.class
,省略了Id
和ObjectBox
注解等。
class Entity {
private String name;
private String value;
private List<Target> targets;//ToMany
//省略geter setter
}
class Target {
private String name;
private String value;
private ToOne<Entity> entity;
//省略geter setter
}
在ObjectBox
中,ToMany
本身实现了List
接口,故在定义POJO时,可以将ToMany
字段定义为List
类型来使用该对象。
当我们创建Entity
和Target
的实例时,ObjectBox
会自动为这里的List<Target> targets
以及ToOne<Entity> entity
属性分别实例化一个ToMany
和ToOne
对象,故不需要我们手动实例化。
以上两个class
在使用Gson
序列化时,Entity
能成功被序列化,而Target
对象则由于包含ToOne
类型的属性无法成功序列化。在反序列化时,Entity
的List<Target> targets
会被实例化为一个ArrayList
对象,在ObjectBox
中是不会对该属性进行操作的,需要我们再次手动转换。而Target
则仍然因为ToOne
类型的属性无法被反序列化,这不是我们希望看到的。
此时Gson
的TypeAdapter.class
这个类则可以解决以上问题,由于内容较多,我在这里就不再对其用法及原理进行描述了,想要了解的请参考 你真的会用Gson吗?Gson使用指南(四)
直接看代码
JsonBox.class
public abstract class JsonBox {
abstract public void fromJson(JsonObject jo, JsonDeserializationContext context);
protected <T> void filling(List<T> toMany, Class<T> type, JsonElement jsonElement, JsonDeserializationContext context) {
if (toMany == null)
return;
toMany.clear();
if (jsonElement.isJsonArray()) {
JsonArray array = jsonElement.getAsJsonArray();
for (int i = 0; i < array.size(); i++) {
JsonElement element = array.get(i);
T item = context.deserialize(element, type);
toMany.add(item);
}
}
}
protected <T extends JsonBox> void filling(ToOne<T> toOne, Type typeOfT, JsonElement jsonElement, JsonDeserializationContext context) {
if (toOne == null)
return;
try {
T one = ((Class<T>) typeOfT).newInstance();
one.fromJson(jsonElement.getAsJsonObject(), context);
toOne.setTarget(one);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
继承并实现JsonBox.class
在有ToMany
或ToOne
类型属性的POPO中调用filling()
方法为其填充数据
class Entity extends JsonBox {
private String name;
private String value;
private List<Target> targets;//ToMany
@Override
public void fromJson(JsonObject jo, JsonDeserializationContext context) {
filling(targets, Target.class, jo.get("targets"), context);
}
//省略geter setter
}
class Target extends JsonBox {
private String name;
private String value;
private ToOne<Entity> entity;
@Override
public void fromJson(JsonObject jo, JsonDeserializationContext context) {
filling(entity, Entity.class, jo.get("entity"), context);
}
//省略geter setter
}
ToOneSerializer.class
用于序列化时处理ToOne
对象
由于ToMany
不会对序列化产生任何影响,我们只需要处理遇到ToOne
的情况,如下:
public class ToOneSerializer implements JsonSerializer<ToOne> {
@Override
public JsonElement serialize(ToOne src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src.getTarget());
}
}
JsonBoxDeserializer.class
用于反序列化时处理ToMany
和ToOne
对象
public class JsonBoxDeserializer<T extends JsonBox> implements JsonDeserializer<T> {
@Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
T var = ((Class<T>) typeOfT).newInstance();
var.fromJson(json.getAsJsonObject(), context);
return var;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
}
最终通过将两个TypeAdapter
注册到Gson
并build
一个Gson
实例并调用
Gson gson=new GsonBuilder()
.registerTypeHierarchyAdapter(JsonBox.class, new JsonBoxDeserializer<>())
.registerTypeAdapter(ToOne.class, new ToOneSerializer())
.create();
public void toJson(){
String json=gson.toJson(new Entity());
}
public void fromJson(){
Entity entity=gson.fromJson(json,Entity.class);
}
搞定!