如何使用GSON检查JSON在Java中是否有效?

如何使用GSON检查JSON在Java中是否有效?,java,json,gson,Java,Json,Gson,我有一个必须检查JSON是否有效的方法,可以在上找到,但它不起作用 public static boolean isJson(String Json) { Gson gson = new Gson(); try { gson.fromJson(Json, Object.class); return true; } catch (com.google.gson.JsonSyntaxException e

我有一个必须检查JSON是否有效的方法,可以在上找到,但它不起作用

public static boolean isJson(String Json) {
        Gson gson = new Gson();
        try {
            gson.fromJson(Json, Object.class);
            return true;
        } catch (com.google.gson.JsonSyntaxException ex) {
            return false;
        }
    }
如果我对某个字符串使用这个方法,它总是返回true。例如:

System.out.println(renderHtml.isJson("{\"status\": \"UP\"}"));
它给了我
正确的
,并且

System.out.println(renderHtml.isJson("bncjbhjfjhj"));

也给了我
真的

虽然你可能觉得奇怪

"bncjbhjfjhj"
确实是有效的json,因为它是一个字符串,并且是唯一的字符串

根据这项研究,这并不新鲜

JSON文本是一个序列化的值。请注意,某些以前的 JSON规范将JSON文本约束为对象或 数组。仅生成对象或数组的实现,其中 所调用的JSON文本将是可互操作的,因为所有 实现将接受这些作为一致的JSON文本


您不应使用
Gson
进行此类验证:

  • Gson
    是一个执行反序列化的对象,因此它将整个JSON反序列化为内存中的一个对象
  • Gson
    ,我不知道,对于一些无效的JSON可能不是很严格:
    bncjbhjfjhj
    被反序列化为
    java.lang.String
    实例。惊喜
private static final Gson Gson=new Gson();
私有静态最终字符串有效\u JSON=“{\”状态\“:\”向上\“}”;
私有静态最终字符串无效\u JSON=“bncjbhjfjhj”;
System.out.println(gson.fromJson(有效的_JSON,Object.class).getClass());
System.out.println(gson.fromJson(无效的_JSON,Object.class).getClass());
输出:

class com.google.gson.internal.LinkedTreeMap
类java.lang.String

您可以在这里使用
JsonReader
逐个令牌读取传入的JSON令牌,从而确定给定的JSON文档在语法上是否有效

private静态布尔值isJsonValid(最终字符串json)
抛出IOException{
返回isJsonValid(新的StringReader(json));
}
私有静态布尔值isJsonValid(最终读取器)
抛出IOException{
返回isJsonValid(新的JsonReader(reader));
}
私有静态布尔值isJsonValid(最终JsonReader JsonReader)
抛出IOException{
试一试{
杰森托肯代币;
循环:
while((token=jsonReader.peek())!=END\u文档和&token!=null){
交换机(令牌){
案例开始\u数组:
jsonReader.beginArray();
打破
案例结束单元阵列:
jsonReader.endArray();
打破
案例开始对象:
jsonReader.beginObject();
打破
案例结束对象:
jsonReader.endObject();
打破
案例名称:
jsonReader.nextName();
打破
大小写字符串:
案件编号:
大小写布尔值:
大小写为空:
jsonReader.skipValue();
打破
案例结束文件:
断环;
违约:
抛出新断言错误(令牌);
}
}
返回true;
}捕获(忽略最终格式错误的JSONException){
返回false;
}
}
然后测试它:

System.out.println(isJsonValid(VALID_JSON));
System.out.println(isJsonValid(INVALID_JSON));
输出:

正确
假的


我找到了解决方案,但使用了
org.json
库,根据


现在随机字符串
bncjbhjfjjj
false
{“status”:“UP”}
是true。

我很惊讶

默认情况下,Gson是严格的,只接受由指定的JSON。这个选项使解析器在接受什么方面变得自由

这似乎是彻头彻尾的谎言,因为它实际上总是宽大的。而且,即使是任何对的呼吁都被完全忽略了

在“由于遗留兼容性原因”进行了一些浏览和请求之后,我终于找到了合理的解决方法:

杰克·沃顿于2017年12月15日发表评论

您可以调用getAdapter(type).fromJson(gson.newJsonReader(input)) 而不仅仅是从JSON(输入)获得严格的解析。我们应该 真的不推荐所有fromJson方法并添加新版本 默认情况下是严格的

原因是很久以前的错误决定,我们无法再改变;(

因此,这里有一个纯Gson解决方案,用于使用大量测试用例进行严格的json对象解析

import org.junit.Test;
import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import static org.junit.Assert.*;

public class JsonTest {

    private static final TypeAdapter<JsonObject> strictGsonObjectAdapter = 
            new Gson().getAdapter(JsonObject.class);

    public static JsonObject parseStrict(String json) {
        // https://stackoverflow.com/questions/43233898/how-to-check-if-json-is-valid-in-java-using-gson/47890960#47890960
        try {
            //return strictGsonObjectAdapter.fromJson(json); // this still allows multiple top level values (
            try (JsonReader reader = new JsonReader(new StringReader(json))) {
                JsonObject result = strictGsonObjectAdapter.read(reader);
                reader.hasNext(); // throws on multiple top level values
                return result;
            }
        } catch (IOException e) {
            throw new JsonSyntaxException(e);
        }
    }

    @Test
    public void testStrictParsing() {
        // https://static.javadoc.io/com.google.code.gson/gson/2.8.5/com/google/gson/stream/JsonReader.html#setLenient-boolean-
        // Streams that start with the non-execute prefix, ")]}'\n".
        assertThrows(JsonSyntaxException.class, () -> parseStrict("){}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("]{}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("}{}"));
        // Streams that include multiple top-level values. With strict parsing, each stream must contain exactly one top-level value.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{}{}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{}[]null"));
        // Top-level values of any type. With strict parsing, the top-level value must be an object or an array.
        assertThrows(JsonSyntaxException.class, () -> parseStrict(""));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("null"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("Abracadabra"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("13"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("\"literal\""));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("[]"));
        // Numbers may be NaNs or infinities.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"number\": NaN}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"number\": Infinity}"));
        // End of line comments starting with // or # and ending with a newline character.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{//comment\n}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{#comment\n}"));
        // C-style comments starting with /* and ending with */. Such comments may not be nested.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{/*comment*/}"));
        // Names that are unquoted or 'single quoted'.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{a: 1}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{'a': 1}"));
        // Strings that are unquoted or 'single quoted'.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": str}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": ''}"));
        // Array elements separated by ; instead of ,.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": [1;2]}"));
        // Unnecessary array separators. These are interpreted as if null was the omitted value.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": [1,]}"));
        // Names and values separated by = or => instead of :.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\" = 13}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\" => 13}"));
        // Name/value pairs separated by ; instead of ,.
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": 1; \"b\": 2}"));

        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": }"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": ,}"));
        assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": 0,}"));

        assertTrue(parseStrict("{} ").entrySet().isEmpty());
        assertTrue(parseStrict("{\"a\": null} \n \n").get("a").isJsonNull());
        assertEquals(0, parseStrict("{\"a\": 0}").get("a").getAsInt());
        assertEquals("", parseStrict("{\"a\": \"\"}").get("a").getAsString());
        assertEquals(0, parseStrict("{\"a\": []}").get("a").getAsJsonArray().size());
    }

}
这对我有用

public static boolean isJson(String Json) {
    Gson gson = new Gson();
    try {
        gson.fromJson(Json, Object.class);
        Object jsonObjType = gson.fromJson(Json, Object.class).getClass();
        if(jsonObjType.equals(String.class)){
            return false;
        }
        return true;
    } catch (com.google.gson.JsonSyntaxException ex) {
        return false;
    }
}

你在寻找模式验证吗?尽管你在这一点上是正确的,OP实际上是在问为什么
Gson
没有拒绝
bncjbjfjhj
(没有引号)作为无效的JSON文档。因为它是有效的JSON?它只是一个简单的字符串OP用
renderHtml.isJson(“bncjbjfjhj”)测试它
,而不是使用
renderHtml.isJson(“\'bncjbhjfjj\”)
@WilomGfx你说得对。我通过使用
org.json
库找到了解决方案。@WilomGfx因为
Gson
与更低级的Gson组件
JsonReader
的工作原理不同。请同时检查
bncjbhjbhjfjjjjj
“bncjbhjfjfjfjj”
使用任何JSON linter。您希望使用此方法验证的最大JSON的大小是多少?不是很大。它用于从Springboot应用程序读取健康检查。3或4个嵌套级别。它们有一个特殊的JsonParser用于此:虽然此代码片段可能是解决方案,但确实有助于提高帖子的质量。记住您将为将来的读者回答这个问题,而这些人可能不知道您的代码建议的原因。
// https://github.com/google/gson/issues/1208
private static final TypeAdapter<Pojo> strictGsonAdapter = new Gson().getAdapter(Pojo.class);

public static Pojo parsePayment(String json) throws IOException {
    return strictGsonAdapter.fromJson(json);
}
public static boolean isJson(String Json) {
    Gson gson = new Gson();
    try {
        gson.fromJson(Json, Object.class);
        Object jsonObjType = gson.fromJson(Json, Object.class).getClass();
        if(jsonObjType.equals(String.class)){
            return false;
        }
        return true;
    } catch (com.google.gson.JsonSyntaxException ex) {
        return false;
    }
}