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을 object.Product로 캐스팅 할 수 없다는 오류가 발생 합니다.
내가 도대체 뭘 잘못하고있는 겁니까? LinkedTreeMaps 목록을 만든 것처럼 보이지만 어떻게 내 제품 개체로 변환합니까?
제 생각에는 유형 삭제로 인해 파서가 런타임에 실제 유형 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();
또한 LinkedTreeMaps를 캐스팅하는 것에 대해 불평하는 GSON에 문제가있었습니다.
대답 알렉시스와에 의해 제공 코멘트 오류가 발생하는 이유 Aljoscha에 의해 설명; "유형의 제네릭은 일반적으로 런타임에 지워집니다." 내 문제는 정상적으로 실행할 때 내 코드가 작동했지만 ProGuard를 사용하면 캐스팅에 중요한 코드가 제거된다는 것입니다.
Alexis의 답변을 따라 캐스트를 더 명확하게 정의하면 문제가 해결됩니다. 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 ----------
스토리의 도덕 : 필요한 ProGuard 규칙이 무엇인지 항상 확인하십시오.
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)
}
또한 서명 된 빌드에 대해서만 com.google.gson.internal.LinkedTreeMap의 클래스 캐스트 예외에 직면했습니다. 나는 progurard에서 아래 줄을 추가했습니다. 그런 다음 잘 작동합니다.
-keepattributes 서명
-keepattributes 주석
-keep class com.google. ** {*; }
-keep class sun.misc. ** {*; }
대한 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"
}
에서 목록보기 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;
}
...
...
Android 예제에서 Retrofit2를 사용하는 JSON 데이터의 ListView
나는 같은 문제가 있었다. 나는 당신이 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.
If you use your own ArrayList<MyObject>
in gson when parsing;
Type typeMyType = new TypeToken<ArrayList<MyObject>>(){}.getType();
ArrayList<MyObject> myObject = gson.fromJson(jsonString, typeMyType)
{"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
}
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.
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.
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.
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.
use this when parsing
public static <T> List<T> parseGsonArray(String json, Class<T[]> model) {
return Arrays.asList(new Gson().fromJson(json, model));
}
ReferenceURL : https://stackoverflow.com/questions/27253555/com-google-gson-internal-linkedtreemap-cannot-be-cast-to-my-class
'programing' 카테고리의 다른 글
ng-show / -hide의 대안 또는 DOM의 관련 섹션 만로드하는 방법 (0) | 2021.01.19 |
---|---|
NSBlockOperation 및 큐가있는 NSURLSession (0) | 2021.01.19 |
JUnit 테스트에서 catch 시도 (0) | 2021.01.19 |
Postman을 사용하여 OAuth 2.0 Google API에 액세스 (0) | 2021.01.19 |
팬더 플롯이 표시되지 않음 (0) | 2021.01.19 |