This is an automated email from the ASF dual-hosted git repository. xiangfu pushed a commit to branch jsonpath_function in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
commit 767b04eb21d50af3a2871bc8b6739ed432239078 Author: Xiang Fu <[email protected]> AuthorDate: Mon Sep 9 02:06:14 2019 -0700 Adding json_path function to extract field from json object --- pinot-core/pom.xml | 4 + .../function/JsonPathTransformFunction.java | 195 +++++++++++++++++++++ .../function/TransformFunctionFactory.java | 1 + .../function/BaseTransformFunctionTest.java | 5 + .../DateTimeConversionTransformFunctionTest.java | 4 +- .../function/JsonPathTransformFunctionTest.java | 121 +++++++++++++ .../TimeConversionTransformFunctionTest.java | 6 +- pom.xml | 6 + 8 files changed, 336 insertions(+), 6 deletions(-) diff --git a/pinot-core/pom.xml b/pinot-core/pom.xml index d074639..922c253 100644 --- a/pinot-core/pom.xml +++ b/pinot-core/pom.xml @@ -164,6 +164,10 @@ <groupId>net.sf.jopt-simple</groupId> <artifactId>jopt-simple</artifactId> </dependency> + <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path</artifactId> + </dependency> <!-- test --> <dependency> diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunction.java new file mode 100644 index 0000000..229efe1 --- /dev/null +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunction.java @@ -0,0 +1,195 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pinot.core.operator.transform.function; + +import com.jayway.jsonpath.JsonPath; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.apache.pinot.common.data.FieldSpec; +import org.apache.pinot.core.common.DataSource; +import org.apache.pinot.core.operator.blocks.ProjectionBlock; +import org.apache.pinot.core.operator.transform.TransformResultMetadata; + + +/** + * json_path(jsonColName, 'json_path') + */ +public class JsonPathTransformFunction extends BaseTransformFunction { + + public static final String FUNCTION_NAME = "json_path"; + + private String _jsonPath; + private TransformFunction _jsonFieldTransformFunction; + private TransformResultMetadata _resultMetadata; + + @Override + public String getName() { + return FUNCTION_NAME; + } + + @Override + public void init(@Nonnull List<TransformFunction> arguments, @Nonnull Map<String, DataSource> dataSourceMap) { + // Check that there are exactly 2 arguments + if (arguments.size() != 2) { + throw new IllegalArgumentException("Exactly 2 arguments are required for JSON_PATH transform function"); + } + + TransformFunction firstArgument = arguments.get(0); + if (firstArgument instanceof LiteralTransformFunction || !firstArgument.getResultMetadata().isSingleValue()) { + throw new IllegalArgumentException( + "The first argument of TIME_CONVERT transform function must be a single-valued column or a transform function"); + } + _jsonFieldTransformFunction = firstArgument; + _jsonPath = ((LiteralTransformFunction) arguments.get(1)).getLiteral(); + _resultMetadata = new TransformResultMetadata(FieldSpec.DataType.STRING, true, false); + } + + @Override + public TransformResultMetadata getResultMetadata() { + return _resultMetadata; + } + + @Override + public int[] transformToIntValuesSV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesSV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final int[] results = new int[projectionBlock.getNumDocs()]; + for (int i = 0; i < results.length; i++) { + results[i] = JsonPath.read(stringValuesSV[i], _jsonPath); + } + return results; + } + + @Override + public long[] transformToLongValuesSV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesSV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final long[] results = new long[projectionBlock.getNumDocs()]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + results[i] = JsonPath.read(stringValuesSV[i], _jsonPath); + } + return results; + } + + @Override + public float[] transformToFloatValuesSV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesSV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final float[] results = new float[projectionBlock.getNumDocs()]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + double doubleValue = JsonPath.read(stringValuesSV[i], _jsonPath); + results[i] = (float) doubleValue; + } + return results; + } + + @Override + public double[] transformToDoubleValuesSV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesSV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final double[] results = new double[projectionBlock.getNumDocs()]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + Object doubleValue = JsonPath.read(stringValuesSV[i], _jsonPath); + if (doubleValue instanceof BigDecimal) { + results[i] = ((BigDecimal) doubleValue).doubleValue(); + } else { + results[i] = (double) doubleValue; + } + } + return results; + } + + @Override + public String[] transformToStringValuesSV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesSV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final String[] results = new String[projectionBlock.getNumDocs()]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + results[i] = JsonPath.read(stringValuesSV[i], _jsonPath); + } + return results; + } + + @Override + public int[][] transformToIntValuesMV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesMV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final int[][] results = new int[projectionBlock.getNumDocs()][]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + final List<Integer> intVals = JsonPath.read(stringValuesMV[i], _jsonPath); + results[i] = new int[intVals.size()]; + for (int j = 0; j < intVals.size(); j++) { + results[i][j] = intVals.get(j); + } + } + return results; + } + + @Override + public long[][] transformToLongValuesMV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesMV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final long[][] results = new long[projectionBlock.getNumDocs()][]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + final List<Long> intVals = JsonPath.read(stringValuesMV[i], _jsonPath); + results[i] = new long[intVals.size()]; + for (int j = 0; j < intVals.size(); j++) { + results[i][j] = intVals.get(j); + } + } + return results; + } + + @Override + public float[][] transformToFloatValuesMV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesMV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final float[][] results = new float[projectionBlock.getNumDocs()][]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + final List<Float> intVals = JsonPath.read(stringValuesMV[i], _jsonPath); + results[i] = new float[intVals.size()]; + for (int j = 0; j < intVals.size(); j++) { + results[i][j] = intVals.get(j); + } + } + return results; + } + + @Override + public double[][] transformToDoubleValuesMV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesMV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final double[][] results = new double[projectionBlock.getNumDocs()][]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + final List<Double> intVals = JsonPath.read(stringValuesMV[i], _jsonPath); + results[i] = new double[intVals.size()]; + for (int j = 0; j < intVals.size(); j++) { + results[i][j] = intVals.get(j); + } + } + return results; + } + + @Override + public String[][] transformToStringValuesMV(@Nonnull ProjectionBlock projectionBlock) { + final String[] stringValuesMV = _jsonFieldTransformFunction.transformToStringValuesSV(projectionBlock); + final String[][] results = new String[projectionBlock.getNumDocs()][]; + for (int i = 0; i < projectionBlock.getNumDocs(); i++) { + final List<String> intVals = JsonPath.read(stringValuesMV[i], _jsonPath); + results[i] = new String[intVals.size()]; + for (int j = 0; j < intVals.size(); j++) { + results[i][j] = intVals.get(j); + } + } + return results; + } +} diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java index fb89bcd..72b1cdd 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java @@ -48,6 +48,7 @@ public class TransformFunctionFactory { put(TimeConversionTransformFunction.FUNCTION_NAME.toLowerCase(), TimeConversionTransformFunction.class); put(DateTimeConversionTransformFunction.FUNCTION_NAME.toLowerCase(), DateTimeConversionTransformFunction.class); + put(JsonPathTransformFunction.FUNCTION_NAME.toLowerCase(), JsonPathTransformFunction.class); put(ValueInTransformFunction.FUNCTION_NAME.toLowerCase(), ValueInTransformFunction.class); put(AbsTransformFunction.FUNCTION_NAME.toLowerCase(), AbsTransformFunction.class); put(CeilTransformFunction.FUNCTION_NAME.toLowerCase(), CeilTransformFunction.class); diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java index 957177e..626a2bf 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java @@ -18,6 +18,7 @@ */ package org.apache.pinot.core.operator.transform.function; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.util.ArrayList; import java.util.HashMap; @@ -65,6 +66,7 @@ public abstract class BaseTransformFunctionTest { protected static final String STRING_SV_COLUMN = "stringSV"; protected static final String INT_MV_COLUMN = "intMV"; protected static final String TIME_COLUMN = "time"; + protected static final String JSON_COLUMN = "json"; protected final int[] _intSVValues = new int[NUM_ROWS]; protected final long[] _longSVValues = new long[NUM_ROWS]; @@ -73,6 +75,7 @@ public abstract class BaseTransformFunctionTest { protected final String[] _stringSVValues = new String[NUM_ROWS]; protected final int[][] _intMVValues = new int[NUM_ROWS][]; protected final long[] _timeValues = new long[NUM_ROWS]; + protected final String[] _jsonValues = new String[NUM_ROWS]; protected Map<String, DataSource> _dataSourceMap; protected ProjectionBlock _projectionBlock; @@ -110,6 +113,7 @@ public abstract class BaseTransformFunctionTest { map.put(STRING_SV_COLUMN, _stringSVValues[i]); map.put(INT_MV_COLUMN, ArrayUtils.toObject(_intMVValues[i])); map.put(TIME_COLUMN, _timeValues[i]); + map.put(JSON_COLUMN, new ObjectMapper().writeValueAsString(map)); GenericRow row = new GenericRow(); row.init(map); rows.add(row); @@ -123,6 +127,7 @@ public abstract class BaseTransformFunctionTest { schema.addField(new DimensionFieldSpec(STRING_SV_COLUMN, FieldSpec.DataType.STRING, true)); schema.addField(new DimensionFieldSpec(INT_MV_COLUMN, FieldSpec.DataType.INT, false)); schema.addField(new TimeFieldSpec(TIME_COLUMN, FieldSpec.DataType.LONG, TimeUnit.MILLISECONDS)); + schema.addField(new DimensionFieldSpec(JSON_COLUMN, FieldSpec.DataType.STRING, true)); SegmentGeneratorConfig config = new SegmentGeneratorConfig(schema); config.setOutDir(INDEX_DIR_PATH); diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/DateTimeConversionTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/DateTimeConversionTransformFunctionTest.java index 5448e65..99ca9fb 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/DateTimeConversionTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/DateTimeConversionTransformFunctionTest.java @@ -63,8 +63,8 @@ public class DateTimeConversionTransformFunctionTest extends BaseTransformFuncti TIME_COLUMN)}, new Object[]{"dateTimeConvert(5,'1:MILLISECONDS:EPOCH','1:MINUTES:EPOCH','1:MINUTES')"}, new Object[]{String.format( "dateTimeConvert(%s,'1:MILLISECONDS:EPOCH','1:MINUTES:EPOCH','1:MINUTES')", INT_MV_COLUMN)}, new Object[]{String.format( - "dateTimeConvert(%s,'1:MILLISECONDS:EPOCH','1:MINUTES:EPOCH','MINUTES')", - TIME_COLUMN)}, new Object[]{String.format("dateTimeConvert(%s,%s,'1:MINUTES:EPOCH','1:MINUTES')", TIME_COLUMN, + "dateTimeConvert(%s,'1:MILLISECONDS:EPOCH','1:MINUTES:EPOCH','MINUTES')", TIME_COLUMN)}, new Object[]{String.format("dateTimeConvert(%s,%s,'1:MINUTES:EPOCH','1:MINUTES')", + TIME_COLUMN, INT_SV_COLUMN)}}; } } diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunctionTest.java new file mode 100644 index 0000000..e599d36 --- /dev/null +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/JsonPathTransformFunctionTest.java @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pinot.core.operator.transform.function; + +import java.util.concurrent.TimeUnit; +import org.apache.pinot.common.request.transform.TransformExpressionTree; +import org.apache.pinot.core.query.exception.BadQueryRequestException; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + + +public class JsonPathTransformFunctionTest extends BaseTransformFunctionTest { + + @Test + public void testJsonPathTransformFunctionForInt() { + TransformExpressionTree expression = TransformExpressionTree.compileToExpressionTree("json_path(json,'$.intSV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + int[] intValues = transformFunction.transformToIntValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(intValues[i], _intSVValues[i]); + } + } + + @Test + public void testJsonPathTransformFunctionForIntMV() { + TransformExpressionTree expression = TransformExpressionTree.compileToExpressionTree("json_path(json,'$.intMV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + int[][] intValues = transformFunction.transformToIntValuesMV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(intValues[i].length, _intMVValues[i].length); + for (int j = 0; j < _intMVValues[i].length; j++) { + Assert.assertEquals(intValues[i][j], _intMVValues[i][j]); + } + } + } + + @Test + public void testJsonPathTransformFunctionForLong() { + TransformExpressionTree expression = TransformExpressionTree.compileToExpressionTree("json_path(json,'$.longSV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + long[] longValues = transformFunction.transformToLongValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(longValues[i], _longSVValues[i]); + } + } + + @Test + public void testJsonPathTransformFunctionForFloat() { + TransformExpressionTree expression = TransformExpressionTree.compileToExpressionTree("json_path(json,'$.floatSV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + float[] floatValues = transformFunction.transformToFloatValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(floatValues[i], _floatSVValues[i]); + } + } + + @Test + public void testJsonPathTransformFunctionForDouble() { + TransformExpressionTree expression = + TransformExpressionTree.compileToExpressionTree("json_path(json,'$.doubleSV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + double[] doubleValues = transformFunction.transformToDoubleValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(doubleValues[i], _doubleSVValues[i]); + } + } + + @Test + public void testJsonPathTransformFunctionForString() { + TransformExpressionTree expression = + TransformExpressionTree.compileToExpressionTree("json_path(json,'$.stringSV')"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + Assert.assertTrue(transformFunction instanceof JsonPathTransformFunction); + Assert.assertEquals(transformFunction.getName(), JsonPathTransformFunction.FUNCTION_NAME); + String[] stringValues = transformFunction.transformToStringValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + Assert.assertEquals(stringValues[i], _stringSVValues[i]); + } + } + + @Test(dataProvider = "testIllegalArguments", expectedExceptions = {BadQueryRequestException.class}) + public void testIllegalArguments(String expressionStr) { + TransformExpressionTree expression = TransformExpressionTree.compileToExpressionTree(expressionStr); + TransformFunctionFactory.get(expression, _dataSourceMap); + } + + @DataProvider(name = "testIllegalArguments") + public Object[][] testIllegalArguments() { + return new Object[][]{new Object[]{String.format("json_path(%s)", + JSON_COLUMN)}, new Object[]{"json_path(5,'$.store.book[0].author','$.store.book[0].author')"}, new Object[]{String.format( + "json_path(%s,'$.store.book[0].author')", INT_MV_COLUMN)}, new Object[]{String.format("json_path(%s,%s,'DAYS')", + JSON_COLUMN, INT_SV_COLUMN)}}; + } +} diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TimeConversionTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TimeConversionTransformFunctionTest.java index bb8c49b..9b7f9b0 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TimeConversionTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TimeConversionTransformFunctionTest.java @@ -51,8 +51,7 @@ public class TimeConversionTransformFunctionTest extends BaseTransformFunctionTe @DataProvider(name = "testTimeConversionTransformFunction") public Object[][] testTimeConversionTransformFunction() { - return new Object[][]{new Object[]{String.format("timeConvert(%s,'MILLISECONDS','DAYS')", - TIME_COLUMN)}, new Object[]{String.format( + return new Object[][]{new Object[]{String.format("timeConvert(%s,'MILLISECONDS','DAYS')", TIME_COLUMN)}, new Object[]{String.format( "timeConvert(timeConvert(timeConvert(%s,'MILLISECONDS','SECONDS'),'SECONDS','HOURS'),'HOURS','DAYS')", TIME_COLUMN)}}; } @@ -65,8 +64,7 @@ public class TimeConversionTransformFunctionTest extends BaseTransformFunctionTe @DataProvider(name = "testIllegalArguments") public Object[][] testIllegalArguments() { - return new Object[][]{new Object[]{String.format("timeConvert(%s,'MILLISECONDS')", - TIME_COLUMN)}, new Object[]{"timeConvert(5,'MILLISECONDS','DAYS')"}, new Object[]{String.format( + return new Object[][]{new Object[]{String.format("timeConvert(%s,'MILLISECONDS')", TIME_COLUMN)}, new Object[]{"timeConvert(5,'MILLISECONDS','DAYS')"}, new Object[]{String.format( "timeConvert(%s,'MILLISECONDS','DAYS')", INT_MV_COLUMN)}, new Object[]{String.format( "timeConvert(%s,'MILLISECONDS','1:DAYS')", TIME_COLUMN)}, new Object[]{String.format( "timeConvert(%s,%s,'DAYS')", TIME_COLUMN, INT_SV_COLUMN)}}; diff --git a/pom.xml b/pom.xml index d770f29..f55a7d1 100644 --- a/pom.xml +++ b/pom.xml @@ -126,6 +126,7 @@ <swagger.version>1.5.16</swagger.version> <hadoop.version>2.7.0</hadoop.version> <antlr.version>4.6</antlr.version> + <jsonpath.version>2.4.0</jsonpath.version> <calcite.version>1.19.0</calcite.version> <!-- commons-configuration, hadoop-common, hadoop-client use commons-lang --> <commons-lang.version>2.6</commons-lang.version> @@ -738,6 +739,11 @@ <version>${antlr.version}</version> </dependency> <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path</artifactId> + <version>${jsonpath.version}</version> + </dependency> + <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-core</artifactId> <version>${calcite.version}</version> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
