Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 反序列化json时从JsonArray中排除NULL_Java_Spring Boot_Gson - Fatal编程技术网

Java 反序列化json时从JsonArray中排除NULL

Java 反序列化json时从JsonArray中排除NULL,java,spring-boot,gson,Java,Spring Boot,Gson,我在请求体中收到一个无效的json(列表末尾额外的逗号),GSON库正在成功地对其进行反序列化。检查时,我看到GSON在最后插入了一个空对象 { "content": "Test 2", "timestamp": 1494311947530, "entities": [ {"name": "entity1"}, {"name": "entity2"}, {"name": "entity3"}, {"name"

我在请求体中收到一个无效的json(列表末尾额外的逗号),GSON库正在成功地对其进行反序列化。检查时,我看到GSON在最后插入了一个空对象

{
    "content": "Test 2",
    "timestamp": 1494311947530,
    "entities": [
        {"name": "entity1"},
        {"name": "entity2"},
        {"name": "entity3"},
        {"name": "entity4"},
        {"name": "entity5"},
    ]
}
有没有一种方法可以让我指示GSON不要接受无效的json,或者从JsonArray中删除空对象

我已尝试为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;
    }
}
公共类RemoveNullCollectionSerializer实现JsonDeserializer{
@凌驾
公共集反序列化(JsonElement JsonElement,类型类型,JsonDeserializationContext)引发JsonParseException{
JsonArray elements=jsonElement.getAsJsonArray();
Set result=new HashSet();
for(JsonElement元素:元素){
如果(element.isJsonNull())继续;
T值=(T)上下文.反序列化(元素,对象.类);
结果:增加(价值);
}
返回结果;
}
}

我尝试不注册自定义适配器,因为项目中有很多型号,每个型号都需要一个适配器,这将是一项艰巨的任务。

很抱歉,Gson似乎无法做到这一点。Gson中有一个特殊的模式,指示它在“宽松”模式下工作——这就是为什么在结果集合中得到
null
元素的原因。lenient模式告诉Gson忽略一些软无效JSON问题,其中之一是读取尾部数组元素和对象属性。如果查看实际负责收集的
CollectionTypeAdapterFactory
,您会看到:

@Override public Collection read(JsonReader in)引发IOException{
if(in.peek()==JsonToken.NULL){
in.nextNull();
返回null;
}
Collection=constructor.construct();
in.beginArray();
while(在.hasNext()中){
E instance=elementTypeAdapter.read(in);
集合。添加(实例);
}
in.endArray();
回收;
}
如您所见,将读取元素
实例
,并始终将其添加到结果集合中。
elementTypeAdapter.read
在非宽容模式下可能会失败,但这意味着对象不会完全构造。您可以这样检查:

private static final Gson Gson=new GsonBuilder()
.registerTypeAdapterFactory(新的TypeAdapterFactory(){
@凌驾
公共类型适配器创建(最终Gson Gson、最终TypeToken TypeToken){
如果(!Collection.class.isAssignableFrom(typeToken.getRawType())){
返回null;
}
final-TypeAdapter-delegateAdapter=gson.getDelegateAdapter(这个,typeToken);
返回新的TypeAdapter(){
@凌驾
公共无效写入(最终JsonWriter out,最终T值)
抛出IOException{
delegateAdapter.write(out,value);
}
@凌驾
公共T读(最终JsonReader in)
抛出IOException{
最后一个布尔值waslenent=in.isLenient();
试一试{
in.setLenient(假);
返回delegateAdapter.read(in);
}最后{
in.setLenient(waslenet);
}
}
};
}
})
.create();
请注意,
read
方法暂时禁用宽松模式,然后将其恢复。上面的代码会导致

使用JsonReader.setLenient(true)在第20行第3列路径$.entities[5]处接受格式错误的JSON

为您提供一个“空”JSON文档。根据Gson中的宽松模式,无法检查下一个JSON令牌是否会失败。不是最好的方法(但可能是唯一的方法)是使用反射来获得
JsonReader
后台读取器(
reader
),并用一个新的
JsonReader
重写
hasNext()
方法或类似的东西来装饰它。如果
JsonReader
支持一种方法来检查它的最后一个值是否是由于设置为true的宽容模式而生成的,那就太好了。但即使它支持类似的内容,也不能保证删除最后一个元素,因为特定类型适配器可能返回不可修改的集合


顺便说一句,我认为这个问题应该发布到--我希望得到Gson团队的反馈。

可以使用正则表达式从序列化字符串中删除无效逗号。恐怕我不知道确切的语法。json是来自API还是什么?只是想弄清楚您是如何接收无效json的。我不知道Gson中有任何内置函数允许您跳过空值(自定义反序列化程序除外),但是,Genson()的工作方式非常类似,但它确实允许您跳过空值。这是向用户公开的公共api的一部分。json是从用户应用程序收到的,因为他的应用程序中有一个bug,导致API端点抛出NPE。该服务高度依赖GSON,所以用Genson替换有点困难。谢谢您的详细解释。我将尝试上述解决方案,同时我已经在他们的github页面上创建了引起关注的问题