我有方法必须检查JSON是否有效,可以在如何检查给定字符串是否是Java中的有效JSON但是它不起作用.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我将这个方法与一些字符串一起使用,它总是返回true.例如:
System.out.println(renderHtml.isJson("{\"status\": \"UP\"}"));
Run Code Online (Sandbox Code Playgroud)
它给了我true
,而且
System.out.println(renderHtml.isJson("bncjbhjfjhj"));
Run Code Online (Sandbox Code Playgroud)
true
也给了我.
虽然这对你来说可能很奇怪
"bncjbhjfjhj"
Run Code Online (Sandbox Code Playgroud)
确实是有效的json,因为它是一个字符串,它是唯一的字符串.
根据不那么新的JSON RFC
JSON文本是序列化值.请注意,某些先前的JSON规范将JSON文本约束为对象或数组.只生成调用JSON文本的对象或数组的实现将是可互操作的,因为所有实现都将接受这些作为符合JSON文本.
您不应该使用Gson
这种验证:
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());
Run Code Online (Sandbox Code Playgroud)
输出:
com.google.gson.internal.LinkedTreeMap
类java.lang.String类
您可以在这里使用的方法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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后测试一下:
System.out.println(isJsonValid(VALID_JSON));
System.out.println(isJsonValid(INVALID_JSON));
Run Code Online (Sandbox Code Playgroud)
输出:
真
假
我很惊讶虽然GsonBuilder#setLenient
声明
默认情况下,Gson 是严格的,仅接受RFC 4627指定的 JSON 。此选项使解析器可以自由地接受它。
这看起来是彻头彻尾的谎言,但实际上总是很宽容。而且,甚至任何调用都JsonReader.setLenient(false)
被完全忽略!
在浏览了许多 相关 问题和几个 “由于遗留兼容性原因”而被拒绝的 拉取请求之后,我终于找到了https://github.com/google/gson/issues/1208以及合理的解决方法:
杰克沃顿于 2017 年 12 月 15 日发表评论
您可以调用 getAdapter(type).fromJson(gson.newJsonReader(input)) 而不是仅仅 fromJson(input) 来获得严格的解析。我们确实应该弃用所有 fromJson 方法并添加默认严格的新版本。
原因是很久以前就做出了错误的决定,我们无法再改变;(
所以这里是纯 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) {
// /sf/ask/3026372891/#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());
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这确保了单个顶级对象。可以替换JsonObject.class
为JsonArray.class
或JsonElement.class
允许顶级数组或null。
上面的代码将 JSON 解析为JsonObject
DOM 表示。
下面的代码使用常规字段映射严格解析为自定义 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);
}
Run Code Online (Sandbox Code Playgroud)
我找到了解决方案,但使用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;
}
Run Code Online (Sandbox Code Playgroud)
现在看起来随机的字符串bncjbhjfjhj
是false
并且{"status": "UP"}
是真的。