Подтвердить что ты не робот

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

На моем сервере я получаю ArrayList<Product> в представлении JSON String. Например:

[{"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 нельзя передать объекту. Продукт

Что я делаю неправильно? Похоже, что он создал список LinkedTreeMaps, но как я могу преобразовать их в свой объект продукта?

4b9b3361

Ответ 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();

Ответ 2

У меня также были проблемы с GSON, жалующимися на литье LinkedTreeMaps.

Ответ , предоставленный Алексисом, и комментарий от Aljoscha объясняет, почему возникает ошибка; "Дженерики типа обычно удаляются во время выполнения". Моя проблема заключалась в том, что мой код работал, когда я запускал его в обычном режиме, но с помощью кода ProGuard был отключен код, который был жизненно важен для кастинга.

Вы можете следить за ответами Алексиса и более четко определять актерский состав, и это должно устранить проблемы. Вы также можете добавить ProGuard правила, предоставленные Google (просто это очистило проблему для меня).

##---------------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 вам нужны.

Ответ 3

Похоже на ответы Алексея С. но в котлине.
Просто передайте тип класса в функцию и выясните, что такое универсальный тип.
Вот упрощенный пример.

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

Я также столкнулся с классом исключение com.google.gson.internal.LinkedTreeMap только для моей подписанной сборки. Я добавил эти строки в прогурар. Тогда он отлично работает.

-keepattributes Подпись

-keepattributes Annotation

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

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

Ответ 5

Для 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"
}

В файле listView BaseAdapter нам нужно отобразить данные, используя объект KeyedTreeMap 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 из данных JSON с использованием Retrofit2 в примере Android

Ссылка на источник

Ответ 6

Если вы используете свой собственный ArrayList<MyObject> в gson при разборе;

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

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

Ответ 7

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

Ответ 8

Чтобы добавить к уже упомянутым ответам, если у вас есть общий класс, который обрабатывает, скажем, HTTP-вызовы, может быть полезно передать Class<T> как часть конструктора.

Чтобы дать немного более подробную информацию, это происходит потому, что Java не может вывести Class<T> во время выполнения только с помощью T. Для определения требуется реальный сплошной класс.

Итак, если у вас есть что-то вроде этого, как и я:

class HttpEndpoint<T> implements IEndpoint<T>

вы можете разрешить наследовающему коду также отправлять Class<T>, так как в этот момент ясно, что такое 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<T> между методами.

Ответ 9

используйте это при разборе

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

Ответ 10

У меня такая же проблема. Я заметил, что это происходит только тогда, когда у вас есть список в качестве аргумента.

Мое решение состоит в том, чтобы обернуть список в другой объект:

class YourObjectList {

    private List<YourObject> items;

    // constructor, getter and setter
}

С этим единственным объектом у меня больше не было проблем с исключением классов.