使用Gson反序列化接口?

9

我正在尝试使用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进行反序列化?
谢谢。
3个回答

8

1
嗨,Bruce,我想我已经了解了情况,看起来gson目前还不支持多态反序列化。我在你的网站上看到你有一些jackson示例(其中包括多态性)。你建议现在使用jackson而不是gson吗?谢谢。 - user291701
2
是的,我建议使用Jackson而不是Gson,正如http://programmerbruce.blogspot.com/2011/07/gson-v-jackson-part-6.html中所概述的那样。 Jackson具有良好的多态内置支持,以及其他优点,例如显着更好的性能。 对于感兴趣的人,有关使用Jackson进行多态反序列化的帖子在http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html上。 - Programmer Bruce

5

简单来说,你不能用GSON做到这一点。

当我偶然发现Jackson时,我也遇到了同样的问题。 使用Jackson就非常容易:

ObjectMapper mapper = new ObjectMapper();  
mapper.enableDefaultTyping(); 

然后,您可以在不编写额外的自定义反序列化程序、注释或任何其他代码的情况下对Java对象和接口进行序列化和反序列化。

这不是问题的一部分,但如果您决定从Gson转换到Jackson,则可能会证明有用。 Gson默认支持私有字段,但对于Jackson,您必须在代码中包含此内容。

mapper.setVisibilityChecker(g.getVisibilityChecker().with(Visibility.ANY));

以下是在主函数中的代码样例实现:

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承诺将在未来版本中解决这个问题,但目前为止他们还没有解决。 如果这对你的应用非常重要,我建议你转到Jackson。


0

我已经通过编译Groovy属性类来与GWT Autobeans模型进行交互的方式构建了一个原始接口Shim生成器。这是一种非常粗糙的方法,可以暂时避开ASM/cglib的学习曲线。背景:使用Autobeans时,您只能使用接口,而sun.*代理无法进行gson互操作,因为我尝试过所有访问尝试。但是,当Groovy类加载器对于GsonBuilder是本地的时候,事情会变得稍微容易一些。请注意,除非实际从Groovy本身调用gsonBuilder注册,否则此操作将失败。

要访问Shim工厂,请将其创建为名为JSON_SHIM的单例并调用

JSON_SHIM.getShim("{}",MyInterface.class)

如有需要,请注册并创建[空白]实例。如果您的接口中有接口,则必须提前注册这些接口以供使用。这仅是足够使用gson的平面Autobean所需的魔法,而不是整个框架。 此生成器中没有Groovy代码,因此具有javassist技巧的人可以重复实验。

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;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接