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

yzckvree  于 2022-11-06  发布在  Java
关注(0)|答案(6)|浏览(196)

我在How to check whether a given string is valid JSON in Java上找到了一些必须检查JSON是否有效方法,但这些方法不起作用。

  1. public static boolean isJson(String Json) {
  2. Gson gson = new Gson();
  3. try {
  4. gson.fromJson(Json, Object.class);
  5. return true;
  6. } catch (com.google.gson.JsonSyntaxException ex) {
  7. return false;
  8. }
  9. }

如果我用这个方法处理某个字符串,它总是返回true。例如:

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

它给了我true

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

也给了我true

z9zf31ra

z9zf31ra1#

您不应该使用Gson来进行这样的验证:

  • Gson是一个执行 * 反序列化 * 的对象,因此它将 * 整个 * JSON反序列化为内存中的对象。
  • Gson(我不知道)对于某些无效JSON可能不是很严格:bncjbhjfjhj被反序列化为java.lang.String示例。惊喜吧!
  1. private static final Gson gson = new Gson();
  2. private static final String VALID_JSON = "{\"status\": \"UP\"}";
  3. private static final String INVALID_JSON = "bncjbhjfjhj";
  4. System.out.println(gson.fromJson(VALID_JSON, Object.class).getClass());
  5. System.out.println(gson.fromJson(INVALID_JSON, Object.class).getClass());

输出量:
谷歌公司网站首页
类java.lang.String
在这里,您可以使用JsonReader逐个读取传入的JSON令牌,从而判断给定的JSON文档在语法上是否有效。

  1. private static boolean isJsonValid(final String json)
  2. throws IOException {
  3. return isJsonValid(new StringReader(json));
  4. }
  5. private static boolean isJsonValid(final Reader reader)
  6. throws IOException {
  7. return isJsonValid(new JsonReader(reader));
  8. }
  9. private static boolean isJsonValid(final JsonReader jsonReader)
  10. throws IOException {
  11. try {
  12. JsonToken token;
  13. loop:
  14. while ( (token = jsonReader.peek()) != END_DOCUMENT && token != null ) {
  15. switch ( token ) {
  16. case BEGIN_ARRAY:
  17. jsonReader.beginArray();
  18. break;
  19. case END_ARRAY:
  20. jsonReader.endArray();
  21. break;
  22. case BEGIN_OBJECT:
  23. jsonReader.beginObject();
  24. break;
  25. case END_OBJECT:
  26. jsonReader.endObject();
  27. break;
  28. case NAME:
  29. jsonReader.nextName();
  30. break;
  31. case STRING:
  32. case NUMBER:
  33. case BOOLEAN:
  34. case NULL:
  35. jsonReader.skipValue();
  36. break;
  37. case END_DOCUMENT:
  38. break loop;
  39. default:
  40. throw new AssertionError(token);
  41. }
  42. }
  43. return true;
  44. } catch ( final MalformedJsonException ignored ) {
  45. return false;
  46. }
  47. }

然后测试它:

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

输出量:
真的
假的

展开查看全部
qaxu7uf2

qaxu7uf22#

我找到了解决方案,但使用org.json库,根据如何检查给定字符串是否为Java中的有效JSON

  1. public static boolean isJson(String Json) {
  2. try {
  3. new JSONObject(Json);
  4. } catch (JSONException ex) {
  5. try {
  6. new JSONArray(Json);
  7. } catch (JSONException ex1) {
  8. return false;
  9. }
  10. }
  11. return true;
  12. }

现在随机字符串bncjbhjfjhjfalse{"status": "UP"}是真。

xiozqbni

xiozqbni3#

虽然你可能觉得奇怪

  1. "bncjbhjfjhj"

确实是有效的json,因为它是一个字符串,并且是它的唯一字符串。
根据不那么新的JSON RFC
JSON文本是一个序列化的值。请注意,某些以前的JSON规范将JSON文本限制为对象或数组。在调用JSON文本的地方只生成对象或数组的实现将是可互操作的,因为所有实现都将接受这些对象或数组作为一致的JSON文本。

eanckbw9

eanckbw94#

我很惊讶当GsonBuilder#setLenient声明
默认情况下,Gson是严格的,只接受RFC 4627指定的JSON。这个选项使解析器可以自由接受。
它看起来是彻头彻尾的谎言,实际上它总是很宽容。而且,甚至任何对JsonReader.setLenient(false)的调用都被完全忽略!
在浏览了一些与numerous相关的issuesseveralrejectedpull请求后,“由于传统的兼容性原因”,我终于找到了具有合理解决方案的https://github.com/google/gson/issues/1208
JakeWharton于2017年12月15日发表评论
你可以调用getAdapter(type).fromJson(gson.newJsonReader(input))而不是仅仅调用fromJson(input)来获得严格的解析。我们真的应该弃用所有的fromJson方法,并添加默认情况下严格的新版本。
原因是很久以前的错误决定使我们再也无法改变;(
因此,这里是一个纯Gson解决方案,用于严格的json对象解析和大量的测试用例。

  1. import org.junit.Test;
  2. import com.google.gson.*;
  3. import com.google.gson.stream.JsonReader;
  4. import static org.junit.Assert.*;
  5. public class JsonTest {
  6. private static final TypeAdapter<JsonObject> strictGsonObjectAdapter =
  7. new Gson().getAdapter(JsonObject.class);
  8. public static JsonObject parseStrict(String json) {
  9. // https://stackoverflow.com/questions/43233898/how-to-check-if-json-is-valid-in-java-using-gson/47890960#47890960
  10. try {
  11. //return strictGsonObjectAdapter.fromJson(json); // this still allows multiple top level values (
  12. try (JsonReader reader = new JsonReader(new StringReader(json))) {
  13. JsonObject result = strictGsonObjectAdapter.read(reader);
  14. reader.hasNext(); // throws on multiple top level values
  15. return result;
  16. }
  17. } catch (IOException e) {
  18. throw new JsonSyntaxException(e);
  19. }
  20. }
  21. @Test
  22. public void testStrictParsing() {
  23. // https://static.javadoc.io/com.google.code.gson/gson/2.8.5/com/google/gson/stream/JsonReader.html#setLenient-boolean-
  24. // Streams that start with the non-execute prefix, ")]}'\n".
  25. assertThrows(JsonSyntaxException.class, () -> parseStrict("){}"));
  26. assertThrows(JsonSyntaxException.class, () -> parseStrict("]{}"));
  27. assertThrows(JsonSyntaxException.class, () -> parseStrict("}{}"));
  28. // Streams that include multiple top-level values. With strict parsing, each stream must contain exactly one top-level value.
  29. assertThrows(JsonSyntaxException.class, () -> parseStrict("{}{}"));
  30. assertThrows(JsonSyntaxException.class, () -> parseStrict("{}[]null"));
  31. // Top-level values of any type. With strict parsing, the top-level value must be an object or an array.
  32. assertThrows(JsonSyntaxException.class, () -> parseStrict(""));
  33. assertThrows(JsonSyntaxException.class, () -> parseStrict("null"));
  34. assertThrows(JsonSyntaxException.class, () -> parseStrict("Abracadabra"));
  35. assertThrows(JsonSyntaxException.class, () -> parseStrict("13"));
  36. assertThrows(JsonSyntaxException.class, () -> parseStrict("\"literal\""));
  37. assertThrows(JsonSyntaxException.class, () -> parseStrict("[]"));
  38. // Numbers may be NaNs or infinities.
  39. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"number\": NaN}"));
  40. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"number\": Infinity}"));
  41. // End of line comments starting with // or # and ending with a newline character.
  42. assertThrows(JsonSyntaxException.class, () -> parseStrict("{//comment\n}"));
  43. assertThrows(JsonSyntaxException.class, () -> parseStrict("{#comment\n}"));
  44. // C-style comments starting with /* and ending with */. Such comments may not be nested.
  45. assertThrows(JsonSyntaxException.class, () -> parseStrict("{/*comment*/}"));
  46. // Names that are unquoted or 'single quoted'.
  47. assertThrows(JsonSyntaxException.class, () -> parseStrict("{a: 1}"));
  48. assertThrows(JsonSyntaxException.class, () -> parseStrict("{'a': 1}"));
  49. // Strings that are unquoted or 'single quoted'.
  50. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": str}"));
  51. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": ''}"));
  52. // Array elements separated by ; instead of ,.
  53. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": [1;2]}"));
  54. // Unnecessary array separators. These are interpreted as if null was the omitted value.
  55. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": [1,]}"));
  56. // Names and values separated by = or => instead of :.
  57. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\" = 13}"));
  58. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\" => 13}"));
  59. // Name/value pairs separated by ; instead of ,.
  60. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": 1; \"b\": 2}"));
  61. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": }"));
  62. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": ,}"));
  63. assertThrows(JsonSyntaxException.class, () -> parseStrict("{\"a\": 0,}"));
  64. assertTrue(parseStrict("{} ").entrySet().isEmpty());
  65. assertTrue(parseStrict("{\"a\": null} \n \n").get("a").isJsonNull());
  66. assertEquals(0, parseStrict("{\"a\": 0}").get("a").getAsInt());
  67. assertEquals("", parseStrict("{\"a\": \"\"}").get("a").getAsString());
  68. assertEquals(0, parseStrict("{\"a\": []}").get("a").getAsJsonArray().size());
  69. }
  70. }

请注意,这确保了单个顶级对象。可以将JsonObject.class替换为JsonArray.classJsonElement.class,以允许顶级数组或null
上面的代码将JSON解析为JsonObject DOM表示。
下面的代码使用常规字段Map对自定义POJO进行严格解析。

  1. // https://github.com/google/gson/issues/1208
  2. private static final TypeAdapter<Pojo> strictGsonAdapter = new Gson().getAdapter(Pojo.class);
  3. public static Pojo parsePayment(String json) throws IOException {
  4. return strictGsonAdapter.fromJson(json);
  5. }
展开查看全部
t5fffqht

t5fffqht5#

这对我有用

  1. public static boolean isJson(String Json) {
  2. Gson gson = new Gson();
  3. try {
  4. gson.fromJson(Json, Object.class);
  5. Object jsonObjType = gson.fromJson(Json, Object.class).getClass();
  6. if(jsonObjType.equals(String.class)){
  7. return false;
  8. }
  9. return true;
  10. } catch (com.google.gson.JsonSyntaxException ex) {
  11. return false;
  12. }
  13. }
eivnm1vs

eivnm1vs6#

如果您只想验证输入是否为有效的JSON,而不使用解析后的JSON数据,那么最简单且可能性能最高的解决方案是:

  1. public static boolean isValidJson(String input) {
  2. try (JsonReader reader = new JsonReader(new StringReader(input))) {
  3. reader.skipValue();
  4. return reader.peek() == JsonToken.END_DOCUMENT;
  5. } catch (IOException e) {
  6. return false;
  7. }
  8. }

但是请注意,即使JsonReader在非宽松模式下也允许某些根据规范无效的JSON字符串,请参见JsonReader.setLenient(boolean)的文档,其中列出了这些情况。
使用GsonJsonParser的所有其他解决方案可能无法正常工作,因为这些类在默认情况下是宽松的,并且无法配置此行为。

相关问题