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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43233898/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:47:47  来源:igfitidea点击:

How to check if JSON is valid in Java using GSON?

javajsongson

提问by QkiZ

I have method that have to check if JSON is valid, found on How to check whether a given string is valid JSON in Javabut it doesn't work.

我有必须检查 JSON 是否有效的方法,可以在How to check a given string is valid JSON in Java 中找到,但它不起作用。

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;
        }
    }

If I use this method with some string it always returns true. For example:

如果我将此方法与某个字符串一起使用,它总是返回 true。例如:

System.out.println(renderHtml.isJson("{\"status\": \"UP\"}"));

it gave me true, and

它给了我true,并且

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

gave me truealso.

true也给了我。

采纳答案by QkiZ

I found solution but using org.jsonlibrary, according to How to check whether a given string is valid JSON in Java

我找到了解决方案,但使用org.json库,根据How to check if a given string is valid JSON in Java

public static boolean isJson(String Json) {
        try {
            new JSONObject(Json);
        } catch (JSONException ex) {
            try {
                new JSONArray(Json);
            } catch (JSONException ex1) {
                return false;
            }
        }
        return true;
    }

Now random looking string bncjbhjfjhjis falseand {"status": "UP"}is true.

现在看起来随机的字符串bncjbhjfjhjfalse并且{"status": "UP"}是真的。

回答by WilomGfx

While it might be weird to you

虽然这对你来说可能很奇怪

"bncjbhjfjhj"

Is indeed valid json, as it is a string, and its the only string.

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

According to the not so new JSON RFC

根据不太新的JSON RFC

A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array. Implementations that generate only objects or arrays where a JSON text is called for will be interoperable in the sense that all implementations will accept these as conforming JSON texts.

JSON 文本是一个序列化值。请注意,某些先前的 JSON 规范将 JSON 文本限制为对象或数组。仅生成需要 JSON 文本的对象或数组的实现将是可互操作的,因为所有实现都将接受这些作为一致的 JSON 文本。

回答by Lyubomyr Shaydariv

You should not use Gsonto make such validation:

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

  • Gsonis an object that performs deserializationtherefore it deserializes entireJSON as an object in memory.
  • Gson, and I didn't know it, may be not very strict for some invalid JSONs: bncjbhjfjhjis deserialized as a java.lang.Stringinstance. Surprise-surprise!
  • Gson是一个执行反序列化的对象,因此它将整个JSON反序列化为内存中的一个对象。
  • Gson,我不知道,对于一些无效的 JSON 可能不是很严格:bncjbhjfjhj被反序列化为一个java.lang.String实例。惊喜——惊喜!
private static final Gson gson = new Gson();

private static final String VALID_JSON = "{\"status\": \"UP\"}";
private static final String INVALID_JSON = "bncjbhjfjhj";

System.out.println(gson.fromJson(VALID_JSON, Object.class).getClass());
System.out.println(gson.fromJson(INVALID_JSON, Object.class).getClass());

Output:

输出:

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

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

What you can do here is using JsonReaderto read incoming JSON token by token thus making if the given JSON document is syntactically valid.

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

private static boolean isJsonValid(final String json)
        throws IOException {
    return isJsonValid(new StringReader(json));
}

private static boolean isJsonValid(final Reader reader)
        throws IOException {
    return isJsonValid(new JsonReader(reader));
}

private static boolean isJsonValid(final JsonReader jsonReader)
        throws IOException {
    try {
        JsonToken token;
        loop:
        while ( (token = jsonReader.peek()) != END_DOCUMENT && token != null ) {
            switch ( token ) {
            case BEGIN_ARRAY:
                jsonReader.beginArray();
                break;
            case END_ARRAY:
                jsonReader.endArray();
                break;
            case BEGIN_OBJECT:
                jsonReader.beginObject();
                break;
            case END_OBJECT:
                jsonReader.endObject();
                break;
            case NAME:
                jsonReader.nextName();
                break;
            case STRING:
            case NUMBER:
            case BOOLEAN:
            case NULL:
                jsonReader.skipValue();
                break;
            case END_DOCUMENT:
                break loop;
            default:
                throw new AssertionError(token);
            }
        }
        return true;
    } catch ( final MalformedJsonException ignored ) {
        return false;
    }
}

And then test it:

然后测试一下:

System.out.println(isJsonValid(VALID_JSON));
System.out.println(isJsonValid(INVALID_JSON));

Output:

输出:

true
false


回答by Vadzim

I was quite surprised that while GsonBuilder#setLenientstates

我很惊讶,虽然GsonBuilder#setLenient状态

By default, Gson is strict and only accepts JSON as specified by RFC 4627. This option makes the parser liberal in what it accepts.

默认情况下,Gson 是严格的,并且只接受RFC 4627指定的 JSON 。此选项使解析器在其接受的内容上自由化。

It appears to be flat-out lie as it is actually always lenient. Moreover, even any call to JsonReader.setLenient(false)is completely ignored!

这似乎是彻头彻尾的谎言,因为它实际上总是很宽容。而且,甚至任何调用都JsonReader.setLenient(false)被完全忽略了!

After some browsing in numerousrelatedissuesand severalrejectedpullrequests "due to legacy compatibility reasons" I've at last found https://github.com/google/gson/issues/1208with sensible workaround:

在浏览了许多相关问题几个“由于遗留兼容性原因”而被拒绝的拉取请求之后,我终于找到了https://github.com/google/gson/issues/1208和合理的解决方法:

JakeWharton commented on 15 Dec 2017

You can call getAdapter(type).fromJson(gson.newJsonReader(input)) instead of just fromJson(input) to get strict parsing. We should really deprecate all of the fromJson methods and add new versions that are strict by default.

The reason is bad decisions long ago that we can no longer change ;(

Hyman沃顿于 2017 年 12 月 15 日发表评论

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

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

So here is pure Gson solution for strinct json object parsing with extensive test case.

所以这里是纯 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());
    }

}

Note the this ensures single top level object. It's possible to replace JsonObject.classwith JsonArray.classor JsonElement.classto allow top level array or null.

请注意,这确保了单个顶级对象。可以替换JsonObject.classJsonArray.classJsonElement.class允许顶级数组或null

The code above parses JSON to JsonObjectDOM representation.

上面的代码将 JSON 解析为JsonObjectDOM 表示。

The code below does strict parsing into custom POJO with conventional fields mapping.

下面的代码使用常规字段映射严格解析为自定义 POJO。

// 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);
}

回答by mathslimin

this works for me

这对我有用

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;
    }
}