如何使用 GSON 反序列化自定义地图
How to deserialize custom Map with GSON
我正在使用 Apache Collection 的 BidiMap
,它提供 DualHashBidiMap
class。我必须在项目中使用这个 class。
用它连载没有问题。但是我有反序列化的问题!
这是一个示例 class:
package com.description;
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
public class Sample {
private String id;
private String adress;
BidiMap<Integer, String> items = new DualHashBidiMap<Integer, String>();
public Sample() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public BidiMap<Integer, String> getItems() {
return items;
}
public void setItems(BidiMap<Integer, String> items) {
this.items = items;
}
}
和主要方法
Sample sample = new Sample();
sample.setId("12312xoa01");
sample.setAdress("Houston, 43.1");
BidiMap<Integer, String> items = new DualHashBidiMap<Integer, String>();
items.put(1, "gloves");
items.put(90, "boots");
sample.setItems(items);
try {
String result = gson.toJson(sample);
System.out.println("result : "+result);
Sample sample2 = gson.fromJson(result, Sample.class);
System.out.println("address : "+sample2.getAdress());
}catch (Exception e){
e.printStackTrace();
}
**
**
result : {"id":"12312xoa01","adress":"Houston, 43.1","items":{"1":"gloves","90":"boots"}}
java.lang.IllegalArgumentException: Can not set org.apache.commons.collections4.BidiMap field com.description.Sample.items to java.util.LinkedHashMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:741)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:118)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
at com.google.gson.Gson.fromJson(Gson.java:879)
at com.google.gson.Gson.fromJson(Gson.java:844)
at com.google.gson.Gson.fromJson(Gson.java:793)
at com.google.gson.Gson.fromJson(Gson.java:765)
at Main.main(Main.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
为什么需要使用BidiMap?
检查这些:
deserializing generics with gson
How to deserialize a ConcurrentMap with Gson
稍后尝试使用 Map 或 LinkedHashMap 或手动从 Map 解析为 BidiMap 类型,以检查错误是否仍然存在。编写 TypeAdapter 也是一种选择。
顺便说一下:您的 JSON 不是 Map<Integer,String>
而是 Map<String,String>
地图 {"1":"gloves","90":"boots"}
我之前尝试过 GSON,它与 Java 中的原生类型配合得很好。我从未尝试过解析其他库,因为我认为您需要一个 TypeAdapter。
这不是那么简单,但可以做到:
public class BidiMapTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!BidiMap.class.isAssignableFrom(type.getRawType())) {
return null;
}
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
return (T) new DualHashBidiMap<>((Map) delegate.read(in));
}
};
}
}
注册 TypeAdapterFactory:
GsonBuilder b = new GsonBuilder().registerTypeAdapterFactory(new BidiMapTypeAdapterFactory());
Gson gson = b.create();
现在您可以 运行 您的示例,它应该可以工作。
我正在使用 Apache Collection 的 BidiMap
,它提供 DualHashBidiMap
class。我必须在项目中使用这个 class。
用它连载没有问题。但是我有反序列化的问题!
这是一个示例 class:
package com.description;
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
public class Sample {
private String id;
private String adress;
BidiMap<Integer, String> items = new DualHashBidiMap<Integer, String>();
public Sample() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public BidiMap<Integer, String> getItems() {
return items;
}
public void setItems(BidiMap<Integer, String> items) {
this.items = items;
}
}
和主要方法
Sample sample = new Sample();
sample.setId("12312xoa01");
sample.setAdress("Houston, 43.1");
BidiMap<Integer, String> items = new DualHashBidiMap<Integer, String>();
items.put(1, "gloves");
items.put(90, "boots");
sample.setItems(items);
try {
String result = gson.toJson(sample);
System.out.println("result : "+result);
Sample sample2 = gson.fromJson(result, Sample.class);
System.out.println("address : "+sample2.getAdress());
}catch (Exception e){
e.printStackTrace();
}
**
**
result : {"id":"12312xoa01","adress":"Houston, 43.1","items":{"1":"gloves","90":"boots"}}
java.lang.IllegalArgumentException: Can not set org.apache.commons.collections4.BidiMap field com.description.Sample.items to java.util.LinkedHashMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:741)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:118)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
at com.google.gson.Gson.fromJson(Gson.java:879)
at com.google.gson.Gson.fromJson(Gson.java:844)
at com.google.gson.Gson.fromJson(Gson.java:793)
at com.google.gson.Gson.fromJson(Gson.java:765)
at Main.main(Main.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
为什么需要使用BidiMap?
检查这些:
deserializing generics with gson
How to deserialize a ConcurrentMap with Gson
稍后尝试使用 Map 或 LinkedHashMap 或手动从 Map 解析为 BidiMap 类型,以检查错误是否仍然存在。编写 TypeAdapter 也是一种选择。
顺便说一下:您的 JSON 不是 Map<Integer,String>
而是 Map<String,String>
地图 {"1":"gloves","90":"boots"}
我之前尝试过 GSON,它与 Java 中的原生类型配合得很好。我从未尝试过解析其他库,因为我认为您需要一个 TypeAdapter。
这不是那么简单,但可以做到:
public class BidiMapTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!BidiMap.class.isAssignableFrom(type.getRawType())) {
return null;
}
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
return (T) new DualHashBidiMap<>((Map) delegate.read(in));
}
};
}
}
注册 TypeAdapterFactory:
GsonBuilder b = new GsonBuilder().registerTypeAdapterFactory(new BidiMapTypeAdapterFactory());
Gson gson = b.create();
现在您可以 运行 您的示例,它应该可以工作。