2012-06-27 41 views
9

Tôi đang cố gắng sử dụng Gson với một giao diện:Deserializing một giao diện bằng 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); 

Kể từ khi lớp Wrapper có một biến thành viên đó là loại hình ảnh, làm thế nào để tôi đi về deserializing nó bằng cách sử Gson?

Cảm ơn

Trả lời

8

Yêu cầu deserialization là cần thiết.

Tùy thuộc vào vấn đề lớn hơn cần giải quyết, hoặc sử dụng ["bộ điều hợp loại"] 1 hoặc "type hierarchy adapter". Bộ điều hợp phân cấp loại "is to cover the case when you want the same representation for all subtypes of a type".

+1

Xin chào Bruce, vì vậy tôi nghĩ rằng tôi bị cuốn theo những gì, có vẻ như gson không hỗ trợ deserialization đa hình. Tôi đã nhìn thấy trên trang web của bạn rằng bạn có một số ví dụ jackson (trong đó bao gồm đa hình). Bạn có khuyên bạn nên sử dụng jackson trên gson vào thời điểm này? Cảm ơn – user291701

+2

Có, tôi khuyên bạn nên sử dụng Jackson trên Gson, như được nêu trong http://programmerbruce.blogspot.com/2011/07/gson-v-jackson-part-6.html. Jackson có hỗ trợ tích hợp sẵn cho tính đa hình, cũng như các ưu điểm khác, chẳng hạn như hiệu năng tốt hơn đáng kể. Đối với những người quan tâm, bài đăng trên deserialization đa hình với Jackson là tại http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html –

3

Nói một cách đơn giản, bạn không thể làm điều đó với GSON.

Tôi gặp rắc rối bởi cùng một vấn đề khi tôi tình cờ gặp Jackson. Với nó nó là rất dễ dàng:

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

Và sau đó bạn có thể đi về de/serializing đối tượng Java và giao diện của bạn mà không cần phải viết thêm tùy chỉnh de/serializers, annotaions và thực sự không có mã bổ sung nào.

Đây không phải là một phần của câu hỏi, nhưng có thể hữu ích nếu bạn quyết định chuyển từ Gson sang Jackson. Gson hỗ trợ các trường riêng theo mặc định nhưng đối với Jackson, bạn phải bao gồm trường này trong mã của mình.

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

thực hiện mẫu cho mã của bạn trong chính:

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 hứa họ sẽ làm việc về vấn đề này trong các phiên bản tương lai, nhưng họ đã không được giải quyết nó cho đến nay. Nếu điều này là rất quan trọng đối với ứng dụng của bạn, tôi sẽ đề nghị bạn chuyển đến Jackson.

+0

liên kết của bạn bị thiếu – ronalchn

0

Tôi đã tạo một trình tạo shim giao diện nguyên thủy bằng cách biên dịch một lớp thuộc tính groovy để tương thích với mô hình GWT Autobeans. đây là một phương pháp thực sự thô bạo để bỏ qua đường cong học tập ASM/cglib hiện tại. nền tảng về điều này: với Autobeans, bạn chỉ có thể sử dụng giao diện và mặt trời. * proxy không có khả năng tương tác gson cho mọi nỗ lực truy cập mà tôi đã thử nghiệm. NHƯNG, khi trình nạp lớp groovy là cục bộ cho GsonBuilder, mọi thứ trở nên dễ dàng hơn một chút. lưu ý, điều này không thành công trừ khi đăng ký gsonBuilder thực sự được gọi từ bên trong bản thân groovy.

để truy cập máy shim tạo như một tên singleton JSON_SHIM và gọi

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

đăng ký nếu cần thiết và tạo ra một [trống] dụ. nếu bạn có giao diện trong giao diện của mình, bạn phải đăng ký trước những giao diện quá trước khi sử dụng. đây chỉ là đủ ma thuật để sử dụng phẳng Tự động với gson, không phải toàn bộ khuôn khổ. không có mã groovy trong trình tạo này, vì vậy ai đó có javassist-foo có thể lặp lại thử nghiệm.

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; 
    } 
} 
Các vấn đề liên quan