我需要在Groovy中检查字符串是否是有效的JSON。我的第一个想法是通过new JsonSlurper().parseText(myString)
发送它,如果没有例外,则认为它是正确的。
但是,我发现Groovy很乐意接受带有JsonSlurper
的尾随逗号,但是JSON doesn't allow trailing commas。有没有一种简单的方法来验证Groovy中的JSON是否符合官方JSON规范?
答案 0 :(得分:3)
JsonSlurper
类使用JsonParser
接口实现(JsonParserCharArray
是默认接口)。这些解析器通过char检查char是什么是当前字符以及它代表什么类型的令牌类型。如果您查看第139行的JsonParserCharArray.decodeJsonObject()
方法,您会看到如果解析器看到}
字符,它会中断循环并完成解码JSON对象并忽略}
之后存在的任何内容。
这就是为什么如果在JSON对象前放置任何无法识别的字符,JsonSlurper
将抛出异常。但是如果你在}
之后用任何不正确的字符结束你的JSON字符串,它将会通过,因为解析器甚至不考虑这些字符。
您可以考虑使用JsonOutput.prettyPrint(String json)
方法,如果涉及它尝试打印的JSON,则使用更为严格的方法(它使用JsonLexer
以流方式读取JSON令牌)。如果你这样做:
def jsonString = '{"name": "John", "data": [{"id": 1},{"id": 2}]}...'
JsonOutput.prettyPrint(jsonString)
它会抛出一个例外:
Exception in thread "main" groovy.json.JsonException: Lexing failed on line: 1, column: 48, while reading '.', no possible valid JSON value or punctuation could be recognized.
at groovy.json.JsonLexer.nextToken(JsonLexer.java:83)
at groovy.json.JsonLexer.hasNext(JsonLexer.java:233)
at groovy.json.JsonOutput.prettyPrint(JsonOutput.java:501)
at groovy.json.JsonOutput$prettyPrint.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at app.JsonTest.main(JsonTest.groovy:13)
但是如果我们传递一个有效的JSON文档,如:
def jsonString = '{"name": "John", "data": [{"id": 1},{"id": 2}]}'
JsonOutput.prettyPrint(jsonString)
它会顺利通过。
好消息是,您不需要任何额外的依赖来验证您的JSON。
我做了一些调查并使用3种不同的解决方案进行测试:
JsonOutput.prettyJson(String json)
JsonSlurper.parseText(String json)
ObjectMapper.readValue(String json, Class<> type)
(需要添加jackson-databind:2.9.3
依赖项)我使用了以下JSON作为输入:
def json1 = '{"name": "John", "data": [{"id": 1},{"id": 2},]}'
def json2 = '{"name": "John", "data": [{"id": 1},{"id": 2}],}'
def json3 = '{"name": "John", "data": [{"id": 1},{"id": 2}]},'
def json4 = '{"name": "John", "data": [{"id": 1},{"id": 2}]}... abc'
def json5 = '{"name": "John", "data": [{"id": 1},{"id": 2}]}'
预期结果是前4个JSON验证失败,只有第5个JSON正确。为了测试它,我创建了这个Groovy脚本:
@Grab(group='com.fasterxml.jackson.core', module='jackson-databind', version='2.9.3')
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.DeserializationFeature
def json1 = '{"name": "John", "data": [{"id": 1},{"id": 2},]}'
def json2 = '{"name": "John", "data": [{"id": 1},{"id": 2}],}'
def json3 = '{"name": "John", "data": [{"id": 1},{"id": 2}]},'
def json4 = '{"name": "John", "data": [{"id": 1},{"id": 2}]}... abc'
def json5 = '{"name": "John", "data": [{"id": 1},{"id": 2}]}'
def test1 = { String json ->
try {
JsonOutput.prettyPrint(json)
return "VALID"
} catch (ignored) {
return "INVALID"
}
}
def test2 = { String json ->
try {
new JsonSlurper().parseText(json)
return "VALID"
} catch (ignored) {
return "INVALID"
}
}
ObjectMapper mapper = new ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true)
def test3 = { String json ->
try {
mapper.readValue(json, Map)
return "VALID"
} catch (ignored) {
return "INVALID"
}
}
def jsons = [json1, json2, json3, json4, json5]
def tests = ['JsonOutput': test1, 'JsonSlurper': test2, 'ObjectMapper': test3]
def result = tests.collectEntries { name, test ->
[(name): jsons.collect { json ->
[json: json, status: test(json)]
}]
}
result.each {
println "${it.key}:"
it.value.each {
println " ${it.status}: ${it.json}"
}
println ""
}
结果如下:
JsonOutput:
VALID: {"name": "John", "data": [{"id": 1},{"id": 2},]}
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}],}
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]},
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}... abc
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}
JsonSlurper:
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2},]}
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}],}
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]},
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}... abc
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}
ObjectMapper:
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2},]}
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2}],}
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2}]},
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}... abc
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}
正如您所看到的,获胜者是杰克逊的ObjectMapper.readValue()
方法。重要的是 - 它与jackson-databind
&gt; = 2.9.0
一起使用。在这个版本中,他们引入了DeserializationFeature.FAIL_ON_TRAILING_TOKENS
,这使得JSON解析器按预期工作。如果我们不像上面的脚本那样将此配置功能设置为true
,则ObjectMapper会产生错误的结果:
ObjectMapper:
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2},]}
INVALID: {"name": "John", "data": [{"id": 1},{"id": 2}],}
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]},
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}... abc
VALID: {"name": "John", "data": [{"id": 1},{"id": 2}]}
我很惊讶Groovy的标准库在此测试中失败了。幸运的是,它可以通过jackson-databind:2.9.x
依赖来完成。希望它有所帮助。
答案 1 :(得分:2)
似乎是groovy json解析器中的错误或功能
尝试另一个json解析器
我正在使用snakeyaml,因为它支持json和yaml,但你可以通过互联网找到其他基于java的json解析器库
<ScrollView onClick={()=>{
if(this.state.showMoreModal){
this.setState({showMoreModal:false});
}
}}>
...
<Confirm/>
</ScrollView>
答案 2 :(得分:0)
可以这样验证:
Microsoft.VisualBasic.Activities
或更干净一点:
assert JsonOutput.toJson(new JsonSlurper().parseText(myString)).replaceAll("\\s", "") ==
myString.replaceAll("\\s", "")