给定一个任意的JSON我想获得单个字段contentType的值.如何与杰克逊一起做?

{

contentType: "foo",

fooField1: ...

}

{

contentType: "bar",

barArray: [...]

}

有关

解决方法:

杰克逊之路

考虑到您没有描述数据结构的POJO,您可以简单地执行以下操作:

final String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";

final ObjectNode node = new ObjectMapper().readValue(json, ObjectNode.class);

// ^

// actually, try and *reuse* a single instance of ObjectMapper

if (node.has("contentType")) {

System.out.println("contentType: " + node.get("contentType"));

}

在评论部分解决问题

但是,如果您希望不使用整个源String,而只是访问您知道其路径的特定属性,则必须自己编写,利用Tokeniser.

实际上,这是周末,我有时间在我的手上,所以我可以给你一个良好的开端:这是一个基本的!它可以在严格模式下运行并发出合理的错误消息,或者是宽松的,并在无法满足请求时返回Optional.empty.

public static class JSONPath {

protected static final JsonFactory JSON_FACTORY = new JsonFactory();

private final List keys;

public JSONPath(final String from) {

this.keys = Arrays.stream((from.startsWith("[") ? from : String.valueOf("." + from))

.split("(?=\\[|\\]|\\.)"))

.filter(x -> !"]".equals(x))

.map(JSONKey::new)

.collect(Collectors.toList());

}

public Optional getWithin(final String json) throws IOException {

return this.getWithin(json, false);

}

public Optional getWithin(final String json, final boolean strict) throws IOException {

try (final InputStream stream = new StringInputStream(json)) {

return this.getWithin(stream, strict);

}

}

public Optional getWithin(final InputStream json) throws IOException {

return this.getWithin(json, false);

}

public Optional getWithin(final InputStream json, final boolean strict) throws IOException {

return getValueAt(JSON_FACTORY.createParser(json), 0, strict);

}

protected Optional getValueAt(final JsonParser parser, final int idx, final boolean strict) throws IOException {

try {

if (parser.isClosed()) {

return Optional.empty();

}

if (idx >= this.keys.size()) {

parser.nextToken();

if (null == parser.getValueAsString()) {

throw new JSONPathException("The selected node is not a leaf");

}

return Optional.of(parser.getValueAsString());

}

this.keys.get(idx).advanceCursor(parser);

return getValueAt(parser, idx + 1, strict);

} catch (final JSONPathException e) {

if (strict) {

throw (null == e.getCause() ? new JSONPathException(e.getMessage() + String.format(", at path: '%s'", this.toString(idx)), e) : e);

}

return Optional.empty();

}

}

@Override

public String toString() {

return ((Function) x -> x.startsWith(".") ? x.substring(1) : x)

.apply(this.keys.stream().map(JSONKey::toString).collect(Collectors.joining()));

}

private String toString(final int idx) {

return ((Function) x -> x.startsWith(".") ? x.substring(1) : x)

.apply(this.keys.subList(0, idx).stream().map(JSONKey::toString).collect(Collectors.joining()));

}

@SuppressWarnings("serial")

public static class JSONPathException extends RuntimeException {

public JSONPathException() {

super();

}

public JSONPathException(final String message) {

super(message);

}

public JSONPathException(final String message, final Throwable cause) {

super(message, cause);

}

public JSONPathException(final Throwable cause) {

super(cause);

}

}

private static class JSONKey {

private final String key;

private final JsonToken startToken;

public JSONKey(final String str) {

this(str.substring(1), str.startsWith("[") ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);

}

private JSONKey(final String key, final JsonToken startToken) {

this.key = key;

this.startToken = startToken;

}

/**

* Advances the cursor until finding the current {@link JSONKey}, or

* having consumed the entirety of the current JSON Object or Array.

*/

public void advanceCursor(final JsonParser parser) throws IOException {

final JsonToken token = parser.nextToken();

if (!this.startToken.equals(token)) {

throw new JSONPathException(String.format("Expected token of type '%s', got: '%s'", this.startToken, token));

}

if (JsonToken.START_ARRAY.equals(this.startToken)) {

// Moving cursor within a JSON Array

for (int i = 0; i != Integer.valueOf(this.key).intValue(); i++) {

JSONKey.skipToNext(parser);

}

} else {

// Moving cursor in a JSON Object

String name;

for (parser.nextToken(), name = parser.getCurrentName(); !this.key.equals(name); parser.nextToken(), name = parser.getCurrentName()) {

JSONKey.skipToNext(parser);

}

}

}

/**

* Advances the cursor to the next entry in the current JSON Object

* or Array.

*/

private static void skipToNext(final JsonParser parser) throws IOException {

final JsonToken token = parser.nextToken();

if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {

skipToNextImpl(parser, 1);

} else if (JsonToken.END_ARRAY.equals(token) || JsonToken.END_OBJECT.equals(token)) {

throw new JSONPathException("Could not find requested key");

}

}

/**

* Recursively consumes whatever is next until getting back to the

* same depth level.

*/

private static void skipToNextImpl(final JsonParser parser, final int depth) throws IOException {

if (depth == 0) {

return;

}

final JsonToken token = parser.nextToken();

if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {

skipToNextImpl(parser, depth + 1);

} else {

skipToNextImpl(parser, depth - 1);

}

}

@Override

public String toString() {

return String.format(this.startToken.equals(JsonToken.START_ARRAY) ? "[%s]" : ".%s", this.key);

}

}

}

假设以下JSON内容:

{

"people": [{

"name": "Eric",

"age": 28

}, {

"name": "Karin",

"age": 26

}],

"company": {

"name": "Elm Farm",

"address": "3756 Preston Street Wichita, KS 67213",

"phone": "857-778-1265"

}

}

…您可以使用我的JSONPath类,如下所示:

final String json = "{\"people\":[],\"company\":{}}"; // refer to JSON above

System.out.println(new JSONPath("people[0].name").getWithin(json)); // Optional[Eric]

System.out.println(new JSONPath("people[1].name").getWithin(json)); // Optional[Karin]

System.out.println(new JSONPath("people[2].name").getWithin(json)); // Optional.empty

System.out.println(new JSONPath("people[0].age").getWithin(json)); // Optional[28]

System.out.println(new JSONPath("company").getWithin(json)); // Optional.empty

System.out.println(new JSONPath("company.name").getWithin(json)); // Optional[Elm Farm]

请记住,这是基本的.它不会强制数据类型(它返回的每个值都是String)并且只返回叶节点.

实际测试用例

它处理InputStreams,因此您可以针对某些巨型JSON文档对其进行测试,并发现它比浏览器下载和显示其内容要快得多:

System.out.println(new JSONPath("info.contact.email")

.getWithin(new URL("http://test-api.rescuegroups.org/v5/public/swagger.php").openStream()));

// Optional[support@rescuegroups.org]

快速测试

注意我没有重复使用任何已经存在的JSONPath或ObjectMapper,因此结果不准确 – 这只是一个非常粗略的比较:

public static Long time(final Callable> r) throws Exception {

final long start = System.currentTimeMillis();

r.call();

return Long.valueOf(System.currentTimeMillis() - start);

}

public static void main(final String[] args) throws Exception {

final URL url = new URL("http://test-api.rescuegroups.org/v5/public/swagger.php");

System.out.println(String.format( "%dms to get 'info.contact.email' with JSONPath",

time(() -> new JSONPath("info.contact.email").getWithin(url.openStream()))));

System.out.println(String.format( "%dms to just download the entire document otherwise",

time(() -> new Scanner(url.openStream()).useDelimiter("\\A").next())));

System.out.println(String.format( "%dms to bluntly map it entirely with Jackson and access a specific field",

time(() -> new ObjectMapper()

.readValue(url.openStream(), ObjectNode.class)

.get("info").get("contact").get("email"))));

}

378ms to get ‘info.contact.email’ with JSONPath

756ms to just download the entire document otherwise

896ms to bluntly map it entirely with Jackson and access a specific field

标签:java,json,jackson

来源: https://codeday.me/bug/20191001/1838167.html

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐