2010-11-19 42 views
21

我使用GSON將JSON解碼爲類型T的對象,例如在GSON中使用泛型

public T decode(String json) { 
    Gson gson = new Gson(); 
    return gson.fromJson(json, new TypeToken<T>() {}.getType()); 
} 

然而,這會返回一個例外 -

java.lang.AssertionError:意外的類型。 預期之一: java.lang.reflect.ParameterizedType, java.lang.reflect.GenericArrayType, 但得到:sun.reflect.generics.reflectiveObjects.TypeVariableImpl,對於令牌類型:T

我認爲,通過使用TypeToken我避免了Type Erasure。

我錯了嗎?

感謝

+0

重複的問題:http://stackoverflow.com/questions/5370768/using-a-generic-type-with-gson – 2013-02-23 05:13:05

回答

14

首先,我看不出包GSON一樣,它是如何的有用。

至於你的問題,關於通用類型T本身的信息在運行時不可用。它已被刪除。它僅在編譯期間可用。您想用實際類型將其參數化,而不是像new TypeToken<List<String>>。如您所見,由於缺乏Java中的泛化泛型(不可能執行T t = new T()),Gson本身被迫使用TypeToken方法。否則,Gson會以更加優雅的方式做到這一點。

爲了能夠傳遞實際的類型,您必須重新創建與TypeToken已經在做的相同的事情。這是沒有意義的:)只是重用它,或者直接使用Gson,而不用像這樣的幫助類中包裝它。

+1

我從使用它的機制中分離出GSON的實際使用。我有一個方法解碼的ObjectDecoder接口(String json)。這意味着我可以在不同的實現之間切換, GSON,Jackson等。然後,我使用Guice將依賴注入到機制中。 – christophmccann 2010-11-19 17:03:49

+3

最好的辦法是重用Gson的'TypeToken'作爲類或方法參數,或者至少重新創建它,如果你不想在你的API中公開第三方依賴。 [它由Apache許可證開放源代碼](http://code.google.com/p/google-gson/source/browse/trunk/src/main/java/com/google/gson/reflect/TypeToken.java?spec = svn2&R = 2)。 [此處的後臺說明](http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener)。 – BalusC 2010-11-19 17:04:54

5

我覺得第一個答案是沒有指出實際的解決方案:你還必須通過Class實例和T一起,就像這樣:

public T decode(String json, Class<T> cls) { 
    Gson gson = new Gson(); 
    return gson.fromJson(json, cls); 
} 

這是因爲「T」在這裏是一種變量,而不是一個類型引用;並且只能由編譯器用於添加隱式轉換並驗證類型兼容性。但是如果你通過實際的課程可以使用它;編譯器會檢查類型兼容性以減少不匹配的可能性。

另外,你可以採取TypeToken並通過它;但是TypeToken必須用實型構造,而不是類型變量;類型變量在這裏沒什麼用處。但是如果你想要包裝你不想調用者使用TypeToken(這是一個Gson類型)。

同樣的包裝機制可以和其他庫一樣,比如你提到的傑克遜。

+4

對於這個問題全是關於參數化的類,這不起作用。沒有像Map .class'這樣的東西,只有'Map.class'。另請參閱我的答案中評論中的「背景說明」鏈接。 – BalusC 2011-01-04 18:45:56

+0

是的,我完全意識到這個問題,只是這個問題並沒有表明它是一個參數化類,所以這個簡單的答案似乎就足夠了。很遺憾JDK沒有類型標記(類型引用等等;每個lib /框架必須定義它自己)。 – StaxMan 2011-01-04 18:49:07

0

我對這個解決方案是使用JSON解析器和它打破成碎片

public static <TT> PushObj<TT> fromJSON(String json, Class<TT> classType) 
{ 
    JsonObject jObj = new JsonParser().parse(json).getAsJsonObject(); 
    String type = jObj.get("type").getAsString(); 
    JsonObject job = jObj.get("object").getAsJsonObject(); 
    TT obj = new Gson().fromJson(job, classType); 
    return new PushObj<TT>(type, obj); 
} 

凡客體結構爲: {字符串:類型,泛型:對象}

而且變量: jObj是在 中傳遞的字符串的JSONObject,作業是通用對象的JSONObject

因此,我使用json解析器分別獲取類型和反射目的。