You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by ot...@apache.org on 2018/07/21 06:30:39 UTC
metron git commit: METRON-1606 Add a ' wrap'
to incoming messages in the metron json parser (ottobackwards) closes
apache/metron#1054
Repository: metron
Updated Branches:
refs/heads/master aceca469a -> 6bac842d7
METRON-1606 Add a 'wrap' to incoming messages in the metron json parser (ottobackwards) closes apache/metron#1054
Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/6bac842d
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/6bac842d
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/6bac842d
Branch: refs/heads/master
Commit: 6bac842d7ad2819c56412837d8befb603ef15f35
Parents: aceca46
Author: ottobackwards <ot...@gmail.com>
Authored: Fri Jul 20 17:44:35 2018 -0400
Committer: otto <ot...@apache.org>
Committed: Fri Jul 20 17:44:35 2018 -0400
----------------------------------------------------------------------
.../docker/rpm-docker/SPECS/metron.spec | 1 +
.../parsed/jsonMapExampleParsed | 6 +
.../raw/jsonMapExampleOutput | 3 +
metron-platform/metron-parsers/README.md | 5 +
.../zookeeper/parsers/jsonMapWrappedQuery.json | 5 +
.../metron/parsers/json/JSONMapParser.java | 40 +++-
.../JSONMapWrappedQueryIntegrationTest.java | 37 ++++
.../integration/ParserIntegrationTest.java | 22 +-
.../json/JSONMapParserWrappedQueryTest.java | 199 +++++++++++++++++++
9 files changed, 299 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
index 4b88fd0..b308908 100644
--- a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
+++ b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
@@ -151,6 +151,7 @@ This package installs the Metron Parser files
%{metron_home}/config/zookeeper/parsers/bro.json
%{metron_home}/config/zookeeper/parsers/jsonMap.json
%{metron_home}/config/zookeeper/parsers/jsonMapQuery.json
+%{metron_home}/config/zookeeper/parsers/jsonMapWrappedQuery.json
%{metron_home}/config/zookeeper/parsers/snort.json
%{metron_home}/config/zookeeper/parsers/squid.json
%{metron_home}/config/zookeeper/parsers/websphere.json
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/parsed/jsonMapExampleParsed
----------------------------------------------------------------------
diff --git a/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/parsed/jsonMapExampleParsed b/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/parsed/jsonMapExampleParsed
new file mode 100644
index 0000000..c6aac78
--- /dev/null
+++ b/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/parsed/jsonMapExampleParsed
@@ -0,0 +1,6 @@
+{ "string" : "foo", "number" : 1, "ignored" : [ "blah" ], "original_string":"{ \"string\" : \"foo\", \"number\" : 1, \"ignored\" : [ \"blah\" ] }","timestamp":1000000000000, "source.type":"jsonMapWrappedQuery","guid":"this-is-random-uuid-will-be-36-chars" }
+{ "number" : 4 , "original_string" : "{ \"number\" : 4 }", "source.type":"jsonMapWrappedQuery","timestamp":1000000000000,"guid":"this-is-random-uuid-will-be-36-chars"}
+{ "string" : "bar", "number" : 2, "ignored" : [ "blah" ], "original_string":"{ \"string\" : \"bar\", \"number\" : 2, \"ignored\" : [ \"blah\" ] }","timestamp":1000000000000, "source.type":"jsonMapWrappedQuery","guid":"this-is-random-uuid-will-be-36-chars" }
+{ "number" : 5 , "original_string" : "{ \"number\" : 5 }", "source.type":"jsonMapWrappedQuery","timestamp":1000000000000,"guid":"this-is-random-uuid-will-be-36-chars"}
+{ "string" : "baz", "number" : 3, "ignored" : [ "blah" ], "original_string":"{ \"string\" : \"baz\", \"number\" : 3, \"ignored\" : [ \"blah\" ] }","timestamp":1000000000000, "source.type":"jsonMapWrappedQuery","guid":"this-is-random-uuid-will-be-36-chars" }
+{ "number" : 6 , "original_string" : "{ \"number\" : 6 }", "source.type":"jsonMapWrappedQuery","timestamp":1000000000000,"guid":"this-is-random-uuid-will-be-36-chars"}
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/raw/jsonMapExampleOutput
----------------------------------------------------------------------
diff --git a/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/raw/jsonMapExampleOutput b/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/raw/jsonMapExampleOutput
new file mode 100644
index 0000000..f142a55
--- /dev/null
+++ b/metron-platform/metron-integration-test/src/main/sample/data/jsonMapWrappedQuery/raw/jsonMapExampleOutput
@@ -0,0 +1,3 @@
+{ "string" : "foo", "number" : 1, "ignored" : [ "blah" ] },{ "number" : 4 },
+{ "string" : "bar", "number" : 2, "ignored" : [ "blah" ] },{ "number" : 5 },
+{ "string" : "baz", "number" : 3, "ignored" : [ "blah" ] },{ "number" : 6 }
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/README.md
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/README.md b/metron-platform/metron-parsers/README.md
index 0e428e3..fd6b470 100644
--- a/metron-platform/metron-parsers/README.md
+++ b/metron-platform/metron-parsers/README.md
@@ -44,6 +44,11 @@ There are two general types types of parsers:
* `ALLOW` : Allow multidimensional maps
* `ERROR` : Throw an error when a multidimensional map is encountered
* `jsonpQuery` : A [JSON Path](#json_path) query string. If present, the result of the JSON Path query should be a list of messages. This is useful if you have a JSON document which contains a list or array of messages embedded in it, and you do not have another means of splitting the message.
+ * `wrapInEntityArray` : `"true" or "false"`. If `jsonQuery` is present and this flag is present and set to `"true"`, the incoming message will be wrapped in a JSON entity and array.
+ for example:
+ `{"name":"value"},{"name2","value2}` will be wrapped as `{"message" : [{"name":"value"},{"name2","value2}]}`.
+ This is using the default value for `wrapEntityName` if that property is not set.
+ * `wrapEntityName` : Sets the name to use when wrapping JSON using `wrapInEntityArray`. The `jsonpQuery` should reference this name.
* A field called `timestamp` is expected to exist and, if it does not, then current time is inserted.
## Parser Error Routing
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/jsonMapWrappedQuery.json
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/jsonMapWrappedQuery.json b/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/jsonMapWrappedQuery.json
new file mode 100644
index 0000000..3e960e0
--- /dev/null
+++ b/metron-platform/metron-parsers/src/main/config/zookeeper/parsers/jsonMapWrappedQuery.json
@@ -0,0 +1,5 @@
+{
+ "parserClassName":"org.apache.metron.parsers.json.JSONMapParser",
+ "sensorTopic":"jsonMapWrappedQuery",
+ "parserConfig": {"jsonpQuery":"$.foo","wrapInEntityArray":"true","wrapEntityName":"foo"}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/json/JSONMapParser.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/json/JSONMapParser.java b/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/json/JSONMapParser.java
index f5d67f9..0acc96c 100644
--- a/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/json/JSONMapParser.java
+++ b/metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/json/JSONMapParser.java
@@ -35,6 +35,7 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.metron.common.utils.JSONUtils;
import org.apache.metron.parsers.BasicParser;
@@ -87,10 +88,18 @@ public class JSONMapParser extends BasicParser {
public static final String MAP_STRATEGY_CONFIG = "mapStrategy";
public static final String JSONP_QUERY = "jsonpQuery";
+ public static final String WRAP_JSON = "wrapInEntityArray";
+ public static final String WRAP_ENTITY_NAME = "wrapEntityName";
+ public static final String DEFAULT_WRAP_ENTITY_NAME = "messages";
+
+ private static final String WRAP_START_FMT = "{ \"%s\" : [";
+ private static final String WRAP_END = "]}";
private MapStrategy mapStrategy = MapStrategy.DROP;
private transient TypeRef<List<Map<String, Object>>> typeRef = null;
private String jsonpQuery = null;
+ private String wrapEntityName = DEFAULT_WRAP_ENTITY_NAME;
+ private boolean wrapJson = false;
@Override
@@ -100,6 +109,20 @@ public class JSONMapParser extends BasicParser {
if (config.containsKey(JSONP_QUERY)) {
typeRef = new TypeRef<List<Map<String, Object>>>() { };
jsonpQuery = (String) config.get(JSONP_QUERY);
+
+ if (!StringUtils.isBlank(jsonpQuery) && config.containsKey(WRAP_JSON)) {
+ Object wrapObject = config.get(WRAP_JSON);
+ if (wrapObject instanceof String) {
+ wrapJson = Boolean.valueOf((String)wrapObject);
+ } else if (wrapObject instanceof Boolean) {
+ wrapJson = (Boolean) config.get(WRAP_JSON);
+ }
+ String entityName = (String)config.get(WRAP_ENTITY_NAME);
+ if (!StringUtils.isBlank(entityName)) {
+ wrapEntityName = entityName;
+ }
+ }
+
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider();
@@ -147,9 +170,14 @@ public class JSONMapParser extends BasicParser {
String originalString = new String(rawMessage);
List<Map<String, Object>> messages = new ArrayList<>();
+ // if configured, wrap the json in an entity and array
+ if (wrapJson) {
+ originalString = wrapMessageJson(originalString);
+ }
+
if (!StringUtils.isEmpty(jsonpQuery)) {
- Object parsedObject = JsonPath.parse(new String(rawMessage)).read(jsonpQuery, typeRef);
- if(parsedObject != null) {
+ Object parsedObject = JsonPath.parse(originalString).read(jsonpQuery, typeRef);
+ if (parsedObject != null) {
messages.addAll((List<Map<String,Object>>)parsedObject);
}
} else {
@@ -192,4 +220,12 @@ public class JSONMapParser extends BasicParser {
return ret;
}
+ private String wrapMessageJson(String jsonMessage) {
+ String base = new StringBuilder(String.format(WRAP_START_FMT,wrapEntityName))
+ .append(jsonMessage).toString().trim();
+ if (base.endsWith(",")) {
+ base = base.substring(0, base.length() - 1);
+ }
+ return base + WRAP_END;
+ }
}
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/JSONMapWrappedQueryIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/JSONMapWrappedQueryIntegrationTest.java b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/JSONMapWrappedQueryIntegrationTest.java
new file mode 100644
index 0000000..569e175
--- /dev/null
+++ b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/JSONMapWrappedQueryIntegrationTest.java
@@ -0,0 +1,37 @@
+/**
+ * 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.metron.parsers.integration;
+
+import org.apache.metron.parsers.integration.validation.SampleDataValidation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JSONMapWrappedQueryIntegrationTest extends ParserIntegrationTest {
+ @Override
+ String getSensorType() {
+ return "jsonMapWrappedQuery";
+ }
+
+ @Override
+ List<ParserValidation> getValidations() {
+ return new ArrayList<ParserValidation>() {{
+ add(new SampleDataValidation());
+ }};
+ }
+}
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/ParserIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/ParserIntegrationTest.java b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/ParserIntegrationTest.java
index cd3d005..6b00a2b 100644
--- a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/ParserIntegrationTest.java
+++ b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/integration/ParserIntegrationTest.java
@@ -1,4 +1,4 @@
-/**
+/*
* 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
@@ -17,31 +17,19 @@
*/
package org.apache.metron.parsers.integration;
-import com.google.common.base.Function;
import org.apache.metron.TestConstants;
-import org.apache.metron.common.Constants;
-import org.apache.metron.enrichment.integration.components.ConfigUploadComponent;
-import org.apache.metron.integration.*;
-import org.apache.metron.integration.components.KafkaComponent;
-import org.apache.metron.integration.processors.KafkaMessageSet;
-import org.apache.metron.integration.components.ZKServerComponent;
-import org.apache.metron.integration.processors.KafkaProcessor;
+import org.apache.metron.integration.BaseIntegrationTest;
+import org.apache.metron.integration.ProcessorResult;
import org.apache.metron.integration.utils.TestUtils;
-import org.apache.metron.parsers.integration.components.ParserTopologyComponent;
import org.apache.metron.test.TestDataType;
import org.apache.metron.test.utils.SampleDataUtils;
-import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
-import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
-import java.util.*;
+import java.util.List;
public abstract class ParserIntegrationTest extends BaseIntegrationTest {
protected List<byte[]> inputMessages;
@@ -74,7 +62,7 @@ public abstract class ParserIntegrationTest extends BaseIntegrationTest {
} else {
List<ParserValidation> validations = getValidations();
if (validations == null || validations.isEmpty()) {
- buffer.append("No validations configured for sensorType " + sensorType + ". Dumping parsed messages").append("\n");
+ buffer.append("No validations configured for sensorType ").append(sensorType).append(". Dumping parsed messages").append("\n");
dumpParsedMessages(outputMessages,buffer);
Assert.fail(buffer.toString());
} else {
http://git-wip-us.apache.org/repos/asf/metron/blob/6bac842d/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/json/JSONMapParserWrappedQueryTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/json/JSONMapParserWrappedQueryTest.java b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/json/JSONMapParserWrappedQueryTest.java
new file mode 100644
index 0000000..0da45dd
--- /dev/null
+++ b/metron-platform/metron-parsers/src/test/java/org/apache/metron/parsers/json/JSONMapParserWrappedQueryTest.java
@@ -0,0 +1,199 @@
+/**
+ * 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.metron.parsers.json;
+
+import com.google.common.collect.ImmutableMap;
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.log4j.Level;
+import org.apache.metron.parsers.BasicParser;
+import org.apache.metron.test.utils.UnitTestHelper;
+import org.json.simple.JSONObject;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.List;
+
+public class JSONMapParserWrappedQueryTest {
+
+ /**
+ * { "name" : "foo1", "value" : "bar", "number" : 1.0 },
+ * { "name" : "foo2", "value" : "baz", "number" : 2.0 }
+ */
+ @Multiline
+ static String JSON_LIST;
+
+ /**
+ * { "name" : "foo1", "value" : "bar", "number" : 1.0 }
+ */
+ @Multiline
+ static String JSON_SINGLE;
+
+ /**
+ * { "name" : "foo2", "value" : "baz", "number" : 2.0 }
+ */
+ @Multiline
+ static String JSON_SINGLE2;
+
+ @Test
+ public void testHappyPath() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(new HashMap<String, Object>() {{
+ put(JSONMapParser.WRAP_JSON,true);
+ put(JSONMapParser.WRAP_ENTITY_NAME,"foo");
+ put(JSONMapParser.JSONP_QUERY, "$.foo");
+ }});
+ List<JSONObject> output = parser.parse(JSON_LIST.getBytes());
+ Assert.assertEquals(output.size(), 2);
+ //don't forget the timestamp field!
+ Assert.assertEquals(output.get(0).size(), 5);
+ JSONObject message = output.get(0);
+ Assert.assertEquals("foo1", message.get("name"));
+ Assert.assertEquals("bar", message.get("value"));
+ Assert.assertEquals(1.0, message.get("number"));
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+ Assert.assertNotNull(message.get("number"));
+ Assert.assertTrue(message.get("number") instanceof Number);
+
+ message = output.get(1);
+ Assert.assertEquals("foo2", message.get("name"));
+ Assert.assertEquals("baz", message.get("value"));
+ Assert.assertEquals(2.0, message.get("number"));
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+ Assert.assertNotNull(message.get("number"));
+ Assert.assertTrue(message.get("number") instanceof Number);
+
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInvalidJSONPathThrows() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(new HashMap<String, Object>() {{
+ put(JSONMapParser.JSONP_QUERY, "$$..$$SDSE$#$#.");
+ }});
+ List<JSONObject> output = parser.parse(JSON_LIST.getBytes());
+
+ }
+
+ @Test
+ public void testNoMatchesNoExceptions() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(new HashMap<String, Object>() {{
+ put(JSONMapParser.JSONP_QUERY, "$.foo");
+ }});
+ List<JSONObject> output = parser.parse(JSON_SINGLE.getBytes());
+ Assert.assertEquals(0, output.size());
+ }
+
+ /**
+ * {
+ * "foo" :
+ * [
+ * {
+ * "collection" : { "blah" : 7, "blah2" : "foo", "bigblah" : { "innerBlah" : "baz", "reallyInnerBlah" : { "color" : "grey" }}}
+ * },
+ * {
+ * "collection" : { "blah" : 8, "blah2" : "bar", "bigblah" : { "innerBlah" : "baz2", "reallyInnerBlah" : { "color" : "blue" }}}
+ * }
+ * ]
+ * }
+ */
+ @Multiline
+ static String collectionHandlingJSON;
+
+ @Test
+ public void testCollectionHandlingDrop() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(new HashMap<String, Object>() {{
+ put(JSONMapParser.JSONP_QUERY, "$.foo");
+ }});
+ List<JSONObject> output = parser.parse(collectionHandlingJSON.getBytes());
+ Assert.assertEquals(output.size(), 2);
+
+ //don't forget the timestamp field!
+ Assert.assertEquals(output.get(0).size(), 2);
+
+ JSONObject message = output.get(0);
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+
+ message = output.get(1);
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCollectionHandlingError() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(ImmutableMap
+ .of(JSONMapParser.MAP_STRATEGY_CONFIG, JSONMapParser.MapStrategy.ERROR.name(),
+ JSONMapParser.JSONP_QUERY, "$.foo"));
+ UnitTestHelper.setLog4jLevel(BasicParser.class, Level.FATAL);
+ parser.parse(collectionHandlingJSON.getBytes());
+ UnitTestHelper.setLog4jLevel(BasicParser.class, Level.ERROR);
+ }
+
+
+ @Test
+ public void testCollectionHandlingAllow() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(ImmutableMap
+ .of(JSONMapParser.MAP_STRATEGY_CONFIG, JSONMapParser.MapStrategy.ALLOW.name(),
+ JSONMapParser.JSONP_QUERY, "$.foo"));
+ List<JSONObject> output = parser.parse(collectionHandlingJSON.getBytes());
+ Assert.assertEquals(output.size(), 2);
+ Assert.assertEquals(output.get(0).size(), 3);
+ JSONObject message = output.get(0);
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+
+ Assert.assertEquals(output.get(1).size(), 3);
+ message = output.get(1);
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+ }
+
+ @Test
+ public void testCollectionHandlingUnfold() {
+ JSONMapParser parser = new JSONMapParser();
+ parser.configure(ImmutableMap
+ .of(JSONMapParser.MAP_STRATEGY_CONFIG, JSONMapParser.MapStrategy.UNFOLD.name(),
+ JSONMapParser.JSONP_QUERY, "$.foo"));
+ List<JSONObject> output = parser.parse(collectionHandlingJSON.getBytes());
+ Assert.assertEquals(output.size(), 2);
+ Assert.assertEquals(output.get(0).size(), 6);
+ JSONObject message = output.get(0);
+ Assert.assertEquals(message.get("collection.blah"), 7);
+ Assert.assertEquals(message.get("collection.blah2"), "foo");
+ Assert.assertEquals(message.get("collection.bigblah.innerBlah"), "baz");
+ Assert.assertEquals(message.get("collection.bigblah.reallyInnerBlah.color"), "grey");
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+
+ Assert.assertEquals(output.get(1).size(), 6);
+ message = output.get(1);
+ Assert.assertEquals(message.get("collection.blah"), 8);
+ Assert.assertEquals(message.get("collection.blah2"), "bar");
+ Assert.assertEquals(message.get("collection.bigblah.innerBlah"), "baz2");
+ Assert.assertEquals(message.get("collection.bigblah.reallyInnerBlah.color"), "blue");
+ Assert.assertNotNull(message.get("timestamp"));
+ Assert.assertTrue(message.get("timestamp") instanceof Number);
+ }
+}