我在请求体中收到一个无效的json(列表末尾的额外逗号),GSON库正在成功地反序列化。在检查时,我看到GSON最终会插入一个NULL对象。
{
"content": "Test 2",
"timestamp": 1494311947530,
"entities": [
{"name": "entity1"},
{"name": "entity2"},
{"name": "entity3"},
{"name": "entity4"},
{"name": "entity5"},
]
}
有没有办法可以指示GSON不接受无效的json或从JsonArray中删除NULL对象。
我已经尝试为Set.class注册类型适配器,但我无法继续使用此解决方案,因为无法获取参数化对象的Type
。
public class RemoveNullCollectionSerializer<T> implements JsonDeserializer<Set<T>> {
@Override
public Set<T> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonArray elements = jsonElement.getAsJsonArray();
Set<T> result = new HashSet();
for (JsonElement element : elements) {
if (element.isJsonNull()) continue;
T value = (T) context.deserialize(element, Object.class);
result.add(value);
}
return result;
}
}
我试图不注册自定义适配器,因为项目中有很多模型,每个都需要一个适配器,这将是一项重大任务。
答案 0 :(得分:2)
我很抱歉,但Gson似乎无法做到这一点。 Gson中有一种特殊模式指示它在“宽松”模式下工作 - 这就是为什么你在结果集合中得到一个null
元素。宽松模式告诉Gson忽略一些软无效的JSON问题,其中一个是读取尾随数组元素和对象属性。如果您查看实际负责收集read的CollectionTypeAdapterFactory
,您会看到:
@Override public Collection<E> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Collection<E> collection = constructor.construct();
in.beginArray();
while (in.hasNext()) {
E instance = elementTypeAdapter.read(in);
collection.add(instance);
}
in.endArray();
return collection;
}
如您所见,读取元素instance
并将始终添加到结果集合中。 elementTypeAdapter.read
可能在非宽松模式下失败,但这意味着该对象不会完全构造。您可以这样检查:
private static final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( !Collection.class.isAssignableFrom(typeToken.getRawType()) ) {
return null;
}
final TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
final boolean wasLenient = in.isLenient();
try {
in.setLenient(false);
return delegateAdapter.read(in);
} finally {
in.setLenient(wasLenient);
}
}
};
}
})
.create();
请注意,read
方法会暂时禁用宽松模式,然后将其恢复。上面的代码会导致
使用JsonReader.setLenient(true)接受第20行第3行路径格式错误的JSON $ .entities [5]
为你尾随“空虚”JSON文件。根据Gson中的宽松模式,无法检查下一个JSON令牌是否会失败。本身并不是最好的(但可能唯一的方法)是使用反射来获取JsonReader
支持阅读器(实际为Reader
)并使用新的JsonReader
覆盖{{1}进行装饰方法或类似的东西。如果hasNext()
支持一种方法来检查是否由于lenient模式设置为true而生成了它的最后一个值,那将是很好的。但即使它支持类似的东西,也不能保证删除最后一个元素,因为特定类型的适配器可能会返回一个不可修改的集合。
顺便说一下,我认为这个问题应该发布到https://github.com/google/gson/issues/ - 我很想得到Gson团队的反馈意见。