Java 具有内部抽象类的容器类的Gson反序列化
我发现使用GSON反序列化这个类有点困难。 从这里的资源抽象类开始:Java 具有内部抽象类的容器类的Gson反序列化,java,gson,Java,Gson,我发现使用GSON反序列化这个类有点困难。 从这里的资源抽象类开始: public abstract class Resource() { String id; Integer quantity; } public class Wood extends Resource { } public class Stone extends Resource{ } 然后我有一个容器类: public class ResourceSet { Map<String, Resource> re
public abstract class Resource() {
String id;
Integer quantity;
}
public class Wood extends Resource {
}
public class Stone extends Resource{
}
然后我有一个容器类:
public class ResourceSet {
Map<String, Resource> resourcesMap;
}
一个选项是为
资源
类型创建自定义反序列化器。在其中,在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;
}
}
这是一个很好的响应,但问题是我想为资源集而不是资源编写json反序列化程序。假设我想反序列化这个json字符串:
{“resourcesMap”:{“Wood”:{“quantity”:4},“Stone”:{“quantity”:2}}}
在这种情况下,您可以“向上一级”并反序列化映射本身。我在我的答案中添加了一个更新,以演示我所说的内容。
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);
}
}