From 00f85a42f8b34fe30c378c061cbbd381b081709e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 12 Nov 2014 22:56:42 +1300 Subject: [PATCH] JSON Refactor - move EJson into text.json package --- .../avaje/ebean/{ => text}/json/EJson.java | 27 +- .../ebean/{ => text}/json/EJsonReader.java | 82 +---- .../ebean/{ => text}/json/EJsonWriter.java | 15 +- .../server/deploy/BeanPropertyCompound.java | 4 +- .../server/text/json/DJsonContext.java | 2 +- .../server/type/ScalarTypePostgresHstore.java | 2 +- .../java/com/avaje/ebean/json/EJsonTests.java | 289 +++++++++++------- .../avaje/tests/text/json/TestJsonSimple.java | 4 +- 8 files changed, 211 insertions(+), 214 deletions(-) rename src/main/java/com/avaje/ebean/{ => text}/json/EJson.java (75%) rename src/main/java/com/avaje/ebean/{ => text}/json/EJsonReader.java (71%) rename src/main/java/com/avaje/ebean/{ => text}/json/EJsonWriter.java (97%) diff --git a/src/main/java/com/avaje/ebean/json/EJson.java b/src/main/java/com/avaje/ebean/text/json/EJson.java similarity index 75% rename from src/main/java/com/avaje/ebean/json/EJson.java rename to src/main/java/com/avaje/ebean/text/json/EJson.java index 75ca67566..16250549a 100644 --- a/src/main/java/com/avaje/ebean/json/EJson.java +++ b/src/main/java/com/avaje/ebean/text/json/EJson.java @@ -1,4 +1,4 @@ -package com.avaje.ebean.json; +package com.avaje.ebean.text.json; import java.io.IOException; import java.io.Reader; @@ -10,7 +10,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; /** - * Utility that converts between JSON content and java Maps/Lists. + * Utility that converts between JSON content and simple java Maps/Lists. */ public class EJson { @@ -91,31 +91,14 @@ public class EJson { * Parse the json and return as a List or Map. */ public static Object parse(Reader reader) throws IOException { - return EJsonReader.parse(reader, false); + return EJsonReader.parse(reader); } /** * Parse the json and return as a List or Map. */ public static Object parse(JsonParser parser) throws IOException { - return EJsonReader.parse(parser, false); - } - -// /** -// * Parse the json and return the next json value, List or Map. -// * This will not consume all the reader content and return once the -// * next json object, list or value is read. -// */ -// public static Object parsePartial(Reader reader) { -// return EJsonReader.parse(reader, true); -// } - - /** - * Parse the json and return the next json value, List or Map. - * This will not consume all the reader content and return once the - * next json object, list or value is read. - */ - public static Object parsePartial(JsonParser parser) throws IOException { - return EJsonReader.parse(parser, true); + return EJsonReader.parse(parser); } + } diff --git a/src/main/java/com/avaje/ebean/json/EJsonReader.java b/src/main/java/com/avaje/ebean/text/json/EJsonReader.java similarity index 71% rename from src/main/java/com/avaje/ebean/json/EJsonReader.java rename to src/main/java/com/avaje/ebean/text/json/EJsonReader.java index 4e715e97b..c9e8283bb 100644 --- a/src/main/java/com/avaje/ebean/json/EJsonReader.java +++ b/src/main/java/com/avaje/ebean/text/json/EJsonReader.java @@ -1,4 +1,4 @@ -package com.avaje.ebean.json; +package com.avaje.ebean.text.json; import java.io.IOException; import java.io.Reader; @@ -24,12 +24,12 @@ class EJsonReader { @SuppressWarnings("unchecked") static Map parseObject(Reader reader) throws IOException { - return (Map) parse(reader, false); + return (Map) parse(reader); } @SuppressWarnings("unchecked") static Map parseObject(JsonParser parser) throws IOException { - return (Map) parse(parser, false); + return (Map) parse(parser); } @SuppressWarnings("unchecked") @@ -39,40 +39,36 @@ class EJsonReader { @SuppressWarnings("unchecked") static List parseList(Reader reader) throws IOException { - return (List) parse(reader, false); + return (List) parse(reader); } @SuppressWarnings("unchecked") static List parseList(JsonParser parser) throws IOException { - return (List) parse(parser, false); + return (List) parse(parser); } static Object parse(String json) throws IOException { - return parse(new StringReader(json), false); + return parse(new StringReader(json)); } - static Object parse(Reader reader, boolean partial) throws IOException { - return parse(json.createParser(reader), partial); + static Object parse(Reader reader) throws IOException { + return parse(json.createParser(reader)); } - static Object parse(JsonParser parser, boolean partial) throws IOException { - return new EJsonReader(parser, partial).parseJson(); + static Object parse(JsonParser parser) throws IOException { + return new EJsonReader(parser).parseJson(); } private final JsonParser parser; - - //private final boolean partial; - + private int depth; private Stack stack; private Context currentContext; - - EJsonReader(JsonParser parser, boolean partial) { + EJsonReader(JsonParser parser) { this.parser = parser; - //this.partial = partial; } private void startArray() { @@ -98,10 +94,6 @@ class EJsonReader { private void end() { depth--; if (!stack.isEmpty()) { - - //if (currentContext != null) { - // Object value = currentContext.getValue(); - //} currentContext = stack.pop(currentContext); } } @@ -121,27 +113,6 @@ class EJsonReader { if (JsonToken.VALUE_NULL == token) { return null; } - -//// if (jp.nextToken() != JsonToken.START_OBJECT) { -//// throw new IOException("Expected data to start with an Object"); -//// } -//// TwitterEntry result = new TwitterEntry(); -//// // Iterate over object fields: -//// while (jp.nextToken() != JsonToken.END_OBJECT) { -//// String fieldName = jp.getCurrentName(); -//// // Let's move to value -//// jp.nextToken(); -//// -// if (!parser.hasNext()) { -// return null; -// } -// -// -// Object simpleValue = getSimpleValue(JsonToken); -// if (simpleValue != null) { -// // it is a simple string, number or boolean -// return simpleValue; -// } stack = new Stack(); // it is a object or array, process the first JsonToken @@ -158,35 +129,6 @@ class EJsonReader { throw new RuntimeException(e); } } - -// /** -// * See if the JsonToken is a value rather than object or array. -// *

-// * If just a value then return that value else return null. -// * @throws IOException -// */ -// private Object getSimpleValue(JsonToken JsonToken) throws IOException { -// -// switch (JsonToken) { -// case VALUE_STRING: -// return parser.getValueAsString(); -// -// case VALUE_NUMBER_INT: -// return parser.getLongValue(); -// -// case VALUE_NUMBER_FLOAT: -// return parser.getDecimalValue(); -// -// case VALUE_TRUE: -// return Boolean.TRUE; -// -// case VALUE_FALSE: -// return Boolean.FALSE; -// -// default: -// return null; -// } -// } /** * Process the JsonToken for objects and arrays. diff --git a/src/main/java/com/avaje/ebean/json/EJsonWriter.java b/src/main/java/com/avaje/ebean/text/json/EJsonWriter.java similarity index 97% rename from src/main/java/com/avaje/ebean/json/EJsonWriter.java rename to src/main/java/com/avaje/ebean/text/json/EJsonWriter.java index fad1281f8..470a35c73 100644 --- a/src/main/java/com/avaje/ebean/json/EJsonWriter.java +++ b/src/main/java/com/avaje/ebean/text/json/EJsonWriter.java @@ -1,4 +1,4 @@ -package com.avaje.ebean.json; +package com.avaje.ebean.text.json; import java.io.IOException; import java.io.StringWriter; @@ -20,7 +20,7 @@ class EJsonWriter { * Base jsonFactory implementation used when it is not passed in. */ static JsonFactory jsonFactory = new JsonFactory(); - + static String write(Object object) throws IOException { StringWriter writer = new StringWriter(200); write(object, writer); @@ -102,22 +102,21 @@ class EJsonWriter { private void writeNumber(String name, Number object) throws IOException { - if (object instanceof Long) { writeLong(name, object); } else if (object instanceof Integer) { writeInteger(name, object); - + } else if (object instanceof Double) { writeDouble(name, object); - + } else if (object instanceof BigDecimal) { writeBigDecimal(name, object); } else if (object instanceof BigInteger) { writeBigInteger(name, object); - + } else { writeGeneralNumber(name, object); } @@ -139,7 +138,7 @@ class EJsonWriter { if (name == null) { jsonGenerator.writeNumber((BigInteger) object); } else { - jsonGenerator.writeNumberField(name, ((BigInteger) object).longValue()); + jsonGenerator.writeNumberField(name, object.longValue()); } } @@ -186,7 +185,7 @@ class EJsonWriter { private void writeCollection(String name, Collection collection) throws IOException { if (name != null) { jsonGenerator.writeFieldName(name); - } + } jsonGenerator.writeStartArray(); for (Object object : collection) { writeJson(null, object); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java index 0adbffb64..4621cef24 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java @@ -8,7 +8,7 @@ import java.util.Map; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.config.ScalarTypeConverter; -import com.avaje.ebean.json.EJson; +import com.avaje.ebean.text.json.EJson; import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound; import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder; import com.avaje.ebeaninternal.server.el.ElPropertyValue; @@ -198,7 +198,7 @@ public class BeanPropertyCompound extends BeanProperty { return; } - Object value = EJson.parsePartial(ctx); + Object value = EJson.parse(ctx); if (value == null) { setValue(bean, null); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/text/json/DJsonContext.java b/src/main/java/com/avaje/ebeaninternal/server/text/json/DJsonContext.java index d47309c3d..b71c90318 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/text/json/DJsonContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/text/json/DJsonContext.java @@ -1,7 +1,7 @@ package com.avaje.ebeaninternal.server.text.json; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.json.EJson; +import com.avaje.ebean.text.json.EJson; import com.avaje.ebean.text.PathProperties; import com.avaje.ebean.text.json.JsonContext; import com.avaje.ebean.text.json.JsonWriteOptions; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java index 8023a56db..d2d9f8709 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -7,7 +7,7 @@ import java.sql.SQLException; import java.util.Map; import com.avaje.ebean.config.dbplatform.PostgresPlatform; -import com.avaje.ebean.json.EJson; +import com.avaje.ebean.text.json.EJson; import com.avaje.ebean.text.TextException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; diff --git a/src/test/java/com/avaje/ebean/json/EJsonTests.java b/src/test/java/com/avaje/ebean/json/EJsonTests.java index 668db9e47..42b5c161c 100644 --- a/src/test/java/com/avaje/ebean/json/EJsonTests.java +++ b/src/test/java/com/avaje/ebean/json/EJsonTests.java @@ -1,19 +1,20 @@ package com.avaje.ebean.json; -import java.io.IOException; -import java.util.Map; - +import com.avaje.ebean.text.json.EJson; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; import org.junit.Assert; import org.junit.Test; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; +import java.io.IOException; +import java.io.StringReader; +import java.util.List; +import java.util.Map; public class EJsonTests { @Test - public void test_map_simple() throws JsonParseException, IOException { + public void test_map_simple() throws IOException { JsonFactory factory = new JsonFactory(); @@ -28,108 +29,180 @@ public class EJsonTests { Assert.assertEquals("rob", map.get("name")); Assert.assertEquals(12L, map.get("age")); -// String jsonOutput = EJson.write(result); -// Assert.assertEquals(jsonInput, jsonOutput); + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_parseObject() throws IOException { + + JsonFactory factory = new JsonFactory(); + + String jsonInput = "{\"name\":\"rob\",\"age\":12}"; + + JsonParser jsonParser = factory.createParser(jsonInput); + + Object result = EJson.parseObject(jsonParser); + + Assert.assertTrue(result instanceof Map); + Map map = (Map)result; + Assert.assertEquals("rob", map.get("name")); + Assert.assertEquals(12L, map.get("age")); + + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_parseObject_reader() throws IOException { + + String jsonInput = "{\"name\":\"rob\",\"age\":12}"; + + StringReader reader = new StringReader(jsonInput); + + Object result = EJson.parseObject(reader); + + Assert.assertTrue(result instanceof Map); + Map map = (Map)result; + Assert.assertEquals("rob", map.get("name")); + Assert.assertEquals(12L, map.get("age")); + + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_map_nested() throws IOException { + + String jsonInput = "{\"name\":\"rob\",\"age\":12,\"org\":{\"name\":\"superorg\",\"rating\":4},\"nums\":[1,2,3]}"; + Object result = EJson.parse(jsonInput); + + Assert.assertTrue(result instanceof Map); + Map map = (Map)result; + Assert.assertEquals(4, map.size()); + Assert.assertEquals("rob", map.get("name")); + Assert.assertEquals(12L, map.get("age")); + + Map org = (Map)map.get("org"); + Assert.assertEquals("superorg", org.get("name")); + Assert.assertEquals(4L, org.get("rating")); + + List nums = (List)map.get("nums"); + Assert.assertEquals(3, nums.size()); + Assert.assertEquals(1L, nums.get(0)); + Assert.assertEquals(2L, nums.get(1)); + Assert.assertEquals(3L, nums.get(2)); + + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_map_withNull() throws IOException { + + String jsonInput = "{\"name\":\"rob\",\"age\":null}"; + Object result = EJson.parse(jsonInput); + + Assert.assertTrue(result instanceof Map); + Map map = (Map)result; + Assert.assertEquals("rob", map.get("name")); + Assert.assertNull(map.get("age")); + + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_list_simple() throws IOException { + + String jsonInput = "[\"name\",\"rob\",12,13]"; + List list = EJson.parseList(jsonInput); + + Assert.assertEquals(4, list.size()); + Assert.assertEquals("name", list.get(0)); + Assert.assertEquals("rob", list.get(1)); + Assert.assertEquals(12L, list.get(2)); + Assert.assertEquals(13L, list.get(3)); + + String jsonOutput = EJson.write(list); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_list_reader() throws IOException { + + String jsonInput = "[\"name\",\"rob\",12,13]"; + StringReader reader = new StringReader(jsonInput); + List list = EJson.parseList(reader); + + Assert.assertEquals(4, list.size()); + Assert.assertEquals("name", list.get(0)); + Assert.assertEquals("rob", list.get(1)); + Assert.assertEquals(12L, list.get(2)); + Assert.assertEquals(13L, list.get(3)); + + String jsonOutput = EJson.write(list); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_list_jsonParser() throws IOException { + + String jsonInput = "[\"name\",\"rob\",12,13]"; + + JsonFactory jsonFactory = new JsonFactory(); + JsonParser parser = jsonFactory.createParser(jsonInput); + + List list = EJson.parseList(parser); + + Assert.assertEquals(4, list.size()); + Assert.assertEquals("name", list.get(0)); + Assert.assertEquals("rob", list.get(1)); + Assert.assertEquals(12L, list.get(2)); + Assert.assertEquals(13L, list.get(3)); + + String jsonOutput = EJson.write(list); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @SuppressWarnings("unchecked") + @Test + public void test_list_ofMaps() throws IOException { + + String jsonInput = "[{\"name\":\"rob\",\"age\":12},{\"name\":\"mike\",\"age\":13}]"; + Object result = EJson.parse(jsonInput); + + Assert.assertTrue(result instanceof List); + + List> list = (List>)result; + Assert.assertEquals(2, list.size()); + Assert.assertEquals("rob", list.get(0).get("name")); + Assert.assertEquals(12L, list.get(0).get("age")); + Assert.assertEquals("mike", list.get(1).get("name")); + Assert.assertEquals(13L, list.get(1).get("age")); + + String jsonOutput = EJson.write(result); + Assert.assertEquals(jsonInput, jsonOutput); + } + + @Test + public void test_partial_read() throws IOException { + + String jsonInput = "{\"name\":\"rob\",\"age\":null,\"friend\":{\"name\":\"mike\",\"age\":13}},some more json would follow..."; + StringReader reader = new StringReader(jsonInput); + + Object result = EJson.parse(reader); + + Assert.assertTrue(result instanceof Map); + Map map = (Map)result; + Assert.assertEquals("rob", map.get("name")); + Assert.assertNull(map.get("age")); + + Map friend = (Map)map.get("friend"); + Assert.assertEquals("mike", friend.get("name")); + Assert.assertEquals(13L, friend.get("age")); + } - -// @Test -// public void test_map_nested() { -// -// String jsonInput = "{\"name\":\"rob\",\"age\":12,\"org\":{\"name\":\"superorg\",\"rating\":4},\"nums\":[1,2,3]}"; -// Object result = EJson.parse(jsonInput); -// -// Assert.assertTrue(result instanceof Map); -// Map map = (Map)result; -// Assert.assertEquals(4, map.size()); -// Assert.assertEquals("rob", map.get("name")); -// Assert.assertEquals(12L, map.get("age")); -// -// Map org = (Map)map.get("org"); -// Assert.assertEquals("superorg", org.get("name")); -// Assert.assertEquals(4L, org.get("rating")); -// -// List nums = (List)map.get("nums"); -// Assert.assertEquals(3, nums.size()); -// Assert.assertEquals(1L, nums.get(0)); -// Assert.assertEquals(2L, nums.get(1)); -// Assert.assertEquals(3L, nums.get(2)); -// -// String jsonOutput = EJson.write(result); -// Assert.assertEquals(jsonInput, jsonOutput); -// } -// -// @Test -// public void test_map_withNull() { -// -// String jsonInput = "{\"name\":\"rob\",\"age\":null}"; -// Object result = EJson.parse(jsonInput); -// -// Assert.assertTrue(result instanceof Map); -// Map map = (Map)result; -// Assert.assertEquals("rob", map.get("name")); -// Assert.assertNull(map.get("age")); -// -// String jsonOutput = EJson.write(result); -// Assert.assertEquals(jsonInput, jsonOutput); -// } -// -// @Test -// public void test_list_simple() { -// -// String jsonInput = "[\"name\",\"rob\",12,13]"; -// Object result = EJson.parse(jsonInput); -// -// Assert.assertTrue(result instanceof List); -// List list = (List)result; -// Assert.assertEquals(4, list.size()); -// Assert.assertEquals("name", list.get(0)); -// Assert.assertEquals("rob", list.get(1)); -// Assert.assertEquals(12L, list.get(2)); -// Assert.assertEquals(13L, list.get(3)); -// -// String jsonOutput = EJson.write(result); -// Assert.assertEquals(jsonInput, jsonOutput); -// } -// -// @SuppressWarnings("unchecked") -// @Test -// public void test_list_ofMaps() { -// -// String jsonInput = "[{\"name\":\"rob\",\"age\":12},{\"name\":\"mike\",\"age\":13}]"; -// Object result = EJson.parse(jsonInput); -// -// Assert.assertTrue(result instanceof List); -// -// List> list = (List>)result; -// Assert.assertEquals(2, list.size()); -// Assert.assertEquals("rob", list.get(0).get("name")); -// Assert.assertEquals(12L, list.get(0).get("age")); -// Assert.assertEquals("mike", list.get(1).get("name")); -// Assert.assertEquals(13L, list.get(1).get("age")); -// -// String jsonOutput = EJson.write(result); -// Assert.assertEquals(jsonInput, jsonOutput); -// } -// -// @Test -// public void test_partial_read() { -// -// String jsonInput = "{\"name\":\"rob\",\"age\":null,\"friend\":{\"name\":\"mike\",\"age\":13}},some more json would follow..."; -// StringReader reader = new StringReader(jsonInput); -// JsonParser parser = Json.createParser(reader); -// -// Object result = EJson.parsePartial(parser); -// -// Assert.assertTrue(result instanceof Map); -// Map map = (Map)result; -// Assert.assertEquals("rob", map.get("name")); -// Assert.assertNull(map.get("age")); -// -// Map friend = (Map)map.get("friend"); -// Assert.assertEquals("mike", friend.get("name")); -// Assert.assertEquals(13L, friend.get("age")); -// -// } } diff --git a/src/test/java/com/avaje/tests/text/json/TestJsonSimple.java b/src/test/java/com/avaje/tests/text/json/TestJsonSimple.java index d2aa86e16..d534584fa 100644 --- a/src/test/java/com/avaje/tests/text/json/TestJsonSimple.java +++ b/src/test/java/com/avaje/tests/text/json/TestJsonSimple.java @@ -14,7 +14,7 @@ import org.junit.Test; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; -import com.avaje.ebean.json.EJson; +import com.avaje.ebean.text.json.EJson; import com.avaje.ebean.text.json.JsonContext; public class TestJsonSimple extends BaseTestCase { @@ -28,7 +28,7 @@ public class TestJsonSimple extends BaseTestCase { final Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); LineNumberReader lineReader = new LineNumberReader(reader); - String readLine = null; + String readLine; StringBuilder sb = new StringBuilder(); while ((readLine = lineReader.readLine()) != null) {