Ben*_*ynn 34 java json interface gson
我从未对序列化做过多少工作,但我尝试使用Google的gson将Java对象序列化为文件.这是我的问题的一个例子:
public interface Animal {
public String getName();
}
public class Cat implements Animal {
private String mName = "Cat";
private String mHabbit = "Playing with yarn";
public String getName() {
return mName;
}
public void setName(String pName) {
mName = pName;
}
public String getHabbit() {
return mHabbit;
}
public void setHabbit(String pHabbit) {
mHabbit = pHabbit;
}
}
public class Exhibit {
private String mDescription;
private Animal mAnimal;
public Exhibit() {
mDescription = "This is a public exhibit.";
}
public String getDescription() {
return mDescription;
}
public void setDescription(String pDescription) {
mDescription = pDescription;
}
public Animal getAnimal() {
return mAnimal;
}
public void setAnimal(Animal pAnimal) {
mAnimal = pAnimal;
}
}
public class GsonTest {
public static void main(String[] argv) {
Exhibit exhibit = new Exhibit();
exhibit.setAnimal(new Cat());
Gson gson = new Gson();
String jsonString = gson.toJson(exhibit);
System.out.println(jsonString);
Exhibit deserializedExhibit = gson.fromJson(jsonString, Exhibit.class);
System.out.println(deserializedExhibit);
}
}
Run Code Online (Sandbox Code Playgroud)
所以这很好地序列化 - 但可以理解的是删除了Animal上的类型信息:
{"mDescription":"This is a public exhibit.","mAnimal":{"mName":"Cat","mHabbit":"Playing with yarn"}}
Run Code Online (Sandbox Code Playgroud)
但这会导致反序列化的真正问题:
Exception in thread "main" java.lang.RuntimeException: No-args constructor for interface com.atg.lp.gson.Animal does not exist. Register an InstanceCreator with Gson for this type to fix this problem.
Run Code Online (Sandbox Code Playgroud)
我知道为什么会发生这种情况,但是我很难找到解决这个问题的正确模式.我确实看过指南,但没有直接解决这个问题.
nar*_*thi 82
这是一个通用的解决方案,适用于只有静态知道接口的所有情况.
创建序列化器/反序列化器:
final class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
final JsonObject wrapper = new JsonObject();
wrapper.addProperty("type", object.getClass().getName());
wrapper.add("data", context.serialize(object));
return wrapper;
}
public T deserialize(JsonElement elem, Type interfaceType, JsonDeserializationContext context) throws JsonParseException {
final JsonObject wrapper = (JsonObject) elem;
final JsonElement typeName = get(wrapper, "type");
final JsonElement data = get(wrapper, "data");
final Type actualType = typeForName(typeName);
return context.deserialize(data, actualType);
}
private Type typeForName(final JsonElement typeElem) {
try {
return Class.forName(typeElem.getAsString());
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
private JsonElement get(final JsonObject wrapper, String memberName) {
final JsonElement elem = wrapper.get(memberName);
if (elem == null) throw new JsonParseException("no '" + memberName + "' member found in what was expected to be an interface wrapper");
return elem;
}
}
Run Code Online (Sandbox Code Playgroud)让Gson使用它作为您选择的接口类型:
Gson gson = new GsonBuilder().registerTypeAdapter(Animal.class, new InterfaceAdapter<Animal>())
.create();
Run Code Online (Sandbox Code Playgroud)