2016-05-12 78 views
0

我无法完全理解反射如何工作,所以我在尝试为我的GsonBuilder注册自定义类型适配器时遇到了一些麻烦。获取通用类型的参数化类型

我需要为List<Something>类型注册一个类型适配器。

这是一个工作代码:

gsonBuilder.registerTypeAdapter(
      new TypeToken<List<MyClass>>() { }.getType(), new ListDeserializer(MyClass.class) 
    ); 

的事情是,我有很多的类注册我的类型的适配器,和我有一个ListDeserializerSingleDeserializer适配器。

我想去通用,所以我只是调用一个函数,通过我的GsonBuilder和类,然后你去。

这里是我的尝试:

private static <T> void registerTypeAdapter(GsonBuilder gsonBuilder, T clazz) { 
    gsonBuilder.registerTypeAdapter(clazz.getClass(), new SingleDeserializer(clazz.getClass())); 
    gsonBuilder.registerTypeAdapter(
      new TypeToken<List<T>>() { 
      }.getType(), new ListDeserializer(clazz.getClass()) 
    ); 
} 

它不适合我的工作ListDeserializer。我的猜测是,由于TList的通用参数化类型,因此无法在运行时检测到它。

有什么建议吗?

回答

1

是的,你不能在运行时使用new TypeToken<List<T>>() {}.getType(),因为泛型type erasure。在运行时,List<T>只是List<Object>。但是你可以做的是创造ParameterizedType和使用这样的:

Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz.getClass()}, null); 
gsonBuilder.registerTypeAdapter(type, new ListDeserializer(clazz.getClass())); 

但你真的需要这种通用?你可以做

private static void registerTypeAdapter2(GsonBuilder gsonBuilder, Class<?> clazz) { 
    gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer()); 
    Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null); 
    gsonBuilder.registerTypeAdapter(type, new ListDeserializer()); 
} 

这里是演示:

import com.google.gson.*; 
import com.google.gson.annotations.SerializedName; 
import com.google.gson.reflect.TypeToken; 
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; 

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.ArrayList; 
import java.util.List; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     GsonBuilder gb = new GsonBuilder(); 
     registerTypeAdapter(gb, MyClass.class); 

     Gson gson = gb.create(); 
     List data = new ArrayList<>(); 
     data.add(new MyClass("Bob")); 
     data.add(new MyClass("Alice")); 

     String listString = gson.toJson(data); 
     String soloString = gson.toJson(new MyClass("Test")); 

     Object resultList = gson.fromJson(listString, new TypeToken<List<MyClass>>() {}.getType()); 
     Object resultSolo = gson.fromJson(soloString, MyClass.class); 

     System.out.println("RESULT:"); 
     System.out.println("FROM " + listString +" TO "+ resultList); 
     System.out.println("FROM " + soloString +" TO "+ resultSolo); 

    } 

    private static void registerTypeAdapter(GsonBuilder gsonBuilder, Class<?> clazz) { 
     gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer()); 
     Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null); 
     gsonBuilder.registerTypeAdapter(type, new ListDeserializer()); 
    } 

    private static class ListDeserializer implements JsonDeserializer { 
     private static Gson gson = new Gson(); 

     @Override 
     public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
      System.out.println("Used ListDeserializer: Type " + typeOfT); 

      Type t = (typeOfT instanceof ParameterizedType) ? 
        ((ParameterizedType) typeOfT).getActualTypeArguments()[0] : 
        Object.class; 

      Type type = ParameterizedTypeImpl.make(List.class, new Type[]{t}, null); 
      List list = gson.fromJson(json, type); 
      return list; 
     } 
    } 

    private static class SingleDeserializer implements JsonDeserializer { 
     private static Gson gson = new Gson(); 

     @Override 
     public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
      System.out.println("Used SingleDeserializer: Type " + typeOfT); 
      return gson.fromJson(json, typeOfT); 
     } 
    } 

    public static class MyClass { 
     @SerializedName("name") 
     private String name; 

     public MyClass(String name) { 
      this.name = name; 
     } 

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 

     @Override 
     public String toString() { 
      return "MyClass{" + 
        "name='" + name + '\'' + 
        '}'; 
     } 
    } 
} 
+0

这是真棒@varren!谢谢! –