概述

在Java中处理原始JSON值时,有时我们需要检查其有效性。有许多库可以帮助我们:GsonJSON APIJackson。每个工具都有其独特的优点和限制。

本教程将使用每种工具实现JSON字符串验证,并详细比较它们在实践中的主要差异。

2. JSON API 验证

JSON API是最轻量级且简单的库。

通常,检查一个String是否是有效的JSON的方法是异常处理。因此,我们委托JSON解析并在值不正确时处理特定类型的错误,或者如果没有异常发生,假设值是正确的

2.1. Maven依赖

首先,我们需要在pom.xml中添加json依赖:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20211205</version>
</dependency>

2.2. 使用JSONObject验证

首先,我们要尝试创建一个JSONObject来检查String是否为JSON。如果值无效,我们将得到一个JSONException:

public boolean isValid(String json) {
    try {
        new JSONObject(json);
    } catch (JSONException e) {
        return false;
    }
    return true;
}

让我们用一个简单例子来尝试:

String json = "{\"email\": \"example@com\", \"name\": \"John\"}";
assertTrue(validator.isValid(json));
String json = "Invalid_Json"; 
assertFalse(validator.isValid(json));

然而,这种方法的缺点是,使用JSONObjectString只能表示对象,不能表示数组。

例如,看它如何处理数组:

String json = "[{\"email\": \"example@com\", \"name\": \"John\"}]";
assertFalse(validator.isValid(json));

2.3. 使用JSONArray验证

为了无论String是对象还是数组都能进行验证,我们需要在创建JSONObject失败时添加额外的条件。同样,如果String不适合作为JSON数组,JSONArray也会抛出JSONException:

public boolean isValid(String json) {
    try {
        new JSONObject(json);
    } catch (JSONException e) {
        try {
            new JSONArray(json);
        } catch (JSONException ne) {
            return false;
        }
    }
    return true;
}

因此,我们可以验证任何值:

String json = "[{\"email\": \"example@com\", \"name\": \"John\"}]";
assertTrue(validator.isValid(json));

3. Jackson 验证

Jackson库也提供了基于异常处理的JSON验证方式。它是一个功能更强大的工具,具有多种解析策略,但使用起来更为方便。

3.1. Maven依赖

接下来,我们在项目中添加jackson-databind Maven依赖:

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

3.2. 使用ObjectMapper验证

我们使用readTree()方法读取整个JSON,如果语法不正确,会抛出JacksonException

换句话说,我们不需要额外的检查。它适用于对象和数组:

ObjectMapper mapper = new ObjectMapper()
  .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
  .build()

public boolean isValid(String json) {
    try {
        mapper.readTree(json);
    } catch (JacksonException e) {
        return false;
    }
    return true;
}

让我们用例子来看看如何使用:

String json = "{\"email\": \"example@com\", \"name\": \"John\"}";
assertTrue(validator.isValid(json));

String json = "[{\"email\": \"example@com\", \"name\": \"John\"}]";
assertTrue(validator.isValid(json));

String json = "Invalid_Json";
assertFalse(validator.isValid(json));

注意,我们还启用了FAIL_ON_TRAILING_TOKENS选项,确保如果有效JSON后跟有非空白文本,验证会失败。

如果没有这个选项,形式为{“email”:”example@com”}text的JSON仍然会被认为是有效的,尽管它不符合规范。

4. Gson 验证

Gson是另一个常用库,允许我们使用相同的方法验证原始JSON值。这是一个复杂的工具,用于Java对象与各种JSON处理方式的映射。

4.1. Maven依赖

现在添加gson Maven依赖:

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

4.2. 非严格验证

Gson提供了JsonParser将指定JSON读入一个JsonElement树。因此,如果在读取过程中出现错误,它将保证我们收到JsonSyntaxException

我们可以使用parse()方法计算String并处理异常,以处理格式错误的JSON值:

public boolean isValid(String json) {
    try {
        JsonParser.parseString(json);
    } catch (JsonSyntaxException e) {
        return false;
    }
    return true;
}

让我们编写一些测试来检查主要情况:

String json = "{\"email\": \"example@com\", \"name\": \"John\"}";
assertTrue(validator.isValid(json));

String json = "[{\"email\": \"example@com\", \"name\": \"John\"}]";
assertTrue(validator.isValid(json));

这种方法的主要区别在于,Gson默认策略认为单独的字符串和数字值作为JsonElement节点是有效的。也就是说,单个字符串或数字也被视为有效。

例如,看它是如何处理单个字符串的:

String json = "Invalid_Json";
assertTrue(validator.isValid(json));

然而,如果我们希望将此类值视为格式错误,我们需要在JsonParser上强制执行严格的类型策略。

4.3. 严格验证

为了实现严格的类型策略,我们需要创建一个TypeAdapter并定义JsonElement类为所需类型匹配。结果,JsonParser将在遇到非JSON对象或数组类型时抛出JsonSyntaxException

我们可以使用特定的TypeAdapter调用fromJson()方法来读取原始JSON:

final TypeAdapter<JsonElement> strictAdapter = new Gson().getAdapter(JsonElement.class);

public boolean isValid(String json) {
    try {
        strictAdapter.fromJson(json);
    } catch (JsonSyntaxException | IOException e) {
        return false;
    }
    return true;
}

最后,我们可以检查JSON是否有效:

String json = "Invalid_Json";
assertFalse(validator.isValid(json));

5. 总结

在这篇文章中,我们了解了不同的方法来检查String是否是有效的JSON。

每个方法都有其优缺点。虽然JSON API适合于简单的对象验证,但Gson对于作为JSON对象部分的原始值验证可能更具扩展性。然而,Jackson使用起来更方便。因此,我们应该选择最适合的那一个。

此外,我们还应检查是否有现成的库已在使用,或者是否适用于其他目标。

如往常一样,示例代码可以在GitHub上找到。