我正在尝试使用Gson接口:
public interface Photo {
public int getWidth();
}
public class DinosaurPhoto implements Photo {
...
}
public class Wrapper {
private Photo mPhoto; // <- problematic
}
...
Wrapper wrapper = new Wrapper();
wrapper.setPhoto(new DinosaurPhoto());
Gson gson = new Gson();
String raw = gson.toJson(wrapper);
// Throws an error since "Photo" can't be deserialized as expected.
Wrapper deserialized = gson.fromJson(raw, Wrapper.class);
由于Wrapper类有一个类型为Photo的成员变量,我该如何使用Gson对其进行反序列化?
谢谢
答案 0 :(得分:8)
自定义反序列化是必要的。
根据要解决的较大问题,应使用 [“type adapter”] 1或"type hierarchy adapter"。类型层次结构适配器"is to cover the case when you want the same representation for all subtypes of a type"。
答案 1 :(得分:4)
简单地说,你不能用GSON做到这一点。
当我偶然发现Jackson时,我对同样的问题感到困扰。 有了它,这很容易:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
然后你就可以进行de / serializing你的Java对象和接口,而无需编写额外的自定义de / serializers,注释,也没有添加任何代码。
这不是问题的一部分,但如果您决定从Gson移植到杰克逊,可能会有用。 Gson默认支持私有字段,但对于Jackson,你必须在代码中包含它。
mapper.setVisibilityChecker(g.getVisibilityChecker().with(Visibility.ANY));
main中代码的示例实现:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.setVisibilityChecker(g.getVisibilityChecker().with(Visibility.ANY));
Wrapper wrapper = new Wrapper();
wrapper.setPhoto(new DinosaurPhoto());
String wrapper_json = mapper.writeValueAsString(wrapper);
Wrapper wrapper_from_json = mapper.readValue(wrapper_json,Wrapper.class);
Gson承诺他们将在未来版本中解决这个问题,但到目前为止他们还没有解决。 如果这对你的申请非常重要,我会建议你移植到杰克逊。
答案 2 :(得分:0)
我已经构建了一个原始接口填充生成器,它通过编译groovy属性类来与GWT Autobeans模型进行互操作。这是一个非常粗略的方法,现在回避ASM / cglib学习曲线。关于这一点的背景:使用Autobeans,你可能只使用接口,而sun。*代理对我尝试过的所有访问尝试都没有gson interop。但是,当groovy类加载器是GsonBuilder的本地时,事情会变得更容易一些。请注意,除非实际上从groovy本身调用gsonBuilder注册,否则会失败。
访问shim工厂创建一个单独的名称JSON_SHIM并调用
JSON_SHIM.getShim( “{}”,MyInterface.class)
如果需要注册并创建一个[空白]实例。如果接口中有接口,则必须在使用前预先注册这些接口。这对于使用 flat Autobeans与gson而不是整个框架来说是足够神奇的。 这个生成器中没有groovy代码,所以有javassist-foo的人可以重复实验。
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
import groovy.lang.GroovyClassLoader;
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
public class GroovyGsonShimFactory {
private Map<Class, Method> shimMethods = new LinkedHashMap<>();
private void generateGroovyProxy(Class ifaceClass) {
String shimClassName = ifaceClass.getSimpleName() + "$Proxy";
String ifaceClassCanonicalName = ifaceClass.getCanonicalName();
String s = "import com.google.gson.*;\n" +
"import org.apache.commons.beanutils.BeanUtils;\n" +
"import java.lang.reflect.*;\n" +
"import java.util.*;\n\n" +
"public class "+shimClassName+" implements "+ifaceClassCanonicalName+" {\n" ;
{
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(ifaceClass);
for (PropertyDescriptor p : propertyDescriptors) {
String name = p.getName();
String tname = p.getPropertyType().getCanonicalName();
s += "public " + tname + " " + name + ";\n";
s += " " + p.getReadMethod().toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "") + "{return " + name + ";};\n";
Method writeMethod = p.getWriteMethod();
if (writeMethod != null)
s += " " + writeMethod.toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "").replace(")", " v){" + name + "=v;};") + "\n\n";
}
}
s+= " public static "+ifaceClassCanonicalName+" fromJson(String s) {\n" +
" return (" +ifaceClassCanonicalName+
")cydesign.strombolian.server.ddl.DefaultDriver.gson().fromJson(s, "+shimClassName+".class);\n" +
" }\n" +
" static public interface foo extends InstanceCreator<"+ifaceClassCanonicalName+">, JsonSerializer<"+ifaceClassCanonicalName+">, JsonDeserializer<"+ifaceClassCanonicalName+"> {}\n" +
" static {\n" +
" cydesign.strombolian.server.ddl.DefaultDriver.builder().registerTypeAdapter("+ifaceClassCanonicalName+".class, new foo() {\n" +
" public "+ifaceClassCanonicalName+" deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n" +
" return context.deserialize(json, "+shimClassName+".class);\n" +
" }\n" +
"\n" +
" public "+ifaceClassCanonicalName+" createInstance(java.lang.reflect.Type type) {\n" +
" try {\n" +
" return new "+shimClassName+"();\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace(); \n" +
" }\n" +
" return null;\n" +
" }\n" +
"\n" +
" @Override\n" +
" public JsonElement serialize("+ifaceClassCanonicalName+" src, Type typeOfSrc, JsonSerializationContext context) {\n" +
" LinkedHashMap linkedHashMap = new LinkedHashMap();\n" +
" try {\n" +
" BeanUtils.populate(src, linkedHashMap);\n" +
" return context.serialize(linkedHashMap);\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace(); \n" +
" }\n" +
"\n" +
" return null;\n" +
" }\n" +
" });\n" +
" }\n\n" +
"};";
System.err.println("" + s);
ClassLoader parent = DefaultDriver.class.getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
final Class gClass = loader.parseClass(s);
try {
Method shimMethod = gClass.getMethod("fromJson", String.class);
shimMethods.put(ifaceClass, shimMethod);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public <T> T getShim(String json, Class<T> ifaceClass) {
if (!shimMethods.containsKey(ifaceClass))
generateGroovyProxy(ifaceClass);
T shim = null;//= gson().shimMethods(json, CowSchema.class);
try {
shim = (T) shimMethods.get(ifaceClass).invoke(null, json);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return shim;
}
}