diff --git a/pom.xml b/pom.xml index 718111d2..e4ffcd3f 100644 --- a/pom.xml +++ b/pom.xml @@ -113,9 +113,15 @@ 1.7R5 - com.jayway.jsonpath - json-path - 2.0.0 + com.jayway.jsonpath + json-path + 2.1.0 + + + net.minidev + json-smart + + diff --git a/src/main/java/com/metamx/common/parsers/JSONPathParser.java b/src/main/java/com/metamx/common/parsers/JSONPathParser.java index b6cbf499..87dbef02 100644 --- a/src/main/java/com/metamx/common/parsers/JSONPathParser.java +++ b/src/main/java/com/metamx/common/parsers/JSONPathParser.java @@ -25,12 +25,15 @@ import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; +import com.jayway.jsonpath.spi.json.JacksonJsonProvider; +import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; import com.metamx.common.Pair; import com.metamx.common.StringUtils; import java.math.BigInteger; import java.nio.charset.CharsetEncoder; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -50,10 +53,10 @@ public class JSONPathParser implements Parser /** * Constructor * - * @param fieldSpecs List of field specifications. - * @param useFieldDiscovery If true, automatically add root fields seen in the JSON document to the parsed object Map. - * Only fields that contain a singular value or flat list (list containing no subobjects or lists) are automatically added. - * @param mapper Optionally provide an ObjectMapper, used by the parser for reading the input JSON. + * @param fieldSpecs List of field specifications. + * @param useFieldDiscovery If true, automatically add root fields seen in the JSON document to the parsed object Map. + * Only fields that contain a singular value or flat list (list containing no subobjects or lists) are automatically added. + * @param mapper Optionally provide an ObjectMapper, used by the parser for reading the input JSON. */ public JSONPathParser(List fieldSpecs, boolean useFieldDiscovery, ObjectMapper mapper) { @@ -61,7 +64,13 @@ public JSONPathParser(List fieldSpecs, boolean useFieldDiscovery, Obj this.fieldPathMap = generateFieldPaths(fieldSpecs); this.useFieldDiscovery = useFieldDiscovery; this.mapper = mapper == null ? new ObjectMapper() : mapper; - this.jsonPathConfig = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS); + + // Avoid using defaultConfiguration, as this depends on json-smart which we are excluding. + this.jsonPathConfig = Configuration.builder() + .jsonProvider(new JacksonJsonProvider()) + .mappingProvider(new JacksonMappingProvider()) + .options(EnumSet.of(Option.SUPPRESS_EXCEPTIONS)) + .build(); } @Override @@ -76,18 +85,23 @@ public void setFieldNames(Iterable fieldNames) } /** + * @param input JSON string. The root must be a JSON object, not an array. + * e.g., {"valid": "true"} and {"valid":[1,2,3]} are supported + * but [{"invalid": "true"}] and [1,2,3] are not. * - * @param input JSON string. The root must be a JSON object, not an array. - * e.g., {"valid": "true"} and {"valid":[1,2,3]} are supported - * but [{"invalid": "true"}] and [1,2,3] are not. - * @return A map of field names and values + * @return A map of field names and values */ @Override public Map parse(String input) { try { Map map = new LinkedHashMap<>(); - Map document = mapper.readValue(input, new TypeReference>() {}); + Map document = mapper.readValue( + input, + new TypeReference>() + { + } + ); for (Map.Entry> entry : fieldPathMap.entrySet()) { String fieldName = entry.getKey(); Pair pair = entry.getValue(); @@ -119,7 +133,7 @@ private Map> generateFieldPaths(List> map = new LinkedHashMap<>(); for (FieldSpec fieldSpec : fieldSpecs) { String fieldName = fieldSpec.getName(); - if(map.get(fieldName) != null) { + if (map.get(fieldName) != null) { throw new IllegalArgumentException("Cannot have duplicate field definition: " + fieldName); } JsonPath path = JsonPath.compile(fieldSpec.getExpr()); @@ -167,7 +181,7 @@ private Object valueConversionFunction(Object val) if (val instanceof List) { List newList = new ArrayList<>(); - for(Object entry : ((List) val)) { + for (Object entry : ((List) val)) { newList.add(valueConversionFunction(entry)); } return newList; @@ -176,7 +190,7 @@ private Object valueConversionFunction(Object val) if (val instanceof Map) { Map newMap = new LinkedHashMap<>(); Map valMap = (Map) val; - for(Map.Entry entry : valMap.entrySet()) { + for (Map.Entry entry : valMap.entrySet()) { newMap.put(entry.getKey(), valueConversionFunction(entry.getValue())); } return newMap; @@ -237,10 +251,10 @@ public static class FieldSpec /** * Constructor * - * @param type Specifies how this field should be retrieved. - * @param name Name of the field, used as the key in the Object map returned by the parser. - * For ROOT fields, this must match the field name as it appears in the JSON document. - * @param expr Only used by PATH type fields, specifies the JsonPath expression used to access the field. + * @param type Specifies how this field should be retrieved. + * @param name Name of the field, used as the key in the Object map returned by the parser. + * For ROOT fields, this must match the field name as it appears in the JSON document. + * @param expr Only used by PATH type fields, specifies the JsonPath expression used to access the field. */ public FieldSpec( FieldType type,