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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27253555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:03:43  来源:igfitidea点击:

com.google.gson.internal.LinkedTreeMap cannot be cast to my class

javajsoncastinggson

提问by Tanzmaus

I have some problems with getting my object from a JSON string.

我在从 JSON 字符串获取对象时遇到了一些问题。

I got the class Product

我上了课 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);
    }
}    

From my server I get an ArrayList<Product>in JSON String representation. For example:

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

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

This String is generated like this:

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

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

To get my Object back I use this function:

为了取回我的对象​​,我使用了这个函数:

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;
}

But when calling

但是当调用

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

I get the error com.google.gson.internal.LinkedTreeMap cannot be cast to object.Product

我收到错误 com.google.gson.internal.LinkedTreeMap cannot be cast to object.Product

What am I doing wrong? It looks like it created a List of LinkedTreeMaps but how do i convert those into my Product Object?

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

回答by Alexis C.

In my opinion, due to type erasure, the parser can't fetch the real type T at runtime. One workaround would be to provide the class type as parameter to the method.

在我看来,由于类型擦除,解析器无法在运行时获取真正的类型 T。一种解决方法是提供类类型作为方法的参数。

Something like this works, there are certainly other possible workarounds but I find this one very clear and concise.

像这样的工作,当然还有其他可能的解决方法,但我发现这个非常清晰简洁。

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
}

And call it like:

并称之为:

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

回答by welshk91

I also had problems with GSON complaining about casting LinkedTreeMaps.

我也遇到了 GSON 抱怨投射 LinkedTreeMaps 的问题。

The answerprovided by Alexis and the commentby Aljoscha explains why the error occurs; "Generics on a type are typically erased at runtime." My issue was that my code worked when I ran it normally, but using ProGuard caused code to be stripped that was vital to casting.

Alexis 提供的答案和Aljoscha的评论解释了错误发生的原因;“类型上的泛型通常在运行时被擦除。” 我的问题是我的代码在我正常运行时可以工作,但是使用 ProGuard 会导致代码被剥离,这对转换至关重要。

You can follow Alexis's answer and more clearly define the cast and that should fix the problems. You can also add the ProGuard rulesgiven by Google (simply doing this cleared the issue up for me).

您可以按照亚历克西斯的回答,更清楚地定义演员阵容,这应该可以解决问题。您还可以添加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  ----------

Moral of the Story: Always check to see what ProGuard rules you need.

故事寓意:始终检查以了解您需要哪些 ProGuard 规则。

回答by Ganesan

I also faced class cast exception of com.google.gson.internal.LinkedTreeMap for my signed build only. I added these below lines in progurard. Then it works fine.

对于我的签名版本,我还面临 com.google.gson.internal.LinkedTreeMap 的类转换异常。我在 progurard 中添加了以下几行。然后它工作正常。

-keepattributes Signature

-keepattributes 签名

-keepattributes Annotation

-keepattributes注解

-keep class com.google.** { *; }

-keep class com.google.** { *; }

-keep class sun.misc.** { *; }

-保持类 sun.misc.** { *; }

回答by Ozzie

{"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 
}

回答by Serguei Fedorov

To add to the answers already mentioned here, if you have a generic class that handles, say, HTTP calls, it maybe useful to pass Class<T>as part of the constructor.

补充一下这里已经提到的答案,如果你有一个通用类来处理,比如 HTTP 调用,Class<T>作为构造函数的一部分传递可能很有用。

To give a little more detail, this happens because Java cannot infer the Class<T>during runtime with just T. It needs the actual solid class to make the determination.

更详细地说,发生这种情况是因为 Java 无法Class<T>仅使用T. 它需要实际的实体类来做出决定。

So, if you have something like this, like I do:

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

class HttpEndpoint<T> implements IEndpoint<T>

you can allow the inheriting code to also send the class<T>, since at that point is it clear what T is.

您可以允许继承代码也发送class<T>,因为此时很清楚 T 是什么。

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

inheriting class:

继承类:

public class Players extends HttpEndpoint<Player> {

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

while not entirely a clean solution, it does keep the code packaged up and you don't have to Class<T>between methods.

虽然不完全是一个干净的解决方案,但它确实将代码打包,并且您不必Class<T>在方法之间进行转换。

回答by Johnny

Similar to Alexis C's answers. but in Kotlin.
Just pass the class type into function and clarify what generic type is.
Here is simplified example.

类似于 Alexis C 的答案。但是在 Kotlin 中。
只需将类类型传递给函数并阐明泛型类型是什么。
这是简化的示例。

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

Here is example call

这是示例调用

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)
}

回答by Code Spy

For JSON

对于JSON

{
    results: [
    {
        id: "10",
        phone: "+91783XXXX345",
        name: "Mr Example",
        email: "[email protected]"
    },
    {
        id: "11",
        phone: "+9178XXXX66",
        name: "Mr Foo",
        email: "[email protected]"
    }],
    statusCode: "1",
    count: "2"
}

In listView BaseAdapter filewe need to map data using LinkedTreeMap Key Value object to get row attribute value as below:

listView BaseAdapter 文件中,我们需要使用 LinkedTreeMap Key Value 对象映射数据以获取行属性值,如下所示:

...
...

    @Override
    public View getView(final int i, View view, ViewGroup viewGroup) {
        if(view==null)
        {
            view= LayoutInflater.from(c).inflate(R.layout.listview_manage_clients,viewGroup,false);
        }

        TextView mUserName = (TextView) view.findViewById(R.id.userName);
        TextView mUserPhone = (TextView) view.findViewById(R.id.userPhone);


        Object getrow = this.users.get(i);
        LinkedTreeMap<Object,Object> t = (LinkedTreeMap) getrow;
        String name = t.get("name").toString();

        mUserName.setText("Name is "+name);
        mUserPhone.setText("Phone is "+phone);

        return view;
    }
...
...

ListView from JSON Data using Retrofit2 in Android Example

在 Android 示例中使用 Retrofit2 从 JSON 数据获取 ListView

Source Link

源链接

回答by MFQ

use this when parsing

解析时使用这个

  public static <T> List<T> parseGsonArray(String json, Class<T[]> model) {
    return Arrays.asList(new Gson().fromJson(json, model));
}

回答by murat gursel

If you use your own ArrayList<MyObject>in gson when parsing;

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

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

ArrayList<MyObject> myObject = gson.fromJson(jsonString, typeMyType)

回答by kaiser

I had the same problem. I noticed it only occures when you have List as argument.

我有同样的问题。我注意到只有当你有 List 作为参数时才会发生。

My solution is to wrap the list in another Object:

我的解决方案是将列表包装在另一个对象中:

class YourObjectList {

    private List<YourObject> items;

    // constructor, getter and setter
}

With that single object, i had no more problems with class cast exception.

有了那个单一的对象,我就不再有类转换异常的问题了。