2011-03-20 46 views
26

我正在嘗試創建一個通用類,以便與Google Gson一起使用。我創建了類GsonJsonConverterImplementation<T>。這個類有以下方法:在Gson中使用通用類型

public T deserialize(String jsonString) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 

    Gson gson = builder.create(); 
    return gson.fromJson(jsonString, T); // T.class etc. what goes here 
} 

的目標是,這種方法應該能夠一起工作任何類型的我已下定GsonJsonConverterImplementation的工作。不幸的是,gson.fromJson(jsonString, T)不起作用,也沒有使用T.class來代替T.我確信這個問題源於我對Java通用類型的理解不夠。與Gson一起使用泛型的正確方法是什麼?

編輯
使用Kris's answer我會認爲這應該工作。不幸的是,clazz不能以這種方式使用,並導致編譯器錯誤。與Gson一起使用集合和泛型類型有什麼選擇?

public List<T> deserializeList(String jsonString, Class<T> clazz) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 
    Gson gson = builder.create(); 

    Type listType = new TypeToken<clazz>(){}.getType(); // compiler error 

    return gson.fromJson(jsonString, listType); 
} 
+2

我不知道你是否可以使這個(名單 - 是好吧)與Gson一起工作,因爲TypeToken本質上仍然是一個靜態的c onstruct(這就是爲什麼你的代碼無法工作)。但是如果你不一定要使用Gson,Jackson確實支持類型的編程創建(通過TypeFactory方法),並允許你試圖實現的內容。 – StaxMan 2011-03-22 19:26:59

+0

Duplicate question:http://stackoverflow.com/questions/4226738/using-generics-with-gson?rq=1 – 2013-02-23 05:12:43

回答

36

對於您嘗試的最簡單的方法是定義要在方法簽名本身中返回的類的類型。您可以通過將'T'的實例傳遞給方法或要返回的值的Class來實現。第二種方法在希望產生返回值的情況下更爲典型。下面是一個使用GSON這種方法的一個例子:

public <T> T deserialize(String jsonString, Class<T> clazz) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 

    Gson gson = builder.create(); 
    return gson.fromJson(jsonString, clazz); 
} 

用法:

MyClass mc = deserialize(jsonString, MyClass.class); 
+1

克里斯,雖然這個工程,有什麼點設置generica鍵入爲類?對我來說,'GsonJsonConverterImplementation '應該就夠了。我錯過了什麼? – ahsteele 2011-03-20 19:50:14

+1

在我的例子中,除非你在其他地方使用它,否則不會有任何意義。這是泛型的問題之一,也是你看到使用我所展示的方法初始化實例而不是在類級別配置泛型類型的框架的主要原因。在大多數情況下,您無法檢索並使用在類級別定義的實際泛型類型。因此,您無法使用它來創建新實例或執行需要Class實例的任何其他操作。 – 2011-03-20 20:22:34

+1

作爲後續工作,如果您有具有Generic類型的類的子類,那麼有辦法檢索該類型,但是,該方法也存在問題。下面是一個基本的例子(如通過父類與Generic類實現的)在這種情況下如何檢索類實例:(Class)((ParameterizedType)this.getClass()。 getGenericSuperclass())。getActualTypeArguments()[ 0] – 2011-03-20 20:24:33

5

要獲得List<T>運行時類型,如果給定類的T,它會吸,因爲JDK沒想到我們需要它,所以沒有支持。你可以子類ParameterizedType,但它真的很爛。

Type typeListT = new ParameterizedType() 
    { 
     public Type[] getActualTypeArguments() 
     { 
      return new Type[]{clazz}; 
     } 
     public Type getRawType() 
     { 
      return List.class; 
     } 
     public Type getOwnerType() 
     { 
      return null; 
     } 
     public boolean equals(Object obj) 
     { 
      // must implement equals per spec. this sucks 
     } 
     public int hashCode() 
     { 
      // this blows! Java forgot to specific it! 
      // since we override equals, we should override hashCode 
      // we have no idea what value should be returned here! 
      // note we are co-existing with other ParameterizedType impls 
     } 
    }; 
+3

這是一個不好的答案,或許不是誇大API的缺點,您可以關注技術細節。就目前而言,我甚至都沒有從你發佈的內容中看到如何使用該技術。 – 2014-03-17 22:57:38

1

我使用這些方法來讀取使用GSON &寫對象。

public static <T> void saveAnyTypeOfObject(String key, T value){ 
     Gson gson = new Gson(); 
     String json = gson.toJson(value); 
     SharedPref.save(key, json); 
    } 
    //Type listType = new TypeToken<YourClass>(){}.getType(); 
    public static <T> T readAnyTypeOfObject(String key, Type tt) { 
     Gson gson = new Gson(); 
     String json = SharedPref.read(key, "{}"); 
     T obj = gson.fromJson(json, tt); 
     return obj; 
    } 

看它像

TypeToken<YourClassName> typeToken= new TypeToken<YourClassName>() {}; 
    YourClassName yourClassName = ListSharedPref.readAnyTypeOfObject("keyForSavingClass", typeToken.getType()); 

並保存它像

YourClassName yourClassName = gson.fromJson(objJsonObject.toString(),YourClassName.class);    
ListSharedPref.saveAnyTypeOfObject("keyForSavingClass",yourClassName);