com.google.gson.internal.LinkedTreeMap无法投射到我的班级

Tan*_*aus 54 java json casting gson

从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);
    }
}    
Run Code Online (Sandbox Code Playgroud)

从我的服务器,我得到一个ArrayList<Product>JSON字符串表示.例如:

[{"mBarcode":"123","mName":"Apfel","mPrice":"2.7"},
{"mBarcode":"456","mName":"Pfirsich","mPrice":"1.1111"},
{"mBarcode":"89325982","mName":"Birne","mPrice":"1.5555"}] 
Run Code Online (Sandbox Code Playgroud)

此String生成如下:

public static <T> String arrayToString(ArrayList<T> list) {
    Gson g = new Gson();
    return g.toJson(list);
}
Run Code Online (Sandbox Code Playgroud)

为了让我的对象回来,我使用这个函数:

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

但是在打电话时

String name = Util.stringToArray(message).get(i).getName();
Run Code Online (Sandbox Code Playgroud)

我收到错误 com.google.gson.internal.LinkedTreeMap无法强制转换为object.Product

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

Ale*_* C. 85

在我看来,由于类型擦除,解析器无法在运行时获取实际类型T. 一种解决方法是将类类型作为参数提供给方法.

像这样的东西,肯定有其他可能的解决方法,但我发现这一个非常清晰和简洁.

public static <T> List<T> stringToArray(String s, Class<T[]> 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
}
Run Code Online (Sandbox Code Playgroud)

称之为:

String name = stringToArray(message, Product[].class).get(0).getName();
Run Code Online (Sandbox Code Playgroud)

  • 这个答案提供了一种解决方法,但没有解决嵌套泛型的问题。有关更通用的解决方案,请参阅这两个答案:http://stackoverflow.com/a/14506181/4745878 http://stackoverflow.com/a/26203635/4745878 (3认同)

wel*_*k91 15

我也有GSON抱怨有关CastTreeMaps的问题.

Alexis提供的答案和Aljoscha 的评论解释了错误发生的原因; "类型上的泛型通常在运行时被删除." 我的问题是我的代码在我正常运行时工作,但使用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  ----------
Run Code Online (Sandbox Code Playgroud)

故事的道德:始终检查您需要的ProGuard规则.


Joh*_*nny 7

类似于Alexis C的答案.但是在科特林.
只需将类类型传递给函数,并阐明泛型类型.
这是简化的例子.

inline fun <reified T> parseArray(json: String, typeToken: Type): T {
    val gson = GsonBuilder().create()
    return gson.fromJson<T>(json, typeToken)
}
Run Code Online (Sandbox Code Playgroud)

这是示例调用

fun test() {
    val json: String = "......."
    val type = object : TypeToken<List<MyObject>>() {}.type
    val result: List<MyObject> = parseArray<List<MyObject>>(json = json, typeToken = type)
    println(result)
}
Run Code Online (Sandbox Code Playgroud)


小智 7

如果你ArrayList<MyObject>在解析的时候在gson中使用自己的;

Type typeMyType = new TypeToken<ArrayList<MyObject>>(){}.getType();

ArrayList<MyObject> myObject = gson.fromJson(jsonString, typeMyType)
Run Code Online (Sandbox Code Playgroud)