3 回答
TA贡献1864条经验 获得超2个赞
通常,集合实现从集合字段声明“take”类型 - 而不是从 //etc 上的给定项。我们需要编写自定义序列化器,为每个项目查找序列化程序并使用它。实现简单:ListSet
class TypeAwareListJsonSeserializer implements JsonSerializer<List<?>> {
@Override
public JsonElement serialize(List<?> src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
JsonArray array = new JsonArray();
for (Object item : src) {
JsonElement jsonElement = context.serialize(item, item.getClass());
array.add(jsonElement);
}
return array;
}
}
这就是我们如何使用它:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.annotations.JsonAdapter;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
public class GsonApp {
public static void main(String[] args) throws Exception {
List<BaseBean> children = Arrays.asList(new BaseBean(), new ChildBean(), new ChildBean2());
BaseBeanHolder baseHolder = new BaseBeanHolder(children);
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
System.out.println(gson.toJson(baseHolder));
}
}
class BaseBean {
String baseField = "base";
}
class ChildBean extends BaseBean {
String childField = "child";
}
class ChildBean2 extends BaseBean {
int bean2Int = 356;
}
class BaseBeanHolder {
@JsonAdapter(TypeAwareListJsonSeserializer.class)
private List<? extends BaseBean> beans;
// getters, setters, toString
}
以上代码打印:
{
"beans": [
{
"baseField": "base"
},
{
"childField": "child",
"baseField": "base"
},
{
"bean2Int": 356,
"baseField": "base"
}
]
}
编辑
在序列化过程中,我们会丢失有关反序列化过程中所需的类型的信息。我开发了简单的类型信息,这些信息将在序列化期间存储并用于反序列化。它可能如下所示:
class TypeAwareListJsonAdapter implements JsonSerializer<List<?>>, JsonDeserializer<List<?>> {
private final String typeProperty = "@type";
@Override
public JsonElement serialize(List<?> src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
JsonArray array = new JsonArray();
for (Object item : src) {
JsonObject jsonElement = (JsonObject) context.serialize(item, item.getClass());
jsonElement.addProperty(typeProperty, item.getClass().getSimpleName());
array.add(jsonElement);
}
return array;
}
@Override
public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final Type elementType = $Gson$Types.getCollectionElementType(typeOfT, List.class);
if (json instanceof JsonArray) {
final JsonArray array = (JsonArray) json;
final int size = array.size();
if (size == 0) {
return Collections.emptyList();
}
final List<?> suites = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
JsonObject jsonElement = (JsonObject) array.get(i);
String simpleName = jsonElement.get(typeProperty).getAsString();
suites.add(context.deserialize(jsonElement, getClass(simpleName, elementType)));
}
return suites;
}
return Collections.emptyList();
}
private Type getClass(String simpleName, Type defaultType) {
try {
// you can use mapping or something else...
return Class.forName("com.model." + simpleName);
} catch (ClassNotFoundException e) {
return defaultType;
}
}
}
最大的问题是如何将类映射到值。我们可以使用类的简单名称或提供并使用它。现在,我们可以如上所述使用它。现在应用打印示例:JSONMap<String, Class>
{
"beans": [
{
"baseField": "base",
"@type": "BaseBean"
},
{
"childField": "child",
"baseField": "base",
"@type": "ChildBean"
},
{
"bean2Int": 356,
"baseField": "base",
"@type": "ChildBean2"
}
]
}
BaseBean{baseField='base'}
ChildBean{baseField='base', childField='child'}
ChildBean2{baseField='base', bean2Int=356}
TA贡献1860条经验 获得超9个赞
TA贡献1811条经验 获得超6个赞
更多的是附录:我只是认为至少序列化可以很好地处理数组,所以一个简单的解决方法是重新设计持有者:
static class BaseBeanHolder {
BaseBean[] beans;
public BaseBeanHolder(BaseBean... beans) { this.beans = beans; }
}
添加回答
举报