2016-05-12 77 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!謝謝! –