【问题标题】:How to check whether a given string is valid JSON in Java如何检查给定字符串是否是Java中的有效JSON
【发布时间】:2012-04-27 19:53:08
【问题描述】:

如何在 Java 中验证 JSON 字符串?或者我可以使用正则表达式解析它吗?

【问题讨论】:

  • 尝试用 gson 解析?通过正则表达式验证可能不是一个好主意
  • json.org 有很多解析器的链接

标签: java json validation


【解决方案1】:

一个疯狂的想法,尝试解析它并捕获异常:

import org.json.*;

public boolean isJSONValid(String test) {
    try {
        new JSONObject(test);
    } catch (JSONException ex) {
        // edited, to include @Arthur's comment
        // e.g. in case JSONArray is valid as well...
        try {
            new JSONArray(test);
        } catch (JSONException ex1) {
            return false;
        }
    }
    return true;
}

此代码使用org.json JSON API 实现,可用on githubin maven 和部分on Android

【讨论】:

  • 它很接近,但缺少对 JSONArray 的验证(我已经用更合适的功能更新了这篇文章)
  • 我已经尝试过像“{'hello':'foo'} 'invalid'”这样的 json 字符串(在 {} 之外添加了 'invalid'),并且 JSONObject 没有抛出 ParseException。我正在使用 org.json.JSONObject。这是预期的吗?
  • 你没有提到有 JSONObject 的库,我没有在标准 java 库中看到它
  • 此解决方案适用于大多数情况,但在某些情况下可能会失败。例如,它允许在右大括号之前使用逗号,这实际上是一个语法错误。其他极端情况请参阅json.org/javadoc/org/json/JSONObject.html
  • 我不明白为什么发帖者懒得在代码 sn-ps 中包含 import 语句。这里很重要。这里的二等答案好多更好。
【解决方案2】:

杰克逊图书馆

一种选择是使用Jackson library。先导入最新版本(现在是):

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.0</version>
</dependency>

然后,您可以按如下方式实现correct answer

import com.fasterxml.jackson.databind.ObjectMapper;

public final class JSONUtils {
  private JSONUtils(){}

  public static boolean isJSONValid(String jsonInString ) {
    try {
       final ObjectMapper mapper = new ObjectMapper();
       mapper.readTree(jsonInString);
       return true;
    } catch (IOException e) {
       return false;
    }
  }
}

Google GSON 选项

另一种选择是使用Google Gson。导入依赖:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.5</version>
</dependency>

同样,您可以将建议的解决方案实现为:

import com.google.gson.Gson;

public final class JSONUtils {
  private static final Gson gson = new Gson();

  private JSONUtils(){}

  public static boolean isJSONValid(String jsonInString) {
      try {
          gson.fromJson(jsonInString, Object.class);
          return true;
      } catch(com.google.gson.JsonSyntaxException ex) { 
          return false;
      }
  }
}

下面是一个简单的测试:

//A valid JSON String to parse.
String validJsonString = "{ \"developers\": [{ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
        "{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";

// Invalid String with a missing parenthesis at the beginning.
String invalidJsonString = "\"developers\": [ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
        "{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";

boolean firstStringValid = JSONUtils.isJSONValid(validJsonString); //true
boolean secondStringValid = JSONUtils.isJSONValid(invalidJsonString); //false

请注意,由于尾随逗号可能存在​​一个“小”问题,该问题将在版本 3.0.0 中修复。

【讨论】:

  • 虽然这适用于诸如不匹配的引号或缺少括号之类的大问题,但 Gson 会很乐意解析带有尾随逗号的 json 数组,这不符合 RFC-4627
  • 这也验证了 { key: value },但它不是一个有效的 json
  • JACKSON 陷阱:new ObjectMapper().readTree("28xjRBuOQqupRopHeSuhRQ") 无异常解析为 IntNode(28)。没想到...
  • 据我了解,此解决方案不仅验证,而且解析(并存储)整个 json。它将数字转换为 Integer/Long/Double 等。这不仅仅是语法检查,它将整个 json 存储在内存中。这对于密集负载可能很重要。是否存在更好的语法检查解决方案?
  • 请注意这里的 gson 示例使用 lenient 解析模式,它仍然允许许多偏差。请参阅我的其他答案中的more details with testcasestrict parsing example
【解决方案3】:

有了Google Gson,你可以使用JsonParser:

import com.google.gson.JsonParser;

JsonParser parser = new JsonParser();
parser.parse(json_string); // throws JsonSyntaxException

【讨论】:

  • 请注意,这不会在无括号的字符串 ala "asdf" 上引发错误
  • 它也不拒绝 JSON 数组中的尾随逗号。
  • 我真的不能相信...它说字符串“Save”是可解析的。
  • 请注意这里的 gson 示例使用 lenient 解析模式,它仍然允许许多偏差。请参阅我的其他答案中的more details with testcasestrict parsing example
【解决方案4】:

您可以使用JSONUtils 库中提供的.mayBeJSON(String str)

【讨论】:

  • 是的...这是有效的。谢谢 npinti。我正在尝试使用 gson,但我没有见过这样的方法。
  • @sappu:如果此答案解决了您的问题,请标记为。大多数库倾向于接受一个String并尝试解析它,如果解析失败,即该字符串不是有效的JSON字符串,则会抛出异常。
  • @npinti: 额外 } 失败。对于带有额外括号的无效字符串返回 true => }
  • 这个方法实际上只检查字符串是否以引号或括号开头和结尾。非常不可靠。
  • 这就是为什么方法名称是“可能”而不是“是”的原因:)
【解决方案5】:

这取决于您要通过验证来证明什么。 当然,按照其他人的建议解析 json 比使用正则表达式更好,因为 json 的语法比仅用正则表达式表示的要复杂。

如果 json 只会被你的 java 代码解析,那么使用相同的解析器来验证它。

但是仅仅解析并不一定会告诉你它是否会在其他环境中被接受。例如

  • 许多解析器会忽略对象或数组中的尾随逗号,但旧版本的 IE 在遇到尾随逗号时可能会失败。
  • 其他解析器可以接受尾随逗号,但在其后添加未定义/空条目。
  • 某些解析器可能允许不带引号的属性名称。
  • 某些解析器可能会对字符串中的非 ASCII 字符做出不同的反应。

如果您的验证需要非常彻底,您可以:

【讨论】:

    【解决方案6】:

    关于解析的一点:

    Json,实际上是所有语言,都使用 grammar,这是一组可以用作替换的规则。为了解析 json,您基本上需要反向解决这些替换

    Json 是一种上下文无关语法,这意味着您可以拥有无​​限嵌套的对象/数组,并且 json 仍然有效。正则表达式仅处理正则语法(因此名称中的“reg”),它是不允许无限嵌套的上下文无关语法的子集,因此不可能仅使用正则表达式来解析所有有效的json。您可以使用一组复杂的正则表达式和循环,假设没有人会嵌套超过 100 层,但这仍然非常困难。

    如果您准备编写自己的解析器
    搞定语法后,你可以做一个递归下降解析器

    【讨论】:

      【解决方案7】:
      String jsonInput = "{\"mob no\":\"9846716175\"}";//Read input Here
      JSONReader reader = new JSONValidatingReader();
      Object result = reader.read(jsonInput);
      System.out.println("Validation Success !!");
      

      请下载stringtree-json

      【讨论】:

      • 是否可以像上面那样定义一个字符串?或者它只是为了想法。
      • 不可能,这是由于我的错误。现在已更正。谢谢
      • JSONValidatingReader 不是 Java API 的一部分
      • 请使用上述库,谢谢
      【解决方案8】:

      这是一个使用 gson 库进行严格 json 解析的工作示例:

      public static JsonElement parseStrict(String json) {
          // throws on almost any non-valid json
          return new Gson().getAdapter(JsonElement.class).fromJson(json); 
      }
      

      另请参阅我在How to check if JSON is valid in Java using GSON 中的其他详细答案,其中包含更多信息和带有各种无效示例的扩展测试用例。

      【讨论】:

      • 谢谢!在我尝试的所有答案中,这似乎提供了最严格的验证。
      【解决方案9】:

      答案部分正确。我也面临同样的问题。解析 json 并检查异常似乎是常用的方法,但输入 json 的解决方案失败,例如

      {"outputValueSchemaFormat": "","sortByIndexInRecord": 0,"sortOrder":847874874387209"descending"}kajhfsadkjh

      正如你所见,json 是无效的,因为有尾随的垃圾字符。但是,如果您尝试使用 jackson 或 gson 解析上述 json,那么您将获得有效 json 的解析映射,并且垃圾尾随字符将被忽略。当您使用解析器检查 json 有效性时,这不是必需的解决方案。

      有关此问题的解决方案,请参阅here

      PS:这个问题是我提出并回答的。

      【讨论】:

        【解决方案10】:

        检查给定字符串是否是 Kotlin 中的有效 JSON。我将MByDJava 的答案转换为 Kotlin

        fun isJSONValid(test: String): Boolean {
            try {
                JSONObject(test);
            } catch (ex: JSONException) {
                try {
                    JSONArray(test);
                } catch (ex1: JSONException) {
                    return false;
                }
            }
            return true;
        }
        

        【讨论】:

          【解决方案11】:

          使用javax.json 库的解决方案:

          import javax.json.*;
          
          public boolean isTextJson(String text) {
              try {
                  Json.createReader(new StringReader(text)).readObject();
              } catch (JsonException ex) {
                  try {
                      Json.createReader(new StringReader(text)).readArray();
                  } catch (JsonException ex2) {
                      return false;
                  }
              }
              return true;
          }
          

          【讨论】:

          • 请问为什么你们两个不同的读者。我试过Json.createReader(new StringReader(text)).read(),它似乎工作正常。有没有失败的情况?
          • @Knu8 我认为使用read 也应该完全正常。
          【解决方案12】:

          在这里您可以找到可以验证 JSON 文件的tool,或者您可以使用任何 JSON 库反序列化您的 JSON 文件,如果操作成功,那么它应该是有效的(例如,google-json 会抛出如果它正在解析的输入不是有效的 JSON,则会出现异常)。

          【讨论】:

            【解决方案13】:

            使用 Playframework 2.6,java api 中的 Json 库也可以用来简单地解析字符串。该字符串可以是 json 数组的 json 元素。由于返回的值在这里并不重要,我们只是捕获解析错误来确定该字符串是否为正确的 json 字符串。

                import play.libs.Json;
            
                public static Boolean isValidJson(String value) {
                    try{
                        Json.parse(value);
                        return true;
                    } catch(final Exception e){
                        return false;
                    }
                }
            

            【讨论】:

              【解决方案14】:

              恕我直言,最优雅的方式是使用 Java API for JSON Processing (JSON-P),这是符合 JSR 的 JavaEE 标准之一374

              try(StringReader sr = new StringReader(jsonStrn)) {
                  Json.createReader(sr).readObject();
              } catch(JsonParsingException e) {
                  System.out.println("The given string is not a valid json");
                  e.printStackTrace();
              }
              

              使用Maven,添加对JSON-P的依赖:

              <dependency>
                  <groupId>org.glassfish</groupId>
                  <artifactId>javax.json</artifactId>
                  <version>1.1.4</version>
              </dependency>
              

              访问the JSON-P official page了解更多信息。

              【讨论】:

                【解决方案15】:

                如您所见,有很多解决方案,他们主要是解析 JSON 来检查它,最后您必须解析它才能确定。

                但是,根据具体情况,您可以通过预先检查来提高性能。

                我在调用 API 时所做的只是检查第一个字符是否为“{”,最后一个字符是否为“}”。如果不是这样,我不会费心创建解析器。

                【讨论】:

                  【解决方案16】:

                  我找到了一个非常简单的解决方案。

                  请先为它安装这个库net.sf.json-lib

                      import net.sf.json.JSONException;
                  
                      import net.sf.json.JSONSerializer;
                  
                      private static boolean isValidJson(String jsonStr) {
                          boolean isValid = false;
                          try {
                              JSONSerializer.toJSON(jsonStr);
                              isValid = true;
                          } catch (JSONException je) {
                              isValid = false;
                          }
                          return isValid;
                      }
                  
                      public static void testJson() {
                          String vjson = "{\"employees\": [{ \"firstName\":\"John\" , \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
                          String ivjson = "{\"employees\": [{ \"firstName\":\"John\" ,, \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
                          System.out.println(""+isValidJson(vjson)); // true
                          System.out.println(""+isValidJson(ivjson)); // false
                      }
                  

                  完成。享受

                  【讨论】:

                    【解决方案17】:
                    import static net.minidev.json.JSONValue.isValidJson;
                    

                    然后调用这个函数,传入你的 JSON 字符串 :)

                    【讨论】:

                      【解决方案18】:
                      public static boolean isJSONValid(String test) {
                          try {
                              isValidJSON(test);
                              JsonFactory factory = new JsonFactory();
                              JsonParser parser = factory.createParser(test);
                              while (!parser.isClosed()) {
                                  parser.nextToken();
                              }
                          } catch (Exception e) {
                              LOGGER.error("exception: ", e);
                              return false;
                          }
                          return true;
                      }
                      
                      private static void isValidJSON(String test) {
                          try {
                              new JSONObject(test);
                          } catch (JSONException ex) {
                              try {
                                  LOGGER.error("exception: ", ex);
                                  new JSONArray(test);
                              } catch (JSONException ex1) {
                                  LOGGER.error("exception: ", ex1);
                                  throw new Exception("Invalid JSON.");
                              }
                          }
                      }
                      

                      以上解决方案涵盖了这两种情况:

                      • 重复键
                      • 不匹配的引号或缺少括号等。

                      【讨论】:

                        【解决方案19】:

                        你可以试试下面的代码,对我有用:

                         import org.json.JSONObject;
                         import org.json.JSONTokener;
                        
                         public static JSONObject parseJsonObject(String substring)
                         {
                          return new JSONObject(new JSONTokener(substring));
                         }
                        

                        【讨论】:

                          【解决方案20】:

                          您可以使用Validol 声明式验证库中的WellFormedJson 类。

                          声明本身可能如下所示:

                          new WellFormedJson(
                              new Unnamed<>(Either.right(new Present<>(jsonRequestString)))
                          )
                          

                          检查阶段如下所示:

                              Result<JsonElement> result =
                                  (new WellFormedJson(
                                      new Named<>(
                                          "vasya",
                                          Either.right(
                                              new Present<>(
                                                  "{\"guest\":{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"},\"source\":1,\"items\":[{\"id\":1900},{\"id\":777}]}"
                                              )
                                          )
                                      )
                                  ))
                                      .result();
                          
                              assertTrue(result.isSuccessful());
                              assertEquals(
                                  "{\"guest\":{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"},\"source\":1,\"items\":[{\"id\":1900},{\"id\":777}]}",
                                  result.value().raw().toString()
                              );
                              assertEquals(
                                  "{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"}",
                                  result.value().raw().getAsJsonObject().get("guest").toString()
                              );
                          

                          对于这样一个简单的任务来说,这似乎有点过头了,但当您必须验证一个复杂的请求时,它就会大放异彩。查看validol的quick start section

                          【讨论】:

                          • 试过 Validol,它说这是一个有效的 Json:{"a": halfQuotedString"}
                          猜你喜欢
                          • 2013-02-13
                          • 2015-05-23
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-12-15
                          • 2022-01-19
                          • 2011-07-27
                          • 1970-01-01
                          相关资源
                          最近更新 更多