com.google.gson.internal.LinkedTreeMap不能转换为我的类

我从一个JSON字符串中获取我的对象有一些问题。

我有类Product

 public class Product { private String mBarcode; private String mName; private String mPrice; public Product(String barcode, String name, String price) { mBarcode = barcode; mName = name; mPrice = price; } public int getBarcode() { return Integer.parseInt(mBarcode); } public String getName() { return mName; } public double getPrice() { return Double.parseDouble(mPrice); } } 

在我的服务器上,我得到了一个JSON字符串表示forms的ArrayList 。 例如:

 [{"mBarcode":"123","mName":"Apfel","mPrice":"2.7"}, {"mBarcode":"456","mName":"Pfirsich","mPrice":"1.1111"}, {"mBarcode":"89325982","mName":"Birne","mPrice":"1.5555"}] 

这个字符串是这样生成的:

 public static  String arrayToString(ArrayList list) { Gson g = new Gson(); return g.toJson(list); } 

为了得到我的对象,我使用这个函数:

 public static  ArrayList stringToArray(String s) { Gson g = new Gson(); Type listType = new TypeToken<ArrayList>(){}.getType(); ArrayList list = g.fromJson(s, listType); return list; } 

但是打电话时

 String name = Util.stringToArray(message).get(i).getName(); 

我得到的错误com.google.gson.internal.LinkedTreeMap不能转换为object.Product

我究竟做错了什么? 它看起来像它创建LinkedTreeMaps列表,但我如何转换成我的产品对象?

在我看来,由于types擦除,分析器不能在运行时获取真正的typesT. 一种解决方法是将类types作为参数提供给方法。

像这样的工作,肯定还有其他可能的解决方法,但我觉得这一个非常清晰和简洁。

 public static  List stringToArray(String s, Class clazz) { T[] arr = new Gson().fromJson(s, clazz); return Arrays.asList(arr); //or return Arrays.asList(new Gson().fromJson(s, clazz)); for a one-liner } 

并称之为:

 String name = stringToArray(message, Product[].class).get(0).getName(); 

我也有与GSON投诉投诉LinkedTreeMaps的问题。

Alexis提供的答案和Aljoscha的评论解释了错误发生的原因。 “types上的generics通常在运行时被删除。” 我的问题是我的代码在正常运行时工作正常,但是使用ProGuard会导致代码被剥离,这对于投射非常重要。

你可以按照亚历克西斯的答案,更清楚地定义演员,这应该解决问题。 您还可以添加Google提供的ProGuard 规则 (只需执行此操作即可解决问题)。

 ##---------------Begin: proguard configuration for Gson ---------- # Gson uses generic type information stored in a class file when working with fields. Proguard # removes such information by default, so configure it to keep all of it. -keepattributes Signature # For using GSON @Expose annotation -keepattributes *Annotation* # Gson specific classes -keep class sun.misc.Unsafe { *; } #-keep class com.google.gson.stream.** { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.google.gson.examples.android.model.** { *; } ##---------------End: proguard configuration for Gson ---------- 

道德故事:总是检查一下你需要什么ProGuard规则。

我也只面对我的签名版本的类转换com.google.gson.internal.LinkedTreeMapexception。 我在progurard中添加了这些行。 然后它工作正常。

-keepattributes签名

-keepattributes 注释

保持类com.google。** {*; }

维护类sun.misc。** {*; }

为了增加已经在这里提到的答案,如果你有一个处理HTTP调用的generics类,那么传递Class作为构造函数的一部分可能是有用的。

为了给出更多的细节,发生这种情况是因为Java不能在运行时用T推导出Class 。 它需要实际的固体类来做出决定。

所以,如果你有这样的事情,就像我一样:

 class HttpEndpoint implements IEndpoint 

你可以允许inheritance代码也发送class ,因为在那一点上T是清楚的。

 public HttpEndpoint(String baseurl, String route, Class cls) { this.baseurl = baseurl; this.route = route; this.cls = cls; } 

inheritance类:

 public class Players extends HttpEndpoint { public Players() { super("http://127.0.0.1:8080", "/players", Player.class); } } 

虽然不是一个干净的解决方案,但它确实保持了代码的打包,并且不必在方法之间使用Class

类似于Alexis C的回答。 但在Kotlin。
只要将类的types传递给函数,并明确哪个generics是。
这里是简单的例子。

 inline fun  parseArray(json: String, typeToken: Type): T { val gson = GsonBuilder().create() return gson.fromJson(json, typeToken) } 

这里是示例调用

 fun test() { val json: String = "......." val type = object : TypeToken>() {}.type val result: List = parseArray>(json = json, typeToken = type) println(result) } 
 {"root": [ {"mBarcode":"123","mName":"Apfel","mPrice":"2.7"}, {"mBarcode":"456","mName":"Pfirsich","mPrice":"1.1111"}, {"mBarcode":"89325982","mName":"Birne","mPrice":"1.5555"} ] } JsonObject root = g.fromJson(json, JsonObject.class); //read root element which contains list JsonElement e = root.get("root"); //as the element is array convert it JsonArray ja = e.getAsJsonArray(); for(JsonElement j : ja){ //here use the json to parse into your custom object }