From 7c705e2baa63bda1741833a25c531c3fb7af2c27 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 21 Aug 2015 08:20:22 +1200 Subject: [PATCH] #377 - Add back support for JsonWriteBeanVisitor --- .../ebean/text/json/JsonWriteBeanVisitor.java | 30 ++ .../ebean/text/json/JsonWriteOptions.java | 30 ++ .../com/avaje/ebean/text/json/JsonWriter.java | 167 +++++++ .../server/deploy/BeanListHelp.java | 4 +- .../server/deploy/BeanMapHelp.java | 4 +- .../server/deploy/BeanSetHelp.java | 4 +- .../server/text/json/DJsonContext.java | 3 +- .../server/text/json/WriteJson.java | 412 +++++++++++++----- .../ebeaninternal/server/type/JsonWriter.java | 88 ---- .../ebeaninternal/server/type/ScalarType.java | 1 + .../server/type/ScalarTypeBaseDate.java | 1 + .../server/type/ScalarTypeBaseDateTime.java | 1 + .../server/type/ScalarTypeBaseVarchar.java | 1 + .../server/type/ScalarTypeBigDecimal.java | 1 + .../server/type/ScalarTypeBoolean.java | 1 + .../server/type/ScalarTypeByte.java | 1 + .../server/type/ScalarTypeBytesBase.java | 1 + .../server/type/ScalarTypeBytesEncrypted.java | 1 + .../server/type/ScalarTypeDouble.java | 1 + .../server/type/ScalarTypeDuration.java | 1 + .../type/ScalarTypeEncryptedWrapper.java | 1 + .../server/type/ScalarTypeEnumStandard.java | 1 + .../server/type/ScalarTypeFile.java | 1 + .../server/type/ScalarTypeFloat.java | 1 + .../server/type/ScalarTypeInteger.java | 1 + .../server/type/ScalarTypeJodaLocalTime.java | 1 + .../server/type/ScalarTypeJsonMap.java | 1 + .../server/type/ScalarTypeJsonNode.java | 1 + .../server/type/ScalarTypeLocalTime.java | 1 + .../server/type/ScalarTypeLong.java | 1 + .../server/type/ScalarTypeMathBigInteger.java | 1 + .../server/type/ScalarTypeMonthDay.java | 1 + .../server/type/ScalarTypePostgresHstore.java | 1 + .../server/type/ScalarTypeShort.java | 1 + .../server/type/ScalarTypeString.java | 1 + .../server/type/ScalarTypeTime.java | 1 + .../server/type/ScalarTypeUUIDBinary.java | 1 + .../server/type/ScalarTypeWrapper.java | 1 + .../server/type/ScalarTypeYear.java | 1 + .../ebeaninternal/server/util/ArrayStack.java | 4 + .../text/json/TestJsonWriteVisitor.java | 110 +++++ .../json/TestTextJsonBeanReadVisitor.java | 85 ++++ .../server/text/json/WriteJsonTest.java | 2 +- src/test/resources/junk.json | 228 ++++++++++ 44 files changed, 997 insertions(+), 204 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/text/json/JsonWriteBeanVisitor.java create mode 100644 src/main/java/com/avaje/ebean/text/json/JsonWriter.java delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/JsonWriter.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/text/json/TestJsonWriteVisitor.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/text/json/TestTextJsonBeanReadVisitor.java create mode 100644 src/test/resources/junk.json diff --git a/src/main/java/com/avaje/ebean/text/json/JsonWriteBeanVisitor.java b/src/main/java/com/avaje/ebean/text/json/JsonWriteBeanVisitor.java new file mode 100644 index 000000000..1ab885c81 --- /dev/null +++ b/src/main/java/com/avaje/ebean/text/json/JsonWriteBeanVisitor.java @@ -0,0 +1,30 @@ +package com.avaje.ebean.text.json; + +/** + * Allows for customising the JSON write processing. + *

+ * You can use this to add raw JSON content via {@link JsonWriter}. + *

+ * You register a JsonWriteBeanVisitor with {@link JsonWriteOptions}. + *

+ * + * @param + * the type of entity bean + * + * @see JsonWriteOptions + */ +public interface JsonWriteBeanVisitor { + + /** + * Visit the bean that has just been writing it's content to JSON. You can + * write your own additional JSON content to the JsonWriter if you wish. + * + * @param bean + * the bean that has been writing it's content + * @param jsonWriter + * the JsonWriter which you can append custom json content to if you + * wish. + */ + void visit(T bean, JsonWriter jsonWriter); + +} diff --git a/src/main/java/com/avaje/ebean/text/json/JsonWriteOptions.java b/src/main/java/com/avaje/ebean/text/json/JsonWriteOptions.java index 8c2999a85..cfdfeb36d 100644 --- a/src/main/java/com/avaje/ebean/text/json/JsonWriteOptions.java +++ b/src/main/java/com/avaje/ebean/text/json/JsonWriteOptions.java @@ -3,6 +3,9 @@ package com.avaje.ebean.text.json; import com.avaje.ebean.config.JsonConfig; import com.avaje.ebean.text.PathProperties; +import java.util.HashMap; +import java.util.Map; + /** * Provides options for customising the JSON write process. *

@@ -18,6 +21,8 @@ public class JsonWriteOptions { protected JsonConfig.Include include; + protected Map> visitorMap; + /** * Parse and return a PathProperties from nested string format like * (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a @@ -67,6 +72,31 @@ public class JsonWriteOptions { this.include = include; } + /** + * Register a JsonWriteBeanVisitor for the root level. + */ + public JsonWriteOptions setRootPathVisitor(JsonWriteBeanVisitor visitor) { + return setPathVisitor(null, visitor); + } + + /** + * Register a JsonWriteBeanVisitor for the given path. + */ + public JsonWriteOptions setPathVisitor(String path, JsonWriteBeanVisitor visitor) { + if (visitorMap == null) { + visitorMap = new HashMap>(); + } + visitorMap.put(path, visitor); + return this; + } + + /** + * Return the Map of registered JsonWriteBeanVisitor's by path. + */ + public Map> getVisitorMap() { + return visitorMap; + } + /** * Return the jackson object mapper to use. *

diff --git a/src/main/java/com/avaje/ebean/text/json/JsonWriter.java b/src/main/java/com/avaje/ebean/text/json/JsonWriter.java new file mode 100644 index 000000000..91bd95068 --- /dev/null +++ b/src/main/java/com/avaje/ebean/text/json/JsonWriter.java @@ -0,0 +1,167 @@ +package com.avaje.ebean.text.json; + +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.InputStream; +import java.math.BigDecimal; + +/** + * Wraps an underlying JsonGenerator taking into account null suppression and exposing isIncludeEmpty() etc. + */ +public interface JsonWriter { + + /** + * Return the Jackson core JsonGenerator. + */ + JsonGenerator gen(); + + /** + * Return true if null values should be included in JSON output. + */ + boolean isIncludeNull(); + + /** + * Return true if empty collections should be included in the JSON output. + */ + boolean isIncludeEmpty(); + + /** + * Write a field name followed by object start. + */ + void writeStartObject(String key); + + /** + * Write a object start. + */ + void writeStartObject(); + + /** + * Write a object end. + */ + void writeEndObject(); + + /** + * Write a field name followed by array start. + */ + void writeStartArray(String key); + + /** + * Write a array start. + */ + void writeStartArray(); + + /** + * Write a array end. + */ + void writeEndArray(); + + /** + * Write the field name. + */ + void writeFieldName(String name); + + /** + * Write a null value taking into account null value suppression. + */ + void writeNullField(String name); + + /** + * Write a number field. + */ + void writeNumberField(String name, int value); + + /** + * Write a number field. + */ + void writeNumberField(String name, short value); + + /** + * Write a number field. + */ + void writeNumberField(String name, long value); + + /** + * Write a number field. + */ + void writeNumberField(String name, double value); + + /** + * Write a number field. + */ + void writeNumberField(String name, float value); + + /** + * Write a number field. + */ + void writeNumberField(String name, BigDecimal value); + + /** + * Write a sting field. + */ + void writeStringField(String name, String value); + + /** + * Write a binary field. + */ + void writeBinary(InputStream is, int length); + + /** + * Write a binary field. + */ + void writeBinaryField(String name, byte[] value); + + /** + * Write a boolean field. + */ + void writeBooleanField(String name, boolean value); + + /** + * Write a boolean value (typically inside a list). + */ + void writeBoolean(boolean value); + + /** + * Write a string value (typically inside a list). + */ + void writeString(String value); + + /** + * Write a int value (typically inside a list). + */ + void writeNumber(int value); + + /** + * Write a long value (typically inside a list). + */ + void writeNumber(long value); + + /** + * Write a BigDecimal value (typically inside a list). + */ + void writeNumber(BigDecimal value); + + /** + * Write a null value. + */ + void writeNull(); + + /** + * Method that will force generator to copy + * input text verbatim with no modifications (including + * that no escaping is done and no separators are added even + * if context [array, object] would otherwise require such). + * If such separators are desired, use + * {@link #writeRawValue(String)} instead. + */ + void writeRaw(String text); + + /** + * Method that will force generator to copy + * input text verbatim without any modifications, but assuming + * it must constitute a single legal JSON value (number, string, + * boolean, null, Array or List). Assuming this, proper separators + * are added if and as needed (comma or colon), and generator + * state updated to reflect this. + */ + void writeRawValue(String text); +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java index 508cbd2c8..8f4dd78d3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java @@ -141,11 +141,11 @@ public final class BeanListHelp implements BeanCollectionHelp { } if (!list.isEmpty() || ctx.isIncludeEmpty()) { - ctx.writeStartArray(name); + ctx.beginAssocMany(name); for (int j = 0; j < list.size(); j++) { targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j)); } - ctx.writeEndArray(); + ctx.endAssocMany(); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java index c299e7893..143c2db2e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java @@ -179,12 +179,12 @@ public final class BeanMapHelp implements BeanCollectionHelp { } if (!map.isEmpty() || ctx.isIncludeEmpty()) { - ctx.writeStartArray(name); + ctx.beginAssocMany(name); for (Entry entry : map.entrySet()) { //FIXME: json write map key ... targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue()); } - ctx.writeEndArray(); + ctx.endAssocMany(); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java index 73ad8b5df..38ca39ea2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java @@ -140,11 +140,11 @@ public final class BeanSetHelp implements BeanCollectionHelp { } if (!set.isEmpty() || ctx.isIncludeEmpty()) { - ctx.writeStartArray(name); + ctx.beginAssocMany(name); for (Object bean : set) { targetDescriptor.jsonWrite(ctx, (EntityBean) bean); } - ctx.writeEndArray(); + ctx.endAssocMany(); } } } 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 f5159797b..59b614e51 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 @@ -286,7 +286,8 @@ public class DJsonContext implements JsonContext { private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) { PathProperties pathProps = (options == null) ? null : options.getPathProperties(); - return new WriteJson(server, gen, pathProps, determineObjectMapper(options), determineInclude(options)); + Map> visitors = (options == null) ? null : options.getVisitorMap(); + return new WriteJson(server, gen, pathProps, visitors, determineObjectMapper(options), determineInclude(options)); } private void toJsonFromCollection(Collection collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException { diff --git a/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJson.java b/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJson.java index 9e91ff67b..9027599f1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJson.java +++ b/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJson.java @@ -3,10 +3,12 @@ package com.avaje.ebeaninternal.server.text.json; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.config.JsonConfig; import com.avaje.ebean.text.PathProperties; +import com.avaje.ebean.text.json.JsonIOException; +import com.avaje.ebean.text.json.JsonWriteBeanVisitor; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanProperty; -import com.avaje.ebeaninternal.server.type.JsonWriter; import com.avaje.ebeaninternal.server.util.ArrayStack; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; @@ -21,11 +23,13 @@ import java.util.Set; public class WriteJson implements JsonWriter { private final SpiEbeanServer server; - + private final JsonGenerator generator; - + private final PathProperties pathProperties; + private final Map> visitors; + private final PathStack pathStack; private final ArrayStack parentBeans; @@ -37,10 +41,13 @@ public class WriteJson implements JsonWriter { /** * Construct for full bean use (normal). */ - public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties, Object objectMapper, JsonConfig.Include include){ + public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties, + Map> visitors, Object objectMapper, JsonConfig.Include include) { + this.server = server; this.generator = generator; this.pathProperties = pathProperties; + this.visitors = visitors; this.objectMapper = objectMapper; this.include = include; this.parentBeans = new ArrayStack(); @@ -50,9 +57,10 @@ public class WriteJson implements JsonWriter { /** * Construct for Json scalar use. */ - public WriteJson(JsonGenerator generator, JsonConfig.Include include){ + public WriteJson(JsonGenerator generator, JsonConfig.Include include) { this.generator = generator; this.include = include; + this.visitors = null; this.server = null; this.pathProperties = null; this.objectMapper = null; @@ -74,72 +82,253 @@ public class WriteJson implements JsonWriter { return include != JsonConfig.Include.NON_EMPTY; } + @Override public JsonGenerator gen() { return generator; } @Override - public void writeFieldName(String name) throws IOException { - generator.writeFieldName(name); - } - - @Override - public void writeNullField(String name) throws IOException { - if (isIncludeNull()) { - generator.writeNullField(name); + public void writeStartObject(String key) { + try { + if (key != null) { + generator.writeFieldName(key); + } + generator.writeStartObject(); + } catch (IOException e) { + throw new JsonIOException(e); } } @Override - public void writeNumberField(String name, Long value) throws IOException { - generator.writeNumberField(name, value); + public void writeStartObject() { + try { + generator.writeStartObject(); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeNumberField(String name, Double value) throws IOException { - generator.writeNumberField(name, value); + public void writeEndObject() { + try { + generator.writeEndObject(); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeNumberField(String name, int value) throws IOException { - generator.writeNumberField(name, value); + public void writeStartArray(String key) { + try { + if (key != null) { + generator.writeFieldName(key); + } + generator.writeStartArray(); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeNumberField(String name, Short value) throws IOException { - generator.writeNumberField(name, value); + public void writeStartArray() { + try { + generator.writeStartArray(); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeEndArray() { + try { + generator.writeEndArray(); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeRaw(String text) { + try { + generator.writeRaw(text); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeRawValue(String text) { + try { + generator.writeRawValue(text); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeFieldName(String name) { + try { + generator.writeFieldName(name); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNullField(String name) { + if (isIncludeNull()) { + try { + generator.writeNullField(name); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + } + + @Override + public void writeNumberField(String name, long value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumberField(String name, double value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumberField(String name, int value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumberField(String name, short value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeNumberField(String name, Float value) throws IOException { - generator.writeNumberField(name, value); + public void writeNumberField(String name, float value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeNumberField(String name, BigDecimal value) throws IOException { - generator.writeNumberField(name, value); + public void writeNumberField(String name, BigDecimal value) { + try { + generator.writeNumberField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeStringField(String name, String value) throws IOException { - generator.writeStringField(name, value); + public void writeStringField(String name, String value) { + try { + generator.writeStringField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeBinary(InputStream is, int length) throws IOException { - generator.writeBinary(is, length); + public void writeBinary(InputStream is, int length) { + try { + generator.writeBinary(is, length); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeBinaryField(String name, byte[] value) throws IOException { - generator.writeBinaryField(name, value); + public void writeBinaryField(String name, byte[] value) { + try { + generator.writeBinaryField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } @Override - public void writeBooleanField(String name, Boolean value) throws IOException { - generator.writeBooleanField(name, value); + public void writeBooleanField(String name, boolean value) { + try { + generator.writeBooleanField(name, value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeBoolean(boolean value) { + try { + generator.writeBoolean(value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeString(String value) { + try { + generator.writeString(value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumber(int value) { + try { + generator.writeNumber(value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumber(long value) { + try { + generator.writeNumber(value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNumber(BigDecimal value) { + try { + generator.writeNumber(value); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + @Override + public void writeNull() { + try { + generator.writeNull(); + } catch (IOException e) { + throw new JsonIOException(e); + } } public boolean isParentBean(Object bean) { @@ -164,65 +353,90 @@ public class WriteJson implements JsonWriter { pathStack.pop(); } + public void beginAssocMany(String key) { + try { + pathStack.pushPathKey(key); + generator.writeFieldName(key); + generator.writeStartArray(); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + + public void endAssocMany() { + try { + pathStack.pop(); + generator.writeEndArray(); + } catch (IOException e) { + throw new JsonIOException(e); + } + } + public WriteBean createWriteBean(BeanDescriptor desc, EntityBean bean) { + String path = pathStack.peekWithNull(); + JsonWriteBeanVisitor visitor = (visitors == null) ? null : visitors.get(path); if (pathProperties == null) { - return new WriteBean(desc, bean); + return new WriteBean(desc, bean, visitor); } - + boolean explicitAllProps = false; - Set currentIncludeProps = pathProperties.get(pathStack.peekWithNull()); + Set currentIncludeProps = pathProperties.get(path); if (currentIncludeProps != null) { explicitAllProps = currentIncludeProps.contains("*"); if (explicitAllProps || currentIncludeProps.isEmpty()) { currentIncludeProps = null; } } - return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean); + return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean, visitor); } - public void writeValueUsingObjectMapper(String name, Object value) throws IOException { + public void writeValueUsingObjectMapper(String name, Object value) { if (!isIncludeEmpty()) { // check for suppression of empty collection or map - if (value instanceof Collection && ((Collection)value).isEmpty()) { + if (value instanceof Collection && ((Collection) value).isEmpty()) { // suppress empty collection return; - } else if (value instanceof Map && ((Map)value).isEmpty()) { + } else if (value instanceof Map && ((Map) value).isEmpty()) { // suppress empty map return; } } - generator.writeFieldName(name); - objectMapper().writeValue(generator, value); + try { + generator.writeFieldName(name); + objectMapper().writeValue(generator, value); + } catch (IOException e) { + throw new JsonIOException(e); + } } private ObjectMapper objectMapper() { if (objectMapper == null) { - throw new IllegalStateException( - "Jackson ObjectMapper required but not set. Expected to be set on either" - +" serverConfig"); + throw new IllegalStateException("Jackson ObjectMapper required but not set. Expected to be set on either serverConfig"); } - return (ObjectMapper)objectMapper; + return (ObjectMapper) objectMapper; } public static class WriteBean { - + final boolean explicitAllProps; final Set currentIncludeProps; final BeanDescriptor desc; final EntityBean currentBean; - - WriteBean(BeanDescriptor desc, EntityBean currentBean){ - this(desc, false, null, currentBean); + final JsonWriteBeanVisitor visitor; + + WriteBean(BeanDescriptor desc, EntityBean currentBean, JsonWriteBeanVisitor visitor) { + this(desc, false, null, currentBean, visitor); } - WriteBean(BeanDescriptor desc, boolean explicitAllProps, Set currentIncludeProps, EntityBean currentBean) { + WriteBean(BeanDescriptor desc, boolean explicitAllProps, Set currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) { super(); this.desc = desc; this.currentBean = currentBean; this.explicitAllProps = explicitAllProps; this.currentIncludeProps = currentIncludeProps; + this.visitor = visitor; } private boolean isReferenceOnly() { @@ -251,34 +465,43 @@ public class WriteJson implements JsonWriter { } } - public void write(WriteJson writeJson) throws IOException { - - BeanProperty beanProp = desc.getIdProperty(); - if (beanProp != null) { - if (isIncludeProperty(beanProp)) { - beanProp.jsonWrite(writeJson, currentBean); - } - } - - if (!isReferenceOnly()) { - // render all the properties and invoke lazy loading if required - BeanProperty[] props = desc.propertiesNonTransient(); - for (int j = 0; j < props.length; j++) { - if (isIncludeProperty(props[j])) { - props[j].jsonWrite(writeJson, currentBean); + @SuppressWarnings("unchecked") + public void write(WriteJson writeJson) { + + try { + BeanProperty beanProp = desc.getIdProperty(); + if (beanProp != null) { + if (isIncludeProperty(beanProp)) { + beanProp.jsonWrite(writeJson, currentBean); } } - props = desc.propertiesTransient(); - for (int j = 0; j < props.length; j++) { - if (isIncludeTransientProperty(props[j])) { - props[j].jsonWrite(writeJson, currentBean); + + if (!isReferenceOnly()) { + // render all the properties and invoke lazy loading if required + BeanProperty[] props = desc.propertiesNonTransient(); + for (int j = 0; j < props.length; j++) { + if (isIncludeProperty(props[j])) { + props[j].jsonWrite(writeJson, currentBean); + } + } + props = desc.propertiesTransient(); + for (int j = 0; j < props.length; j++) { + if (isIncludeTransientProperty(props[j])) { + props[j].jsonWrite(writeJson, currentBean); + } } } + + if (visitor != null) { + visitor.visit(currentBean, writeJson); + } + + } catch (IOException e) { + throw new JsonIOException(e); } } } - public Boolean includeMany(String key) { if (pathProperties != null) { String fullPath = pathStack.peekFullPath(key); @@ -287,15 +510,19 @@ public class WriteJson implements JsonWriter { return null; } - public void toJson(String name, Collection c) throws IOException { + public void toJson(String name, Collection c) { - beginAssocMany(name); + try { + beginAssocMany(name); - for (Object bean : c) { - BeanDescriptor d = getDescriptor(bean.getClass()); - d.jsonWrite(this, (EntityBean)bean, null); + for (Object bean : c) { + BeanDescriptor d = getDescriptor(bean.getClass()); + d.jsonWrite(this, (EntityBean) bean, null); + } + endAssocMany(); + } catch (IOException e) { + throw new JsonIOException(e); } - endAssocMany(); } private BeanDescriptor getDescriptor(Class cls) { @@ -306,36 +533,5 @@ public class WriteJson implements JsonWriter { return d; } - public void beginAssocMany(String key) throws IOException { - pathStack.pushPathKey(key); - generator.writeFieldName(key); - generator.writeStartArray(); - } - public void endAssocMany() throws IOException { - pathStack.pop(); - generator.writeEndArray(); - } - - public void writeStartArray(String key) throws IOException { - if (key != null) { - generator.writeFieldName(key); - } - generator.writeStartArray(); - } - - public void writeStartObject(String key) throws IOException { - if (key != null) { - generator.writeFieldName(key); - } - generator.writeStartObject(); - } - - public void writeEndObject() throws IOException { - generator.writeEndObject(); - } - - public void writeEndArray() throws IOException { - generator.writeEndArray(); - } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/JsonWriter.java b/src/main/java/com/avaje/ebeaninternal/server/type/JsonWriter.java deleted file mode 100644 index 469b1141f..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/type/JsonWriter.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.avaje.ebeaninternal.server.type; - -import com.fasterxml.jackson.core.JsonGenerator; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; - -/** - * Wraps an underlying JsonGenerator taking into account null suppression and exposing isIncludeEmpty() etc. - */ -public interface JsonWriter { - - /** - * Return the Jackson core JsonGenerator. - */ - JsonGenerator gen(); - - /** - * Return true if null values should be included in JSON output. - */ - boolean isIncludeNull(); - - /** - * Return true if empty collections should be included in the JSON output. - */ - boolean isIncludeEmpty(); - - /** - * Write the field name. - */ - void writeFieldName(String name) throws IOException; - - /** - * Write a null value taking into account null value suppression. - */ - void writeNullField(String name) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, int value) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, Short value) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, Long value) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, Double value) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, Float value) throws IOException; - - /** - * Write a number field. - */ - void writeNumberField(String name, BigDecimal value) throws IOException; - - /** - * Write a sting field. - */ - void writeStringField(String name, String value) throws IOException; - - /** - * Write a binary field. - */ - void writeBinary(InputStream is, int length) throws IOException; - - /** - * Write a binary field. - */ - void writeBinaryField(String name, byte[] value) throws IOException; - - /** - * Write a boolean field. - */ - void writeBooleanField(String name, Boolean value) throws IOException; -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java index 53541675a..c8982fa90 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.StringFormatter; import com.avaje.ebean.text.StringParser; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java index 633affe52..739d9e435 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java index 1b26404ef..934a0f323 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.config.JsonConfig; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java index bddffdaf1..5b0e932bd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java index 2016aac00..8426802f2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java index 7a3ce5d1f..94d85293e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java index 3dadd4759..32792670d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java index 6e751450b..30a230be6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java index cfcd10f23..412712398 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java index 7bb551eb9..c7918a8d4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java index e9a794208..2ed3169ce 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java index 1ec9d2d19..171dc277d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java index 0a8c2f6c1..6f9004242 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFile.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFile.java index bbbb5a5d2..be87a0542 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFile.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFile.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import org.slf4j.Logger; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java index b4986a965..2951bb638 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java index d2d916a64..9312cc0ae 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java index 57a184c7b..eff2bb282 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonMap.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonMap.java index a2c0ef7c0..8b12a8df8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonMap.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonMap.java @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; import com.avaje.ebean.text.json.EJson; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonNode.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonNode.java index a2e8c8d9f..ebccef7ab 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonNode.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonNode.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java index 4a96a7622..d80af485d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java index 535bb23db..8dffa3b56 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java index c5da1bd6b..93bb233db 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java index 1456ce8f7..9d491c091 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; 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 fd7c8e428..23e807408 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.config.dbplatform.DbType; import com.avaje.ebean.text.TextException; import com.avaje.ebean.text.json.EJson; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java index 4afa5eb9d..c6b4a2a97 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java index f949ad459..03f786240 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java index c19fc802c..74ed0871f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeUUIDBinary.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeUUIDBinary.java index f3ca97944..fb789c659 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeUUIDBinary.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeUUIDBinary.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeWrapper.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeWrapper.java index 179a0e63f..ac3b36b97 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeWrapper.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeWrapper.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.config.ScalarTypeConverter; +import com.avaje.ebean.text.json.JsonWriter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeYear.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeYear.java index 48c71bb5f..bb84595fb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeYear.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeYear.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebean.text.TextException; +import com.avaje.ebean.text.json.JsonWriter; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; diff --git a/src/main/java/com/avaje/ebeaninternal/server/util/ArrayStack.java b/src/main/java/com/avaje/ebeaninternal/server/util/ArrayStack.java index 951282205..42761dabf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/util/ArrayStack.java +++ b/src/main/java/com/avaje/ebeaninternal/server/util/ArrayStack.java @@ -26,6 +26,10 @@ public class ArrayStack { this.list = new ArrayList(); } + public String toString() { + return list.toString(); + } + /** * Pushes an item onto the top of this stack. */ diff --git a/src/test/java/com/avaje/ebeaninternal/server/text/json/TestJsonWriteVisitor.java b/src/test/java/com/avaje/ebeaninternal/server/text/json/TestJsonWriteVisitor.java new file mode 100644 index 000000000..2c29e4c61 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/text/json/TestJsonWriteVisitor.java @@ -0,0 +1,110 @@ +package com.avaje.ebeaninternal.server.text.json; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.text.json.JsonContext; +import com.avaje.ebean.text.json.JsonWriteBeanVisitor; +import com.avaje.ebean.text.json.JsonWriteOptions; +import com.avaje.ebean.text.json.JsonWriter; +import com.avaje.tests.model.basic.Address; +import com.avaje.tests.model.basic.Contact; +import com.avaje.tests.model.basic.Country; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestJsonWriteVisitor extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + List list = Ebean.find(Customer.class) + .select("id, name, status") + .fetch("billingAddress", "line1, city") + .fetch("billingAddress.country", "*") + .fetch("contacts", "firstName,email") + .order().desc("id") + .findList(); + + JsonContext json = Ebean.json(); + + JsonWriteOptions options = new JsonWriteOptions(); + options.setRootPathVisitor(new CustomerVisitor()); + options.setPathVisitor("billingAddress", new BillingVisitor()); + options.setPathVisitor("billingAddress.country", new CountryVisitor()); + options.setPathVisitor("contacts", new ContactVisitor()); + + String jsonContent = json.toJson(list, options); + System.out.println(jsonContent); + + assertThat(jsonContent).contains("customerExtra"); + assertThat(jsonContent).contains("contactExtra"); + assertThat(jsonContent).contains("billingExtra"); + assertThat(jsonContent).contains("countryExtra"); + } + + class CustomerVisitor implements JsonWriteBeanVisitor { + + @Override + public void visit(Customer bean, JsonWriter jsonWriter) { + jsonWriter.writeStringField("customerExtra", "extra4"); + jsonWriter.writeStartObject("startObj"); + jsonWriter.writeBooleanField("yesno", true); + jsonWriter.writeEndObject(); + + jsonWriter.writeFieldName("secObj"); + jsonWriter.writeStartObject(); + jsonWriter.writeBooleanField("yesno", false); + jsonWriter.writeEndObject(); + + jsonWriter.writeStartArray("startList"); + jsonWriter.writeBoolean(true); + jsonWriter.writeString("one"); + jsonWriter.writeNumber(1); + jsonWriter.writeNumber(2L); + jsonWriter.writeNumber(new BigDecimal("34.45")); + jsonWriter.writeNull(); + jsonWriter.writeEndArray(); + + jsonWriter.writeFieldName("secondList"); + jsonWriter.writeStartArray(); + jsonWriter.writeNumber(3L); + jsonWriter.writeRawValue("\"rawVal\""); + jsonWriter.writeEndArray(); + + jsonWriter.writeRaw(",\"rawField\":{\"ra\":42}"); + + } + } + + class ContactVisitor implements JsonWriteBeanVisitor { + + @Override + public void visit(Contact bean, JsonWriter jsonWriter) { + jsonWriter.writeStringField("contactExtra", "extra3"); + } + } + + class BillingVisitor implements JsonWriteBeanVisitor
{ + + @Override + public void visit(Address bean, JsonWriter jsonWriter) { + jsonWriter.writeStringField("billingExtra", "extra1"); + } + } + + class CountryVisitor implements JsonWriteBeanVisitor { + + @Override + public void visit(Country bean, JsonWriter jsonWriter) { + jsonWriter.writeStringField("countryExtra", "extra2"); + } + } +} diff --git a/src/test/java/com/avaje/ebeaninternal/server/text/json/TestTextJsonBeanReadVisitor.java b/src/test/java/com/avaje/ebeaninternal/server/text/json/TestTextJsonBeanReadVisitor.java new file mode 100644 index 000000000..420b0b91f --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/text/json/TestTextJsonBeanReadVisitor.java @@ -0,0 +1,85 @@ +package com.avaje.ebeaninternal.server.text.json; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.text.json.JsonContext; +import com.avaje.ebean.text.json.JsonReadBeanVisitor; +import com.avaje.ebean.text.json.JsonReadOptions; +import com.avaje.tests.model.basic.Address; +import com.avaje.tests.model.basic.Contact; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import java.io.StringReader; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class TestTextJsonBeanReadVisitor extends BaseTestCase { + + + @Test + public void test() { + + ResetBasicData.reset(); + + List list = Ebean.find(Customer.class) + .select("id, name, status, shippingAddress") + .fetch("billingAddress", "line1, city") + .fetch("billingAddress.country", "*") + .fetch("contacts", "firstName,email") + .order().desc("id") + .findList(); + + JsonContext json = Ebean.json(); + + JsonReadOptions options = new JsonReadOptions(); + options.addRootVisitor(new CVisitor()); + options.addVisitor("contacts", new ContactVisitor()); + options.addVisitor("billingAddress", new AVisitor()); + options.addVisitor("shippingAddress", new ASVisitor()); + + String s = json.toJson(list); + System.out.println(s); + + List mList = json.toList(Customer.class, s, options); + System.out.println("VIA STRING: " + mList); + + StringReader reader = new StringReader(s); + List mList2 = json.toList(Customer.class, reader); + System.out.println("VIA READER: " + mList2); + + assertEquals(mList.size(), mList2.size()); + } + + private static class CVisitor implements JsonReadBeanVisitor { + + @Override + public void visit(Customer bean, Map unmapped) { + System.out.println("visit customer: " + bean); + } + } + + private static class AVisitor implements JsonReadBeanVisitor
{ + + public void visit(Address bean, Map unmapped) { + System.out.println("visit billing address: " + bean); + } + } + + private static class ASVisitor implements JsonReadBeanVisitor
{ + + public void visit(Address bean, Map unmapped) { + System.out.println("visit shipping address: " + bean); + } + } + + private static class ContactVisitor implements JsonReadBeanVisitor { + + public void visit(Contact bean, Map unmapped) { + System.out.println("visit contact: " + bean); + } + } +} diff --git a/src/test/java/com/avaje/ebeaninternal/server/text/json/WriteJsonTest.java b/src/test/java/com/avaje/ebeaninternal/server/text/json/WriteJsonTest.java index 21409146e..bc5219455 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/text/json/WriteJsonTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/text/json/WriteJsonTest.java @@ -20,7 +20,7 @@ public class WriteJsonTest { JsonGenerator generator = jsonFactory.createGenerator(new StringWriter()); PathProperties pathProperties = PathProperties.parse("id,status,name,customer(id,name,address(street,city)),orders(qty,product(sku,prodName))"); - WriteJson writeJson = new WriteJson(null, generator, pathProperties, null, JsonConfig.Include.ALL); + WriteJson writeJson = new WriteJson(null, generator, pathProperties, null, null, JsonConfig.Include.ALL); WriteJson.WriteBean rootLevel = writeJson.createWriteBean(null, null); assertTrue(rootLevel.currentIncludeProps.contains("id")); diff --git a/src/test/resources/junk.json b/src/test/resources/junk.json new file mode 100644 index 000000000..efe1c09ee --- /dev/null +++ b/src/test/resources/junk.json @@ -0,0 +1,228 @@ +[ + { + "id": 4, + "status": "ACTIVE", + "name": "NocCust", + "billingAddress": { + "id": 5, + "line1": "Bos town", + "city": "Auckland", + "country": { + "code": "NZ", + "name": "New Zealand", + "countryExtra": "extra2" + }, + "billingExtra": "extra1" + }, + "contacts": [ + { + "id": 10, + "firstName": "Jim1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 11, + "firstName": "Fred1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 12, + "firstName": "Bugs1", + "email": null, + "contactExtra": "extra3" + } + ], + "selected": null, + "customerExtra": "extra4", + "startObj": { + "yesno": true + }, + "secObj": { + "yesno": false + }, + "startList": [ + true, + "one", + 1, + 2, + 34.45, + null + ], + "secondList": [ + 3, + "rawVal" + ], + "rawField": { + "ra": 42 + } + }, + { + "id": 3, + "status": "ACTIVE", + "name": "Fiona", + "billingAddress": { + "id": 3, + "line1": "West Coast Rd", + "city": "Auckland", + "country": { + "code": "NZ", + "name": "New Zealand", + "countryExtra": "extra2" + }, + "billingExtra": "extra1" + }, + "contacts": [ + { + "id": 5, + "firstName": "Jim1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 6, + "firstName": "Fred1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 7, + "firstName": "Bugs1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 8, + "firstName": "Fiona", + "email": "black2@test.com", + "contactExtra": "extra3" + }, + { + "id": 9, + "firstName": "Tracy", + "email": "red3@test.com", + "contactExtra": "extra3" + } + ], + "selected": null, + "customerExtra": "extra4", + "startObj": { + "yesno": true + }, + "secObj": { + "yesno": false + }, + "startList": [ + true, + "one", + 1, + 2, + 34.45, + null + ], + "secondList": [ + 3, + "rawVal" + ], + "rawField": { + "ra": 42 + } + }, + { + "id": 2, + "status": "NEW", + "name": "Cust NoAddress", + "billingAddress": null, + "contacts": [ + { + "id": 4, + "firstName": "Jack", + "email": "black1@test.com", + "contactExtra": "extra3" + } + ], + "selected": null, + "customerExtra": "extra4", + "startObj": { + "yesno": true + }, + "secObj": { + "yesno": false + }, + "startList": [ + true, + "one", + 1, + 2, + 34.45, + null + ], + "secondList": [ + 3, + "rawVal" + ], + "rawField": { + "ra": 42 + } + }, + { + "id": 1, + "status": "NEW", + "name": "Rob", + "billingAddress": { + "id": 1, + "line1": "P.O.Box 1234", + "city": "Auckland", + "country": { + "code": "NZ", + "name": "New Zealand", + "countryExtra": "extra2" + }, + "billingExtra": "extra1" + }, + "contacts": [ + { + "id": 1, + "firstName": "Jim1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 2, + "firstName": "Fred1", + "email": null, + "contactExtra": "extra3" + }, + { + "id": 3, + "firstName": "Bugs1", + "email": null, + "contactExtra": "extra3" + } + ], + "selected": null, + "customerExtra": "extra4", + "startObj": { + "yesno": true + }, + "secObj": { + "yesno": false + }, + "startList": [ + true, + "one", + 1, + 2, + 34.45, + null + ], + "secondList": [ + 3, + "rawVal" + ], + "rawField": { + "ra": 42 + } + } +] \ No newline at end of file