com.google.gson.internal.LinkedTreeMap 无法转换为我的班级[重复]

Posted

技术标签:

【中文标题】com.google.gson.internal.LinkedTreeMap 无法转换为我的班级[重复]【英文标题】:com.google.gson.internal.LinkedTreeMap cannot be cast to my class [duplicate] 【发布时间】:2015-01-30 22:38:58 【问题描述】:

我在从 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 字符串表示形式的 ArrayList<Product>。例如:

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

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

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

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

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;

但是调用的时候

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

我得到了错误 com.google.gson.internal.LinkedTreeMap 无法转换为 object.Product

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

【问题讨论】:

试试这个freakyjolly.com/… 试试这个 -keepattributes 签名 您可以遍历 ArrayList 以将每个 LinkedTreeMap 项目转换为 Product 项目。您可以再次使用Gson 进行转换。在此处查看示例代码:randomgyan.com/… 【参考方案1】:

在我看来,由于类型擦除,解析器无法在运行时获取真正的类型 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

然后这样称呼它:

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

【讨论】:

这个答案提供了一种解决方法,但没有解决嵌套泛型的问题。请参阅这两个答案以获得更通用的解决方案:***.com/a/14506181/4745878***.com/a/26203635/4745878 @AljoschaMeyer +1 获取有用的链接。 如果您尝试使用 GSON + Room,该解决方案将不起作用,因为 Room 不允许通用字段类型。这工作***.com/a/52224425/6009482【参考方案2】:

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

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

您可以按照亚历克西斯的回答,更清楚地定义演员阵容,这应该可以解决问题。您还可以添加 Google 提供的 ProGuard rules(只需这样做即可为我解决问题)。

##---------------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 规则。

【讨论】:

我必须定义我的自定义基础响应抽象类来保留。 -keep class * extends in.krsh.app.webservice.BaseResponseBody。这个类就像internal abstract class BaseResponseBody&lt;DataType&gt; 男孩,你是救命稻草 这对我有用。谢谢兄弟。【参考方案3】:

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

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

这里是调用示例

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)

【讨论】:

【参考方案4】:

如果你在解析的时候在gson中使用了自己的ArrayList&lt;MyObject&gt;

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

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

【讨论】:

【参考方案5】:

对于JSON


    results: [
    
        id: "10",
        phone: "+91783XXXX345",
        name: "Mr Example",
        email: "freaky@jolly.com"
    ,
    
        id: "11",
        phone: "+9178XXXX66",
        name: "Mr Foo",
        email: "freaky@jolly.com"
    ],
    statusCode: "1",
    count: "2"

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

Source Link

【讨论】:

【参考方案6】:

我还面临 com.google.gson.internal.LinkedTreeMap 的类转换异常,仅用于我的签名构建。我在 progurard 中添加了以下这些行。然后就可以正常使用了。

-keepattributes 签名

-keepattributes 注解

-keep class com.google.** *;

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

【讨论】:

请添加更多信息并解释解决方案。 您可以将其添加到您的 proguard 中,并且可以在签名版本中正常工作 这些是非常广泛的 Proguard 规则。保留大量代码的规则违背了 Proguard 的目的,因为它无法去除那些包中未使用的代码,而这正是您使用 Proguard 的全部原因。 keep 语句应该一直到您需要的特定类,而不是保留所有 com.google.** 和 sun.misc.**。正确的规则类似于“-keep class com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse ; ”,具体取决于您使用的 GSON 模型类的存储位置。【参考方案7】:

解析时使用这个

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

【讨论】:

【参考方案8】:
"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 

【讨论】:

请附上问题的解释和可能的解决方案。【参考方案9】:

为了补充这里已经提到的答案,如果您有一个处理 HTTP 调用的泛型类,将 Class&lt;T&gt; 作为构造函数的一部分传递可能很有用。

更详细地说,这是因为 Java 无法在运行时仅使用 T 推断出 Class&lt;T&gt;。需要实际的solid类来判断。

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

class HttpEndpoint<T> implements IEndpoint<T>

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

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

继承类:

public class Players extends HttpEndpoint<Player> 

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

虽然不完全是一个干净的解决方案,但它确实将代码打包,您不必在方法之间Class&lt;T&gt;

【讨论】:

【参考方案10】:

我遇到了同样的问题。我注意到它仅在您将 List 作为参数时才会发生。

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

class YourObjectList 

    private List<YourObject> items;

    // constructor, getter and setter

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

【讨论】:

以上是关于com.google.gson.internal.LinkedTreeMap 无法转换为我的班级[重复]的主要内容,如果未能解决你的问题,请参考以下文章

java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为 java.util.LinkedHashMap

SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常

SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常

SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常

SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常

SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常