/* # Licensed Materials - Property of IBM # Copyright IBM Corp. 2015 */ package com.ibm.streamsx.topology.test.json; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.Test; import com.ibm.json.java.JSON; import com.ibm.json.java.JSONArray; import com.ibm.json.java.JSONArtifact; import com.ibm.json.java.JSONObject; import com.ibm.streams.flow.handlers.MostRecent; import com.ibm.streams.operator.Tuple; import com.ibm.streamsx.topology.TStream; import com.ibm.streamsx.topology.Topology; import com.ibm.streamsx.topology.function.UnaryOperator; import com.ibm.streamsx.topology.json.JSONSchemas; import com.ibm.streamsx.topology.json.JSONStreams; import com.ibm.streamsx.topology.spl.SPLStream; import com.ibm.streamsx.topology.spl.SPLStreams; import com.ibm.streamsx.topology.test.TestTopology; import com.ibm.streamsx.topology.tester.Condition; import com.ibm.streamsx.topology.tuple.JSONAble; public class JSONStreamsTest extends TestTopology { private static final String QUESTION = "What is the answer to life, the universe & everything?"; private static final String JSON_EXAMPLE = "{\"menu\": {\n" + " \"id\": \"file\",\n" + " \"value\": \"File\",\n" + " \"popup\": {\n" + " \"menuitem\": [\n" + " {\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"},\n" + " {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},\n" + " {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n" + " ]\n" + " }\n" + "}}"; /** * Convert an example JSON as a String back to a String through JSON * deserialization and serialization. */ @Test public void testSimpleJson() throws Exception { final Topology t = new Topology("SimpleJson"); TStream<String> example = t.strings(JSON_EXAMPLE); TStream<JSONObject> json = JSONStreams.deserialize(example); assertEquals(JSONObject.class, json.getTupleClass()); assertEquals(JSONObject.class, json.getTupleType()); TStream<String> jsonString = JSONStreams.serialize(json); assertEquals(String.class, jsonString.getTupleClass()); assertEquals(String.class, jsonString.getTupleType()); checkJsonOutput(JSON.parse(JSON_EXAMPLE), jsonString); } private JSONArtifact checkJsonOutput(JSONArtifact expected, TStream<String> jsonString) throws Exception, IOException { assertEquals(String.class, jsonString.getTupleClass()); assertEquals(String.class, jsonString.getTupleType()); SPLStream splS = SPLStreams.stringToSPLStream(jsonString); MostRecent<Tuple> mr = jsonString.topology().getTester() .splHandler(splS, new MostRecent<Tuple>()); Condition<Long> singleTuple = jsonString.topology().getTester().tupleCount(splS, 1); complete(jsonString.topology().getTester(), singleTuple, 10, TimeUnit.SECONDS); JSONArtifact rv = JSON.parse(mr.getMostRecentTuple().getString(0)); assertEquals(expected, rv); return rv; } @Test public void testModifyingJson() throws Exception { final Topology t = new Topology("SimpleJson"); final JSONObject value = new JSONObject(); value.put("question",QUESTION); TStream<JSONObject> s = t.constants(Collections.singletonList(value)); TStream<String> jsonString = JSONStreams.serialize(s); TStream<JSONObject> json = JSONStreams.deserialize(jsonString); TStream<JSONObject> jsonm = modifyJSON(json); assertFalse(value.containsKey("answer")); JSONObject ev = new JSONObject(); ev.put("question", QUESTION); ev.put("answer", 42l); checkJsonOutput(ev, JSONStreams.serialize(jsonm)); } @SuppressWarnings("serial") private static TStream<JSONObject> modifyJSON(TStream<JSONObject> json) { return json.modify(new UnaryOperator<JSONObject>() { @Override public JSONObject apply(JSONObject v) { v.put("answer", 42l); return v; } }); } @Test public void testJSONAble() throws IOException, Exception { Topology topology = new Topology(); final TestJSONAble value = new TestJSONAble(42,QUESTION); TStream<TestJSONAble> s = topology.constants( Collections.singletonList(value)).asType(TestJSONAble.class); TStream<JSONObject> js = JSONStreams.toJSON(s); JSONObject ev = new JSONObject(); ev.put("b", QUESTION); ev.put("a", 42l); checkJsonOutput(ev, JSONStreams.serialize(js)); } @SuppressWarnings("serial") public static class TestJSONAble implements Serializable, JSONAble { private final int a; private final String b; public TestJSONAble(int a, String b) { this.a = a; this.b = b; } @Override public JSONObject toJSON() { JSONObject jo = new JSONObject(); jo.put("a", a); jo.put("b", b); return jo; } } /** * Test that if the serialized value is * an array, it ends up wrapped in an object. */ @Test public void testDeserializeArray() throws Exception { final String data = "[ 100, 500, false, 200, 400 ]"; final Topology t = new Topology(); TStream<String> array = t.strings(data); TStream<JSONObject> json = JSONStreams.deserialize(array); TStream<String> jsonString = JSONStreams.serialize(json); JSONArray ja = (JSONArray) JSON.parse(data); JSONObject jo = new JSONObject(); jo.put("payload", ja); checkJsonOutput(jo, jsonString); } @Test public void testJsonSPL() throws Exception { final Topology t = new Topology(); TStream<String> example = t.strings(JSON_EXAMPLE); TStream<JSONObject> json = JSONStreams.deserialize(example); SPLStream spl = JSONStreams.toSPL(json); assertEquals(JSONSchemas.JSON, spl.getSchema()); TStream<JSONObject> jsonFromSPL = spl.toJSON(); assertEquals(JSONObject.class, jsonFromSPL.getTupleClass()); assertEquals(JSONObject.class, jsonFromSPL.getTupleType()); TStream<String> jsonString = JSONStreams.serialize(jsonFromSPL); checkJsonOutput(JSON.parse(JSON_EXAMPLE), jsonString); } @Test public void testFlatten() throws Exception { final Topology t = new Topology(); final JSONObject value = new JSONObject(); final JSONArray array = new JSONArray(); JSONObject e1 = new JSONObject(); e1.put("val", "hello"); array.add(e1); JSONObject e2 = new JSONObject(); e2.put("val", "goodbye"); array.add(e2); JSONObject e3 = new JSONObject(); e3.put("val", "farewell"); array.add(e3); value.put("greetings", array); List<JSONObject> inputs = new ArrayList<>(); inputs.add(value); inputs.add(new JSONObject()); // no list present JSONObject emptyList = new JSONObject(); emptyList.put("greetings", new JSONArray()); inputs.add(emptyList); TStream<JSONObject> s = t.constants(inputs); TStream<JSONObject> jsonm = JSONStreams.flattenArray(s, "greetings"); TStream<String> output = JSONStreams.serialize(jsonm); completeAndValidate(output, 10, e1.toString(), e2.toString(), e3.toString()); } @Test public void testFlattenWithAttributes() throws Exception { final Topology t = new Topology(); JSONObject e1 = new JSONObject(); e1.put("val", "hello"); JSONObject e2 = new JSONObject(); e2.put("val", "goodbye"); e2.put("a", "def"); final JSONObject value = new JSONObject(); { value.put("a", "abc"); final JSONArray array = new JSONArray(); array.add(e1); array.add(e2); value.put("greetings", array); } List<JSONObject> inputs = new ArrayList<>(); inputs.add(value); final JSONObject value2 = new JSONObject(); { final JSONArray array2 = new JSONArray(); array2.add(e1.clone()); array2.add(e2.clone()); value2.put("greetings", array2); } inputs.add(value2); TStream<JSONObject> s = t.constants(inputs); TStream<JSONObject> jsonm = JSONStreams.flattenArray(s, "greetings", "a");; TStream<String> output = JSONStreams.serialize(jsonm); JSONObject e1r = (JSONObject) e1.clone(); e1r.put("a", "abc"); assertFalse(e1.containsKey("a")); completeAndValidate(output, 10, e1r.toString(), e2.toString(), e1.toString(), e2.toString()); } @Test public void testFlattenNoObjects() throws Exception { final Topology t = new Topology(); final JSONObject value = new JSONObject(); final JSONArray array = new JSONArray(); array.add("hello"); value.put("greetings", array); TStream<JSONObject> s = t.constants(Collections.singletonList(value)); TStream<JSONObject> jsonm = JSONStreams.flattenArray(s, "greetings"); TStream<String> output = JSONStreams.serialize(jsonm); JSONObject payload = new JSONObject(); payload.put("payload", "hello"); completeAndValidate(output, 10, payload.toString()); } }