从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"}]
此String的生成如下:
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列表,但我如何将它们转换为我的产品对象?
答案 0 :(得分:82)
在我看来,由于类型擦除,解析器无法在运行时获取实际类型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();
答案 1 :(得分:14)
我也有GSON抱怨有关CastTreeMaps的问题。
Alexis提供的answer和Aljoscha提供的comment解释了错误发生的原因; &#34;类型上的泛型通常在运行时被擦除。&#34;我的问题是我的代码在我正常运行时有效,但使用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规则。
答案 2 :(得分:5)
类似于Alexis C的答案。但是在科特林 只需将类类型传递给函数并阐明泛型类型即可 这是简化的例子。
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)
}
答案 3 :(得分:1)
我还面临com.google.gson.internal.LinkedTreeMap的类强制转换,仅用于我的签名版本。我在progurard中添加了以下这些行。然后它工作正常。
-keepattributes签名
-keepattributes Annotation
-keep class com.google。** {*; }
-keep class sun.misc。** {*; }
答案 4 :(得分:1)
对于 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键值对象映射数据以获取行属性值,如下所示:
...
...
@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;
}
...
...
答案 5 :(得分:1)
如果您在解析时在gson中使用自己的ArrayList<MyObject>
;
Type typeMyType = new TypeToken<ArrayList<MyObject>>(){}.getType();
ArrayList<MyObject> myObject = gson.fromJson(jsonString, typeMyType)
答案 6 :(得分:1)
我有同样的问题。我注意到只有在将List作为参数时,它才会发生。
我的解决方案是将列表包装在另一个对象中
class YourObjectList {
private List<YourObject> items;
// constructor, getter and setter
}
有了这个单个对象,我就不再遇到类强制转换异常的问题。
答案 7 :(得分:0)
{"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 :(得分:0)
要添加到此处已提到的答案,如果您有一个处理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 :(得分:0)
解析时使用
public static <T> List<T> parseGsonArray(String json, Class<T[]> model) {
return Arrays.asList(new Gson().fromJson(json, model));
}