Skip to content

Instantly share code, notes, and snippets.

@hyeonjae
Last active January 20, 2016 11:44
Show Gist options
  • Save hyeonjae/6c5e17cfa483137a9390 to your computer and use it in GitHub Desktop.
Save hyeonjae/6c5e17cfa483137a9390 to your computer and use it in GitHub Desktop.
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsonNodeParser {
private final String DOT = ".";
private final int PATH = 1;
private final int INDEX = 2;
private JsonNode root;
public JsonNodeParser(JsonNode root) {
this.root = root;
}
public List<String> get(String... paths) {
List<String> results = new ArrayList<>();
for (String path : paths) {
int i = StringUtils.indexOf(path, DOT);
if (i > 0) {
String left = this.left(path, i);
String right = this.right(path, i);
if (isArray(left)) {
String pure = extract(left, PATH);
String index = extract(left, INDEX);
JsonNode arrNode = root.path(pure);
if (StringUtils.equals(index, "*")) {
for (JsonNode element : arrNode) {
parse(element, right).stream().forEach(results::add);
}
} else {
assert index != null;
JsonNode child = arrNode.get(Integer.parseInt(index));
parse(child, right).forEach(results::add);
}
} else {
JsonNode child = root.path(left);
parse(child, right).forEach(results::add);
}
}
}
return results;
}
private List<String> parse(JsonNode node, String subPath) {
List<String> results = new ArrayList<>();
int i = StringUtils.indexOf(subPath, DOT);
if (i > 0) {
String left = this.left(subPath, i);
String right = this.right(subPath, i);
if (isArray(left)) {
String pure = extract(left, PATH);
String index = extract(left, INDEX);
JsonNode arrNode = node.path(pure);
if (StringUtils.equals(index, "*")) {
for (JsonNode element : arrNode) {
parse(element, right).stream().forEach(results::add);
}
} else {
assert index != null;
JsonNode child = arrNode.get(Integer.parseInt(index));
if (child != null) {
parse(child, right).forEach(results::add);
}
}
} else {
JsonNode child = node.path(left);
if (!(child instanceof MissingNode)) {
parse(child, right).forEach(results::add);
}
}
} else {
results.add(node.path(subPath).asText());
}
return results;
}
private String left(String str, int pos) {
return StringUtils.substring(str, 0, pos);
}
private String right(String str, int pos) {
return StringUtils.substring(str, pos + 1, Optional.ofNullable(str).map(String::length).orElse(0));
}
private boolean isArray(String path) {
Pattern p = Pattern.compile("^\\w+\\[[0-9]+|\\*\\]$");
Matcher m = p.matcher(path);
return m.find();
}
private String extract(String path, int group) {
Pattern p = Pattern.compile("^(\\w+)\\[([0-9]+|\\*)\\]$");
Matcher m = p.matcher(path);
if (m.find()) {
return m.group(group);
}
return null;
}
}
@hyeonjae
Copy link
Author

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;

public class JsonNodeParserTest {
    @Test
    public void parseTest() throws IOException {
        String payload = "{\"repository\": {\"website\": \"\", \"scm\": \"git\", \"name\": \"bitbucket_test_repo\", \"uuid\": \"{e07de9e6-f6c1-4b8a-9921-c1d5047cc4b6}\", \"full_name\": \"hyeonjae_park/bitbucket_test_repo\", \"owner\": {\"username\": \"hyeonjae_park\", \"type\": \"user\", \"display_name\": \"hyeonjae park\", \"uuid\": \"{118501b7-ebc3-495e-bc3a-59e28e158cc0}\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/users/hyeonjae_park\"}, \"avatar\": {\"href\": \"https://bitbucket.org/account/hyeonjae_park/avatar/32/\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/\"}}}, \"type\": \"repository\", \"is_private\": true, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo\"}, \"avatar\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/avatar/32/\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo\"}}}, \"push\": {\"changes\": [{\"created\": false, \"forced\": false, \"closed\": false, \"truncated\": false, \"commits\": [{\"date\": \"2016-01-13T09:12:24+00:00\", \"parents\": [{\"type\": \"commit\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}}, \"hash\": \"4e51914a8cee8a1e805152a5a3990a483d28aefb\"}], \"message\": \"forth commit\\n\", \"type\": \"commit\", \"author\": {\"raw\": \"\\u1107\\u1161\\u11a8\\u1112\\u1167\\u11ab\\u110c\\u1162/NE <hyeonjae.park@nhnent.com>\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/656759edf99a509eaffcf8f8508025d17058f587\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/656759edf99a509eaffcf8f8508025d17058f587\"}}, \"hash\": \"656759edf99a509eaffcf8f8508025d17058f587\"}, {\"date\": \"2016-01-13T09:09:59+00:00\", \"parents\": [{\"type\": \"commit\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/b816765c169259edfc4942233ec8a3d1df124ea5\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/b816765c169259edfc4942233ec8a3d1df124ea5\"}}, \"hash\": \"b816765c169259edfc4942233ec8a3d1df124ea5\"}], \"message\": \"third commit\\n\", \"type\": \"commit\", \"author\": {\"raw\": \"\\u1107\\u1161\\u11a8\\u1112\\u1167\\u11ab\\u110c\\u1162/NE <hyeonjae.park@nhnent.com>\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}}, \"hash\": \"4e51914a8cee8a1e805152a5a3990a483d28aefb\"}, {\"date\": \"2016-01-13T09:09:35+00:00\", \"parents\": [{\"type\": \"commit\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}}, \"hash\": \"b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}], \"message\": \"second commit\\n\", \"type\": \"commit\", \"author\": {\"raw\": \"\\u1107\\u1161\\u11a8\\u1112\\u1167\\u11ab\\u110c\\u1162/NE <hyeonjae.park@nhnent.com>\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/b816765c169259edfc4942233ec8a3d1df124ea5\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/b816765c169259edfc4942233ec8a3d1df124ea5\"}}, \"hash\": \"b816765c169259edfc4942233ec8a3d1df124ea5\"}], \"old\": {\"repository\": {\"full_name\": \"hyeonjae_park/bitbucket_test_repo\", \"name\": \"bitbucket_test_repo\", \"uuid\": \"{e07de9e6-f6c1-4b8a-9921-c1d5047cc4b6}\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo\"}, \"avatar\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/avatar/32/\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo\"}}, \"type\": \"repository\"}, \"type\": \"branch\", \"name\": \"feature-one\", \"target\": {\"date\": \"2016-01-13T09:08:07+00:00\", \"parents\": [{\"type\": \"commit\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/29af8d486527459f64e9c00bb4c6155878018367\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/29af8d486527459f64e9c00bb4c6155878018367\"}}, \"hash\": \"29af8d486527459f64e9c00bb4c6155878018367\"}], \"message\": \"first commit\\n\", \"type\": \"commit\", \"author\": {\"raw\": \"\\u1107\\u1161\\u11a8\\u1112\\u1167\\u11ab\\u110c\\u1162/NE <hyeonjae.park@nhnent.com>\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}}, \"hash\": \"b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/refs/branches/feature-one\"}, \"commits\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commits/feature-one\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/branch/feature-one\"}}}, \"links\": {\"diff\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/diff/656759edf99a509eaffcf8f8508025d17058f587..b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}, \"commits\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commits?include=656759edf99a509eaffcf8f8508025d17058f587&exclude=b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/branches/compare/656759edf99a509eaffcf8f8508025d17058f587..b8ee98bf323d1fc4d7ce212bd6b7d0479ce1dd04\"}}, \"new\": {\"repository\": {\"full_name\": \"hyeonjae_park/bitbucket_test_repo\", \"name\": \"bitbucket_test_repo\", \"uuid\": \"{e07de9e6-f6c1-4b8a-9921-c1d5047cc4b6}\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo\"}, \"avatar\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/avatar/32/\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo\"}}, \"type\": \"repository\"}, \"type\": \"branch\", \"name\": \"feature-one\", \"target\": {\"date\": \"2016-01-13T09:12:24+00:00\", \"parents\": [{\"type\": \"commit\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/4e51914a8cee8a1e805152a5a3990a483d28aefb\"}}, \"hash\": \"4e51914a8cee8a1e805152a5a3990a483d28aefb\"}], \"message\": \"forth commit\\n\", \"type\": \"commit\", \"author\": {\"raw\": \"\\u1107\\u1161\\u11a8\\u1112\\u1167\\u11ab\\u110c\\u1162/NE <hyeonjae.park@nhnent.com>\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commit/656759edf99a509eaffcf8f8508025d17058f587\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/commits/656759edf99a509eaffcf8f8508025d17058f587\"}}, \"hash\": \"656759edf99a509eaffcf8f8508025d17058f587\"}, \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/refs/branches/feature-one\"}, \"commits\": {\"href\": \"https://api.bitbucket.org/2.0/repositories/hyeonjae_park/bitbucket_test_repo/commits/feature-one\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/bitbucket_test_repo/branch/feature-one\"}}}}]}, \"actor\": {\"username\": \"hyeonjae_park\", \"type\": \"user\", \"display_name\": \"hyeonjae park\", \"uuid\": \"{118501b7-ebc3-495e-bc3a-59e28e158cc0}\", \"links\": {\"self\": {\"href\": \"https://api.bitbucket.org/2.0/users/hyeonjae_park\"}, \"avatar\": {\"href\": \"https://bitbucket.org/account/hyeonjae_park/avatar/32/\"}, \"html\": {\"href\": \"https://bitbucket.org/hyeonjae_park/\"}}}}";
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(payload);
        JsonNodeParser parser = new JsonNodeParser(root);
        List<String> results = parser.get("push.changes[0].commits[*].message");
        results.forEach(System.out::println);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment