如何在Java中检查给定的字符串是否为有效的JSON格式

206

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


尝试使用Gson解析?通过正则表达式进行验证可能不是一个好主意。 - aishwarya
2
http://www.json.org 上有很多解析器的链接。 - MartinK
20个回答

320

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

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实现,可在GitHub上、Maven中以及部分适用于Android平台


2
它接近完成,但缺少对JSONArray的验证(我已更新此帖子以使用更合适的函数)。 - Arthur
12
我尝试了一个类似于“{'hello':'foo'} 'invalid'”(在{}外添加了'invalid')的json字符串,但JSONObject没有抛出ParseException异常。我正在使用org.json.JSONObject。这是正常情况吗? - Soichi Hayashi
18
你没有提到具有JSONObject的库,我在标准的Java库中没有看到它。 - Krzysztof Krasoń
7
这个解决方案适用于大多数情况,但在某些情况下可能会失败。例如,它允许在闭括号之前放置逗号,这实际上是一种语法错误。请参考http://www.json.org/javadoc/org/json/JSONObject.html了解其他特殊情况。 - Hua2308
10
我不明白为什么张贴者不愿意在代码片段中包含导入语句,这是很重要的。这里的第二个答案要好得多。 - seansand
显示剩余18条评论

125

JACKSON Library

使用Jackson库是其中之一选择。首先导入最新版本(目前为止):

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

那么,您可以按照正确答案的方式进行实现:

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 - Ch4ni
1
这个也验证 { key: value },但它不是有效的 JSON。 - Pratapi Hemant Patel
5
JACKSON陷阱:new ObjectMapper().readTree("28xjRBuOQqupRopHeSuhRQ")解析时没有抛出异常,而是将其解析为IntNode(28)。这并不是预期的结果... - mgaert
1
据我理解,这个解决方案不仅验证,而且解析(并存储)整个JSON。它将数字转换为Integer / Long / Double等。这不仅仅是语法检查,它还将整个JSON存储在内存中。这对于高负载可能非常重要。如果存在更好的语法检查解决方案呢? - Oleg Vazhnev
2
请注意,此处的gson示例使用宽松模式解析,仍允许许多偏差。请参阅我的其他答案中的更多详细信息和测试用例严格解析示例 - Vadzim
显示剩余3条评论

16

使用Google Gson,您可以使用JsonParser:

import com.google.gson.JsonParser;

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

3
请注意,这不会对未加方括号的字符串(例如"asdf")抛出错误。 - Andrew
1
它也不会拒绝在JSON数组中使用尾随逗号。 - Sotirios Delimanolis
我真的不能信任那个...它说字符串“保存”是可解析的。 - Dherik
请注意,此处的gson示例使用宽松模式解析,仍允许许多偏差。请参阅我的其他答案中的更多详细信息和测试用例严格解析示例 - Vadzim

15

是的,这个可行。谢谢 npinti。我之前试过用 gson,但没有看到这样的方法。 - sappu
如果这个答案解决了你的问题,请标记一下。大多数库倾向于输入一个字符串并尝试解析它,如果解析失败,也就是说,字符串不是一个有效的JSON字符串,它会抛出一个异常。 - npinti
3
这种方法只是简单地检查字符串是否以引号或括号开头和结尾。非常不可靠。 - Michael Munsey
3
这就是为什么这个方法被命名为“maybe”,而不是“is” :) - Khoa
当先测试后解析时,以下代码非常有用:if ! .mayBeJSON(str){ log(str as error)}else{ parseJSON(str)} - Yu Jiaao
显示剩余2条评论

5
取决于您的验证需要证明什么。确实,像其他人建议的那样解析json比使用正则表达式更好,因为json的语法比只能用正则表达式表示的语法更复杂。
如果json只会被您的java代码解析,那么请使用相同的解析器来验证它。
但是仅仅解析并不能告诉您它是否会在其他环境中被接受。例如:
- 许多解析器忽略对象或数组中的尾随逗号,但旧版本的IE在遇到尾随逗号时可能会失败。 - 其他解析器可能接受尾随逗号,但在其后添加未定义/空条目。 - 一些解析器可能允许未引用的属性名称。 - 一些解析器可能对字符串中的非ASCII字符有不同的反应。
如果您的验证需要非常彻底,您可以:

4

关于解析的一些信息:

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

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

如果您准备编写自己的解析器
您可以在确定语法后制作递归下降解析器。


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

请下载stringtree-json库。

能否像上面那样定义一个字符串?还是只是为了想法而已? - Santron Manibharathi
不可能的,那是我的错误。现在已经更正了。谢谢。 - Jamsheer
1
JSONValidatingReader不是Java API的一部分。 - IgorGanapolsky
请使用上述提到的库,谢谢。 - Jamsheer

4

检查给定的字符串是否是有效的 JSON,在 Kotlin 中。我将 MByD 的 Java 答案转换成了 Kotlin。

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

4

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

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

请参阅我在如何使用GSON在Java中检查JSON是否有效的其他详细答案,其中包含更多信息和各种非有效示例的扩展测试用例。


1
谢谢!这似乎是我尝试过的所有答案中提供最严格验证的。 - Fan Li

3
答案部分正确。我也遇到了同样的问题。解析json并检查异常似乎是通常的方法,但对于输入的json格式不正确的情况,该解决方案会失败,例如:

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

正如您所看到的,由于存在尾随垃圾字符,该json格式不正确。但是,如果您尝试使用jackson或gson解析上述json,则会获得有效json的解析映射,并且忽略垃圾尾随字符。这不是在使用解析器检查json有效性时所需的解决方案。

有关此问题的解决方案,请参见此处

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接