使用Gson 2.2.2,我尝试序列化POJO(行为)的数组列表。
我有一个适配器,它几乎是我在网上看到的东西的副本:
public class BehaviorAdapter implements JsonSerializer<Behavior> {
private static final String CLASSNAME = "CLASSNAME";
private static final String INSTANCE = "INSTANCE";
@Override
public JsonElement serialize(Behavior src, Type typeOfSrc,
JsonSerializationContext context) {
JsonObject retValue = new JsonObject();
String className = src.getClass().getCanonicalName();
retValue.addProperty(CLASSNAME, className);
JsonElement elem = context.serialize(src);
retValue.add(INSTANCE, elem);
return retValue;
}
}我像这样注册它:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeHierarchyAdapter(Behavior.class, new BehaviorAdapter());
gson = builder.create();然后当我尝试序列化我的ArrayList时:
String json2 = gson.toJson(behaviors);我得到一个堆栈溢出。
看起来是这样的:
JsonElement elem = context.serialize(src);它开始一个递归循环,一次又一次地通过我的序列化程序。那么我如何注册它才不会发生这种情况呢?我需要序列化列表并维护多态。
发布于 2012-11-06 15:24:18
看起来你找到了无限循环the JsonSerializer docs warn about
然而,你永远不应该在src对象本身调用它,因为那会导致无限循环(Gson会再次调用你的回调方法)。
我能想到的最简单的方法是创建一个没有安装处理程序的新Gson实例,然后运行您的实例。
作为结束运行,您可以只序列化List<Behavior>:
public class BehaviorListAdapter implements JsonSerializer<List<Behavior>> {
private static final String CLASSNAME = "CLASSNAME";
private static final String INSTANCE = "INSTANCE";
@Override
public JsonElement serialize(List<Behavior> src, Type typeOfSrc,
JsonSerializationContext context) {
JsonArray array = new JsonArray();
for (Behavior behavior : src) {
JsonObject behaviorJson = new JsonObject();
String className = behavior.getClass().getCanonicalName();
behaviorJson.addProperty(CLASSNAME, className);
JsonElement elem = context.serialize(behavior);
behaviorJson.add(INSTANCE, elem);
array.add(behaviorJson);
}
return array;
}
}
GsonBuilder builder = new GsonBuilder();
// use a TypeToken to make a Type instance for a parameterized type
builder.registerTypeAdapter(
(new TypeToken<List<Behavior>>() {}).getType(),
new BehaviorListAdapter());
gson = builder.create();发布于 2012-11-06 15:11:15
看看RuntimeTypeAdapterFactory吧。该类的test有一个示例:
RuntimeTypeAdapterFactory<BillingInstrument> rta = RuntimeTypeAdapterFactory.of(
BillingInstrument.class)
.registerSubtype(CreditCard.class);
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(rta)
.create();
CreditCard original = new CreditCard("Jesse", 234);
assertEquals("{\"type\":\"CreditCard\",\"cvv\":234,\"ownerName\":\"Jesse\"}",
gson.toJson(original, BillingInstrument.class));
BillingInstrument deserialized = gson.fromJson(
"{type:'CreditCard',cvv:234,ownerName:'Jesse'}", BillingInstrument.class);
assertEquals("Jesse", deserialized.ownerName);
assertTrue(deserialized instanceof CreditCard);这个类不在核心Gson中;您需要将它复制到您的项目中才能使用它。
发布于 2017-06-16 19:19:57
我知道你想在这里做什么,我也有同样的问题。
我写完了一个简单的抽象类。
public abstract class TypedJsonizable extends Jsonizable {}并将TypeHierarchyAdapter注册到我的Gson实例
protected static Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter
(TypedJsonizable.class,new TypedJsonizableSerializer());这个TypeAdapter的关键不是调用context.serialize和context.deserialize,因为这会导致一个无限循环,正如Jeff Bowman在他的回答中所说的,这个TypeAdapter使用反射来避免这种情况。
import com.google.gson.*;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
public class TypedJsonizableSerializer implements JsonSerializer<TypedJsonizable>, JsonDeserializer<TypedJsonizable> {
static final String CLASSNAME_FIELD = "_className";
Logger logger = Logger.getLogger(TypedJsonizable.class);
@Override
public JsonElement serialize(TypedJsonizable src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject contentObj = new JsonObject();
contentObj.addProperty(CLASSNAME_FIELD,src.getClass().getCanonicalName());
for (Field field : src.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
if (field.get(src)!=null)
contentObj.add(field.getName(),context.serialize(field.get(src)));
} catch (IllegalAccessException e) {
logger.error(e.getMessage(),e);
}
}
return contentObj;
}
@Override
public TypedJsonizable deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String className = jsonObject.get(CLASSNAME_FIELD).getAsString();
if (className == null || className.isEmpty())
throw new JsonParseException("Cannot find _className field. Probably this instance has not been serialized using Jsonizable jsonizer");
try {
Class<?> clazz = Class.forName(className);
Class<?> realClazz = (Class<?>) typeOfT;
if (!realClazz.equals(clazz))
throw new JsonParseException(String.format("Cannot serialize object of class %s to %s", clazz.getCanonicalName(),realClazz.getCanonicalName()));
Object o = clazz.getConstructor().newInstance();
for (Field field : o.getClass().getDeclaredFields()) {
field.setAccessible(true);
if (jsonObject.has(field.getName())) {
field.set(o,context.deserialize(jsonObject.get(field.getName()) , field.getGenericType()));
}
}
return (TypedJsonizable) o;
} catch (ClassNotFoundException e) {
throw new JsonParseException(String.format("Cannot find class with name %s . Maybe the class has been refactored or sender and receiver are not using the same jars",className));
} catch (IllegalAccessException e){
throw new JsonParseException(String.format("Cannot deserialize, got illegalAccessException %s ",e.getMessage()));
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException e) {
throw new JsonParseException(String.format("Cannot deserialize object of class %s, unable to create a new instance invoking empty constructor",className));
}
}}
https://stackoverflow.com/questions/13244769
复制相似问题