我发现使用GSON反序列化这个类有点困难。 从这里的Resource ABSTRACT类开始:
{
"resourcesMap":{
"Wood":{"quantity":4},
"Stone":{"quantity":2}
}
}
然后我有一个容器类:
{{1}}
在地图中,键是资源的ID,而值是资源本身。 我不知道如何正确地反序列化这个类,让gson知道当他解析字符串“Wood”时,资源就是Wood的一个实例。否则gson使用作为抽象类的资源类的基础构造函数,因此它给了我一个例外。
我想要反序列化的json字符串的示例可能是:
{{1}}
答案 0 :(得分:1)
一个选项是为Resource
类型创建自定义反序列化程序。在其中,使用JSON消息中的提示来确定Resource
应该是什么类型。
我不确定您的JSON消息是什么样的,但解决方案看起来像这样:
public class ResourceDeserializer implements JsonDeserializer<Resource> {
@Override
public Resource deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject root = json.getAsJsonObject();
final Resource resource;
if("wood".equalsIgnoreCase(root.get("type"))) {
resource = new WoodResource();
} else {
resource = new StoneResource();
}
return resource;
}
}
<强>已更新强>
abstract class Resource {
protected String id;
protected Integer quantity;
}
class Wood extends Resource {}
class Stone extends Resource {}
class ResourceMap {
protected Map<String,Resource> resources;
ResourceMap() {
this.resources = new HashMap<>();
}
}
class ResourceMapDeserializer implements JsonDeserializer<ResourceMap> {
@Override
public ResourceMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject root = json.getAsJsonObject();
final ResourceMap instance = new ResourceMap();
instance.resources.put("Wood", parse(root, "Wood"));
instance.resources.put("Stone", parse(root, "Stone"));
return instance;
}
private Resource parse(JsonObject root, String fieldName) {
final JsonElement field = root.get(fieldName);
if(field != null) {
final Resource resource;
if("Wood".equalsIgnoreCase(fieldName)) {
resource = new Wood();
} else {
resource = new Stone();
}
resource.quantity = field.getAsJsonObject().get("quantity").getAsInt();
return resource;
} else {
return null;
}
}
}
简单验证......
@RunWith(MockitoJUnitRunner.class)
public class ResourceDeserializerTest {
@Mock private JsonDeserializationContext mockContext;
private Gson gson;
@Before
public void setUp() {
gson = new GsonBuilder()
.registerTypeAdapter(ResourceMap.class, new ResourceMapDeserializer())
.setPrettyPrinting()
.create();
}
@Test
public void deserializes_resource_map() {
final JsonObject woodJson = new JsonObject();
woodJson.addProperty("quantity", 4);
final JsonObject stoneJson = new JsonObject();
stoneJson.addProperty("quantity", 2);
final JsonObject mapJson = new JsonObject();
mapJson.add("Wood", woodJson);
mapJson.add("Stone", stoneJson);
final ResourceMap deserialized = gson.fromJson(mapJson, ResourceMap.class);
assertThat(deserialized.resources.get("Wood").getClass()).isEqualTo(Wood.class);
assertThat(deserialized.resources.get("Stone").getClass()).isEqualTo(Stone.class);
}
}