diff --git a/src/main/java/com/avaje/ebean/json/EJson.java b/src/main/java/com/avaje/ebean/json/EJson.java index 2f9da3541..53cde48d6 100644 --- a/src/main/java/com/avaje/ebean/json/EJson.java +++ b/src/main/java/com/avaje/ebean/json/EJson.java @@ -8,36 +8,92 @@ import java.util.Map; import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; +/** + * Utility that converts between JSON content and java Maps/Lists. + */ public class EJson { + /** + * Write the nested Map/List as json. + */ public static String write(Object object) { return EJsonWriter.write(object); } + /** + * Write the nested Map/List as json to the writer. + */ public static void write(Object object, Writer writer) { EJsonWriter.write(object, writer); } + /** + * Write the nested Map/List as json to the jsonGenerator. + */ public static void write(Object object, JsonGenerator jsonGenerator) { EJsonWriter.write(object, jsonGenerator); } + /** + * Parse the json and return as a Map. + */ public static Map parseObject(String json) { return EJsonReader.parseObject(json); } + /** + * Parse the json and return as a Map taking a reader. + */ + public static Map parseObject(Reader reader) { + return EJsonReader.parseObject(reader); + } + + /** + * Parse the json and return as a Map taking a JsonParser. + */ + public static Map parseObject(JsonParser parser) { + return EJsonReader.parseObject(parser); + } + + /** + * Parse the json and return as a List. + */ public static List parseList(String json) { return EJsonReader.parseList(json); } + /** + * Parse the json and return as a List taking a Reader. + */ + public static List parseList(Reader reader) { + return EJsonReader.parseList(reader); + } + + /** + * Parse the json and return as a List taking a JsonParser. + */ + public static List parseList(JsonParser parser) { + return EJsonReader.parseList(parser); + } + + + /** + * Parse the json and return as a List or Map. + */ public static Object parse(String json) { return EJsonReader.parse(json); } + /** + * Parse the json and return as a List or Map. + */ public static Object parse(Reader reader) { return EJsonReader.parse(reader); } + /** + * Parse the json and return as a List or Map. + */ public static Object parse(JsonParser parser) { return EJsonReader.parse(parser); } diff --git a/src/main/java/com/avaje/ebean/json/EJsonReader.java b/src/main/java/com/avaje/ebean/json/EJsonReader.java index 1f37ed821..4d043205c 100644 --- a/src/main/java/com/avaje/ebean/json/EJsonReader.java +++ b/src/main/java/com/avaje/ebean/json/EJsonReader.java @@ -12,27 +12,47 @@ import javax.json.Json; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; -public class EJsonReader { +class EJsonReader { @SuppressWarnings("unchecked") - public static Map parseObject(String json) { + static Map parseObject(String json) { return (Map) parse(json); } - + @SuppressWarnings("unchecked") - public static List parseList(String json) { - return (List) parse(json); + static Map parseObject(Reader reader) { + return (Map) parse(reader); + } + + @SuppressWarnings("unchecked") + static Map parseObject(JsonParser parser) { + return (Map) parse(parser); } - public static Object parse(String json) { + @SuppressWarnings("unchecked") + static List parseList(String json) { + return (List) parse(json); + } + + @SuppressWarnings("unchecked") + static List parseList(Reader reader) { + return (List) parse(reader); + } + + @SuppressWarnings("unchecked") + static List parseList(JsonParser parser) { + return (List) parse(parser); + } + + static Object parse(String json) { return parse(new StringReader(json)); } - public static Object parse(Reader reader) { + static Object parse(Reader reader) { return parse(Json.createParser(reader)); } - public static Object parse(JsonParser parser) { + static Object parse(JsonParser parser) { return new EJsonReader(parser).parseJson(); } @@ -67,7 +87,11 @@ public class EJsonReader { private void end() { if (!stack.isEmpty()) { - currentContext = stack.pop(); + + //if (currentContext != null) { + // Object value = currentContext.getValue(); + //} + currentContext = stack.pop(currentContext); } } @@ -133,7 +157,7 @@ public class EJsonReader { return Boolean.FALSE; default: - return false; + return null; } } @@ -203,12 +227,13 @@ public class EJsonReader { } } - private Context pop() { + private Context pop(Context endingContext) { if (head == null) { throw new NoSuchElementException(); } Context temp = head; head = head.next; + temp.popContext(endingContext); return temp; } @@ -219,6 +244,7 @@ public class EJsonReader { private static abstract class Context { Context next; + abstract void popContext(Context temp); abstract Object getValue(); abstract void setKey(String key); abstract void setValue(Object value); @@ -231,6 +257,10 @@ public class EJsonReader { private String key; + public void popContext(Context temp) { + setValue(temp.getValue()); + } + Object getValue() { return map; } @@ -252,6 +282,10 @@ public class EJsonReader { private final List values = new ArrayList(); + public void popContext(Context temp) { + values.add(temp.getValue()); + } + Object getValue() { return values; } diff --git a/src/main/java/com/avaje/ebean/json/EJsonWriter.java b/src/main/java/com/avaje/ebean/json/EJsonWriter.java index 2f98c04b9..d378326d5 100644 --- a/src/main/java/com/avaje/ebean/json/EJsonWriter.java +++ b/src/main/java/com/avaje/ebean/json/EJsonWriter.java @@ -15,19 +15,19 @@ import javax.json.stream.JsonGenerator; class EJsonWriter { - public static String write(Object object) { + static String write(Object object) { StringWriter writer = new StringWriter(200); write(object, writer); return writer.toString(); } - public static void write(Object object, Writer writer) { + static void write(Object object, Writer writer) { JsonGenerator generator = Json.createGenerator(writer); write(object, generator); generator.close(); } - public static void write(Object object, JsonGenerator jsonGenerator) { + static void write(Object object, JsonGenerator jsonGenerator) { new EJsonWriter(jsonGenerator).writeJson(object); } @@ -174,7 +174,7 @@ class EJsonWriter { private void writeCollection(String name, Collection collection) { if (name == null) { - jsonGenerator.writeStartObject(); + jsonGenerator.writeStartArray(); } else { jsonGenerator.writeStartArray(name); } diff --git a/src/main/java/com/avaje/ebean/text/PathPropertiesParser.java b/src/main/java/com/avaje/ebean/text/PathPropertiesParser.java index d6bef851e..926eeaea1 100644 --- a/src/main/java/com/avaje/ebean/text/PathPropertiesParser.java +++ b/src/main/java/com/avaje/ebean/text/PathPropertiesParser.java @@ -53,6 +53,9 @@ class PathPropertiesParser { case '(': return currentWord(); default: + if (pos == 1) { + return ""; + } } } while (pos < eof); throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos); @@ -91,6 +94,10 @@ class PathPropertiesParser { } } while (pos < eof); + if (startPos < pos) { + String currentWord = source.substring(startPos, pos); + currentPathProps.addProperty(currentWord); + } } private void addSubpath() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCollectionHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCollectionHelp.java index 711d1496c..842e0545f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCollectionHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCollectionHelp.java @@ -9,7 +9,7 @@ import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.BeanCollectionLoader; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Helper functions for performing tasks on Lists Sets or Maps. @@ -62,6 +62,6 @@ public interface BeanCollectionHelp { /** * Write the collection out as json. */ - public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude); + public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 437269d41..369d646af 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -35,8 +35,6 @@ import com.avaje.ebean.event.BeanPersistListener; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.meta.MetaBeanInfo; import com.avaje.ebean.meta.MetaQueryPlanStatistic; -import com.avaje.ebean.text.TextException; -import com.avaje.ebean.text.json.JsonWriteBeanVisitor; import com.avaje.ebeaninternal.api.HashQueryPlan; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.api.SpiQuery; @@ -63,10 +61,7 @@ import com.avaje.ebeaninternal.server.query.CQueryPlan; import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot; import com.avaje.ebeaninternal.server.query.SplitName; import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail; -import com.avaje.ebeaninternal.server.text.json.ReadJsonContext; -import com.avaje.ebeaninternal.server.text.json.ReadJsonContext.ReadBeanState; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState; +import com.avaje.ebeaninternal.server.text.json.WriteJson; import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.type.TypeManager; import com.avaje.ebeaninternal.util.SortByClause; @@ -2121,84 +2116,16 @@ public class BeanDescriptor implements MetaBeanInfo { return propertiesLocal; } - public void jsonWrite(WriteJsonContext ctx, EntityBean bean) { - - if (bean != null) { - - ctx.appendObjectBegin(); - WriteBeanState prevState = ctx.pushBeanState(bean); - - if (inheritInfo != null) { - InheritInfo localInheritInfo = inheritInfo.readType(bean.getClass()); - String discValue = localInheritInfo.getDiscriminatorStringValue(); - String discColumn = localInheritInfo.getDiscriminatorColumn(); - ctx.appendDiscriminator(discColumn, discValue); - - BeanDescriptor localDescriptor = localInheritInfo.getBeanDescriptor(); - localDescriptor.jsonWriteProperties(ctx, bean); - - } else { - jsonWriteProperties(ctx, bean); - } - - ctx.pushPreviousState(prevState); - ctx.appendObjectEnd(); - } + public void jsonWrite(WriteJson writeJson, EntityBean bean) { + jsonHelp.jsonWrite(writeJson, bean, null); + } + + public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) { + jsonHelp.jsonWrite(writeJson, bean, key); } - @SuppressWarnings("unchecked") - private void jsonWriteProperties(WriteJsonContext ctx, EntityBean bean) { - - JsonWriteBeanVisitor beanVisitor = (JsonWriteBeanVisitor) ctx.getBeanVisitor(); - - Set props = ctx.getIncludeProperties(); - - boolean explicitAllProps; - if (props == null) { - explicitAllProps = false; - } else { - explicitAllProps = props.contains("*"); - if (explicitAllProps || props.isEmpty()) { - props = null; - } - } - - if (idProperty != null) { - Object idValue = idProperty.getValue(bean); - if (idValue != null) { - if (props == null || props.contains(idProperty.getName())) { - idProperty.jsonWrite(ctx, bean); - } - } - } - - if (!explicitAllProps && props == null) { - // just render the loaded properties - props = ((EntityBean)bean)._ebean_getIntercept().getLoadedPropertyNames(); - } - if (props != null) { - // render only the appropriate properties (when not all properties) - for (String prop : props) { - BeanProperty p = getBeanProperty(prop); - if (p != null && !p.isId()) { - p.jsonWrite(ctx, bean); - } - } - } else { - if (explicitAllProps || !isReference(bean._ebean_getIntercept())) { - // render all the properties and invoke lazy loading if required - for (int j = 0; j < propertiesNonTransient.length; j++) { - propertiesNonTransient[j].jsonWrite(ctx, bean); - } - for (int j = 0; j < propertiesTransient.length; j++) { - propertiesTransient[j].jsonWrite(ctx, bean); - } - } - } - - if (beanVisitor != null) { - beanVisitor.visit((T) bean, ctx); - } + protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) { + jsonHelp.jsonWriteProperties(writeJson, bean); } public T jsonRead(JsonParser parser, String path) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java index 8d93b3937..b6540e7db 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java @@ -1,111 +1,56 @@ package com.avaje.ebeaninternal.server.deploy; -import java.util.Set; - -import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.json.EJson; import com.avaje.ebean.text.TextException; -import com.avaje.ebean.text.json.JsonWriteBeanVisitor; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState; +import com.avaje.ebeaninternal.server.text.json.WriteJson; +import com.avaje.ebeaninternal.server.text.json.WriteJson.WriteBean; public class BeanDescriptorJsonHelp { private final BeanDescriptor desc; + private final InheritInfo inheritInfo; public BeanDescriptorJsonHelp(BeanDescriptor desc) { this.desc = desc; this.inheritInfo = desc.inheritInfo; } + + public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) { +// if (writeJson.hasBean()) { - public void jsonWrite(JsonGenerator ctx, EntityBean bean) { - - if (bean != null) { - - ctx.writeStartObject(); + writeJson.writeStartObject(key); //WriteBeanState prevState = ctx.pushBeanState(bean); - if (inheritInfo != null) { + if (inheritInfo == null) { + jsonWriteProperties(writeJson, bean); + + } else { InheritInfo localInheritInfo = inheritInfo.readType(bean.getClass()); String discValue = localInheritInfo.getDiscriminatorStringValue(); String discColumn = localInheritInfo.getDiscriminatorColumn(); - ctx.write(discColumn, discValue); - //ctx.appendDiscriminator(discColumn, discValue); + writeJson.gen().write(discColumn, discValue); BeanDescriptor localDescriptor = localInheritInfo.getBeanDescriptor(); - localDescriptor.jsonWriteProperties(ctx, bean); - - } else { - jsonWriteProperties(ctx, bean); - } + localDescriptor.jsonWriteProperties(writeJson, bean); + } //ctx.pushPreviousState(prevState); - //ctx.appendObjectEnd(); - ctx.writeEnd(); - } + writeJson.gen().writeEnd(); } - @SuppressWarnings("unchecked") - private void jsonWriteProperties(JsonGenerator ctx, EntityBean bean) { + protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) { - //JsonWriteBeanVisitor beanVisitor = (JsonWriteBeanVisitor) ctx.getBeanVisitor(); - - Set props = ctx.getIncludeProperties(); - - boolean explicitAllProps; - if (props == null) { - explicitAllProps = false; - } else { - explicitAllProps = props.contains("*"); - if (explicitAllProps || props.isEmpty()) { - props = null; - } - } - - if (desc.idProperty != null) { - Object idValue = desc.idProperty.getValue(bean); - if (idValue != null) { - if (props == null || props.contains(idProperty.getName())) { - idProperty.jsonWrite(ctx, bean); - } - } - } - - if (!explicitAllProps && props == null) { - // just render the loaded properties - props = ((EntityBean)bean)._ebean_getIntercept().getLoadedPropertyNames(); - } - if (props != null) { - // render only the appropriate properties (when not all properties) - for (String prop : props) { - BeanProperty p = getBeanProperty(prop); - if (p != null && !p.isId()) { - p.jsonWrite(ctx, bean); - } - } - } else { - if (explicitAllProps || !isReference(bean._ebean_getIntercept())) { - // render all the properties and invoke lazy loading if required - for (int j = 0; j < propertiesNonTransient.length; j++) { - propertiesNonTransient[j].jsonWrite(ctx, bean); - } - for (int j = 0; j < propertiesTransient.length; j++) { - propertiesTransient[j].jsonWrite(ctx, bean); - } - } - } - - if (beanVisitor != null) { - beanVisitor.visit((T) bean, ctx); - } + + WriteBean writeBean = writeJson.createWriteBean(desc, bean); + writeBean.write(writeJson); } - + + @SuppressWarnings("unchecked") public T jsonRead(JsonParser parser, String path) { @@ -124,7 +69,6 @@ public class BeanDescriptorJsonHelp { return jsonReadObject(parser, path); } - // check for the discriminator value to determine the correct sub type String discColumn = inheritInfo.getRoot().getDiscriminatorColumn(); @@ -135,6 +79,13 @@ public class BeanDescriptorJsonHelp { String propName = parser.getString(); if (!propName.equalsIgnoreCase(discColumn)) { + // just try to assume this is the correct bean type in the inheritance + BeanProperty property = desc.getBeanProperty(propName); + if (property != null) { + EntityBean bean = desc.createEntityBean(); + property.jsonRead(parser, bean); + return jsonReadProperties(parser, bean); + } String msg = "Error reading inheritance discriminator, expected property ["+discColumn+"] but got [" + propName + "] ?"; throw new TextException(msg); } @@ -152,12 +103,17 @@ public class BeanDescriptorJsonHelp { return (T) localDescriptor.jsonReadObject(parser, path); } - @SuppressWarnings("unchecked") protected T jsonReadObject(JsonParser parser, String path) { EntityBean bean = desc.createEntityBean(); //ctx.pushBean(bean, path, this); + return jsonReadProperties(parser, bean); + } + + @SuppressWarnings("unchecked") + protected T jsonReadProperties(JsonParser parser, EntityBean bean) { + do { if (parser.hasNext()) { @@ -169,7 +125,7 @@ public class BeanDescriptorJsonHelp { p.jsonRead(parser, bean); } else { - Object rawValue = EJson.parse(parser); + //Object rawValue = EJson.parse(parser); // unknown property key ... //ctx.readUnmappedJson(propName); } @@ -183,7 +139,6 @@ public class BeanDescriptorJsonHelp { } } while (true); - return (T)bean; } 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 25baefd49..71860bbd6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanListHelp.java @@ -12,7 +12,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.BeanCollectionLoader; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.common.BeanList; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Helper object for dealing with Lists. @@ -128,7 +128,7 @@ public final class BeanListHelp implements BeanCollectionHelp { } } - public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) { + public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) { List list; if (collection instanceof BeanCollection) { @@ -147,15 +147,11 @@ public final class BeanListHelp implements BeanCollectionHelp { list = (List) collection; } - ctx.beginAssocMany(name); + ctx.gen().writeStartArray(name); for (int j = 0; j < list.size(); j++) { - if (j > 0) { - ctx.appendComma(); - } - Object detailBean = list.get(j); - targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean); + targetDescriptor.jsonWrite(ctx, (EntityBean)list.get(j)); } - ctx.endAssocMany(); + ctx.gen().writeEnd(); } } 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 316aa2106..b4c6eb4bb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanMapHelp.java @@ -13,7 +13,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.BeanCollectionLoader; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.common.BeanMap; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Helper specifically for dealing with Maps. @@ -156,7 +156,7 @@ public final class BeanMapHelp implements BeanCollectionHelp { } } - public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) { + public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) { Map map; if (collection instanceof BeanCollection){ @@ -175,19 +175,14 @@ public final class BeanMapHelp implements BeanCollectionHelp { map = (Map)collection; } - int count = 0; - ctx.beginAssocMany(name); + ctx.gen().writeStartArray(name); Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); - if (count++ > 0){ - ctx.appendComma(); - } //FIXME: json write map key ... - Object detailBean = entry.getValue(); - targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean); + targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue()); } - ctx.endAssocMany(); + ctx.gen().writeEnd(); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java index 6c3813db7..f6ade3b2b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java @@ -10,7 +10,6 @@ import java.sql.Types; import java.util.List; import java.util.Map; -import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; import javax.persistence.PersistenceException; @@ -32,7 +31,7 @@ import com.avaje.ebeaninternal.server.query.SqlBeanLoad; import com.avaje.ebeaninternal.server.query.SqlJoinType; import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter; import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.type.ScalarType; @@ -1174,54 +1173,18 @@ public class BeanProperty implements ElPropertyValue { return name; } - - - @SuppressWarnings("unchecked") - public void jsonWrite(JsonGenerator ctx, EntityBean bean) { - if(!jsonSerialize){ - return; - } - Object value = getValueIntercept(bean); - if (value == null) { - ctx.writeNull(name); - } else { - scalarType.jsonWrite(ctx, name, value); - //ctx.appendNameValue(name, scalarType, value); - } + public void jsonWrite(WriteJson writeJson, EntityBean bean) { + if (!jsonSerialize) { + return; } - - @SuppressWarnings("unchecked") - public void jsonWrite(WriteJsonContext ctx, EntityBean bean) { - if(!jsonSerialize){ - return; - } - Object value = getValueIntercept(bean); - if (value == null) { - ctx.appendNull(name); - } else { - ctx.appendNameValue(name, scalarType, value); - } + Object value = getValueIntercept(bean); + if (value == null) { + writeJson.gen().writeNull(name); + } else { + scalarType.jsonWrite(writeJson.gen(), name, value); } + } -// public void jsonRead(ReadJsonContext ctx, EntityBean bean) { -// if(!jsonDeserialize){ -// return; -// } -// String jsonValue; -// try { -// jsonValue = ctx.readScalarValue(); -// } catch (TextException e){ -// throw new TextException("Error reading property "+getFullBeanName(), e); -// } -// Object objValue; -// if (jsonValue == null) { -// objValue = null; -// } else { -// objValue = scalarType.jsonFromString(jsonValue, ctx.getValueAdapter()); -// } -// setValue(bean, objValue); -// } - public void jsonRead(JsonParser ctx, EntityBean bean) { if (!jsonDeserialize) { return; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 5f8da9623..0f94035b2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -30,9 +30,7 @@ import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder; import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.lib.util.StringHelper; import com.avaje.ebeaninternal.server.query.SqlBeanLoad; -import com.avaje.ebeaninternal.server.text.json.ReadJsonContext; -import com.avaje.ebeaninternal.server.text.json.ReadJsonContext.ReadBeanState; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Property mapped to a List Set or Map. @@ -883,7 +881,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return null != targetDescriptor.getId(otherBean); } - public void jsonWrite(WriteJsonContext ctx, EntityBean bean) { + public void jsonWrite(WriteJson ctx, EntityBean bean) { if(!this.jsonSerialize){ return; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index b6ac0d47d..d0a7c964d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -25,8 +25,7 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.query.SplitName; import com.avaje.ebeaninternal.server.query.SqlBeanLoad; import com.avaje.ebeaninternal.server.query.SqlJoinType; -import com.avaje.ebeaninternal.server.text.json.ReadJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Property mapped to a joined bean. @@ -832,25 +831,23 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } @Override - public void jsonWrite(WriteJsonContext ctx, EntityBean bean) { + public void jsonWrite(WriteJson writeJson, EntityBean bean) { Object value = getValueIntercept(bean); if (value == null){ - ctx.beginAssocOneIsNull(name); + writeJson.gen().writeNull(name); } else { - if (ctx.isParentBean(value)){ + if (writeJson.isParentBean(value)){ // bi-directional and already rendered parent } else { // Hmmm, not writing complex non-entity bean if (value instanceof EntityBean) { - ctx.pushParentBean(bean); - ctx.beginAssocOne(name); + writeJson.beginAssocOne(name, bean); BeanDescriptor refDesc = descriptor.getBeanDescriptor(value.getClass()); - refDesc.jsonWrite(ctx, (EntityBean)value); - ctx.endAssocOne(); - ctx.popParentBean(); + refDesc.jsonWrite(writeJson, (EntityBean)value, name); + writeJson.endAssocOne(); } } } 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 00132e1d3..17b3f9ff1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java @@ -11,7 +11,7 @@ import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder; import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.query.SqlBeanLoad; import com.avaje.ebeaninternal.server.text.json.ReadJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; import com.avaje.ebeaninternal.server.type.CtCompoundProperty; import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter; import com.avaje.ebeaninternal.server.type.CtCompoundType; @@ -177,10 +177,10 @@ public class BeanPropertyCompound extends BeanProperty { return bean; } - public void jsonWrite(WriteJsonContext ctx, EntityBean bean) { + public void jsonWrite(WriteJson ctx, EntityBean bean) { Object valueObject = getValueIntercept(bean); - compoundType.jsonWrite(ctx, valueObject, name); + //FIXME: compoundType.jsonWrite(ctx, valueObject, name); } public void jsonRead(ReadJsonContext ctx, EntityBean bean){ 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 57ff5575c..bc2f09931 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanSetHelp.java @@ -12,7 +12,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.BeanCollectionLoader; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.common.BeanSet; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +import com.avaje.ebeaninternal.server.text.json.WriteJson; /** * Helper specifically for dealing with Sets. @@ -129,7 +129,7 @@ public final class BeanSetHelp implements BeanCollectionHelp { } } - public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) { + public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) { Set set; if (collection instanceof BeanCollection){ @@ -148,16 +148,11 @@ public final class BeanSetHelp implements BeanCollectionHelp { set = (Set)collection; } - int count = 0; - ctx.beginAssocMany(name); + ctx.gen().writeStartArray(name); Iterator it = set.iterator(); while (it.hasNext()) { - Object detailBean = it.next(); - if (count++ > 0){ - ctx.appendComma(); - } - targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean); + targetDescriptor.jsonWrite(ctx, (EntityBean)it.next()); } - ctx.endAssocMany(); + ctx.gen().writeEnd(); } } 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 582c72ac7..8b9ef652b 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 @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.text.json; import java.io.Reader; import java.io.StringReader; +import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Type; import java.util.ArrayList; @@ -13,10 +14,12 @@ import java.util.Map.Entry; import java.util.Set; import javax.json.Json; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.text.PathProperties; import com.avaje.ebean.text.TextException; import com.avaje.ebean.text.json.JsonContext; import com.avaje.ebean.text.json.JsonElement; @@ -25,7 +28,6 @@ import com.avaje.ebean.text.json.JsonValueAdapter; import com.avaje.ebean.text.json.JsonWriteOptions; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.type.EscapeJson; import com.avaje.ebeaninternal.util.ParamTypeHelper; import com.avaje.ebeaninternal.util.ParamTypeHelper.ManyType; import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo; @@ -37,293 +39,263 @@ import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo; */ public class DJsonContext implements JsonContext { - private final SpiEbeanServer server; - - private final JsonValueAdapter dfltValueAdapter; - - private final boolean dfltPretty; - - public DJsonContext(SpiEbeanServer server, JsonValueAdapter dfltValueAdapter, boolean dfltPretty){ - this.server = server; - this.dfltValueAdapter = dfltValueAdapter; - this.dfltPretty = dfltPretty; - } + private final SpiEbeanServer server; - public boolean isSupportedType(Type genericType) { - return server.isSupportedType(genericType); - } + //private final JsonValueAdapter dfltValueAdapter; - private JsonParser createReader(Reader jsonReader) { - return Json.createParser(jsonReader); - //return new ReadJsonSourceReader(jsonReader, 256, 512); - } - - public T toBean(Class cls, String json){ - return toBean(cls, new StringReader(json), null); - } - - public T toBean(Class cls, Reader jsonReader) { - return toBean(cls, createReader(jsonReader), null); - } - - public T toBean(Class cls, String json, JsonReadOptions options){ - return toBean(cls, new StringReader(json), options); - } + private final boolean dfltPretty; - public T toBean(Class cls, Reader jsonReader, JsonReadOptions options) { - return toBean(cls, createReader(jsonReader), options); - } + public DJsonContext(SpiEbeanServer server, JsonValueAdapter dfltValueAdapter, boolean dfltPretty) { + this.server = server; + //this.dfltValueAdapter = dfltValueAdapter; + this.dfltPretty = dfltPretty; + } -// private T toBean(Class cls, ReadJsonSource src, JsonReadOptions options){ -// -// BeanDescriptor d = getDecriptor(cls); -// ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options); -// return d.jsonReadBean(ctx, null); -// } + public boolean isSupportedType(Type genericType) { + return server.isSupportedType(genericType); + } - private T toBean(Class cls, JsonParser parser, JsonReadOptions options) { - + private JsonParser createReader(Reader jsonReader) { + return Json.createParser(jsonReader); + } + + public T toBean(Class cls, String json) { + return toBean(cls, new StringReader(json), null); + } + + public T toBean(Class cls, Reader jsonReader) { + return toBean(cls, createReader(jsonReader), null); + } + + public T toBean(Class cls, String json, JsonReadOptions options) { + return toBean(cls, new StringReader(json), options); + } + + public T toBean(Class cls, Reader jsonReader, JsonReadOptions options) { + return toBean(cls, createReader(jsonReader), options); + } + + private T toBean(Class cls, JsonParser parser, JsonReadOptions options) { + + BeanDescriptor d = getDecriptor(cls); + return d.jsonRead(parser, null); + } + + public List toList(Class cls, String json) { + return toList(cls, new StringReader(json), null); + } + + public List toList(Class cls, String json, JsonReadOptions options) { + return toList(cls, new StringReader(json), options); + } + + public List toList(Class cls, Reader jsonReader) { + return toList(cls, createReader(jsonReader), null); + } + + public List toList(Class cls, Reader jsonReader, JsonReadOptions options) { + return toList(cls, createReader(jsonReader), options); + } + + private List toList(Class cls, JsonParser src, JsonReadOptions options) { + + try { BeanDescriptor d = getDecriptor(cls); - // ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options); - return d.jsonRead(parser, null); - } - - public List toList(Class cls, String json){ - return toList(cls, new StringReader(json), null); - } - public List toList(Class cls, String json, JsonReadOptions options){ - return toList(cls, new StringReader(json), options); - } - - public List toList(Class cls, Reader jsonReader){ - return toList(cls, createReader(jsonReader), null); - } + List list = new ArrayList(); - public List toList(Class cls, Reader jsonReader, JsonReadOptions options){ - return toList(cls, createReader(jsonReader), options); - } - - private List toList(Class cls, JsonParser src, JsonReadOptions options){ + if (!src.hasNext()) { + return list; + } + Event event = src.next(); + if (event != Event.START_ARRAY) { + throw new TextException("Expecting start_array event but got [" + event + "] at [" + src.getLocation() + "]"); + } - try { - BeanDescriptor d = getDecriptor(cls); - - List list = new ArrayList(); - - //ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options); - if (!src.hasNext()) { - return list; - } - Event event = src.next(); - if (event != Event.START_ARRAY) { - throw new TextException("Expecting start_array event but got ["+event+"] at ["+src.getLocation()+"]"); - } - //ctx.readArrayBegin(); - do { - T bean = d.jsonRead(src, null); - if (bean == null){ - break; - } else { - list.add(bean); - } -// if (!ctx.readArrayNext()){ -// break; -// } - } while(true); - - return list; - - } catch (RuntimeException e){ - throw new TextException("Error parsing "+src, e); - } - } - - - public Object toObject(Type genericType, String json, JsonReadOptions options) { - - TypeInfo info = ParamTypeHelper.getTypeInfo(genericType); - Class beanType = info.getBeanType(); - if (JsonElement.class.isAssignableFrom(beanType)){ - return InternalJsonParser.parse(json); - } - - ManyType manyType = info.getManyType(); - switch (manyType) { - case NONE: - return toBean(info.getBeanType(), json, options); - - case LIST: - return toList(info.getBeanType(), json, options); - - default: - String msg = "ManyType "+manyType+" not supported yet"; - throw new TextException(msg); - } - } - - public Object toObject(Type genericType, Reader json, JsonReadOptions options) { - - TypeInfo info = ParamTypeHelper.getTypeInfo(genericType); - Class beanType = info.getBeanType(); - if (JsonElement.class.isAssignableFrom(beanType)){ - return InternalJsonParser.parse(json); - } - - ManyType manyType = info.getManyType(); - switch (manyType) { - case NONE: - return toBean(info.getBeanType(), json, options); - - case LIST: - return toList(info.getBeanType(), json, options); - - default: - String msg = "ManyType "+manyType+" not supported yet"; - throw new TextException(msg); - } - } - - - public void toJsonWriter(Object o, Writer writer) { - toJsonWriter(o, writer, dfltPretty, null, null); - } - - public void toJsonWriter(Object o, Writer writer, boolean pretty) { - toJsonWriter(o, writer, pretty, null, null); - } - - public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options){ - toJsonWriter(o, writer, pretty, null, null); - } - - public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options, String callback) { - toJsonInternal(o, new WriteJsonBufferWriter(writer), pretty, options, callback); - } - - public String toJsonString(Object o){ - return toJsonString(o, dfltPretty, null); - } - - public String toJsonString(Object o, boolean pretty){ - return toJsonString(o, pretty, null); - } - - public String toJsonString(Object o, boolean pretty, JsonWriteOptions options){ - return toJsonString(o, pretty, options, null); - } - - public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback){ - WriteJsonBufferString b = new WriteJsonBufferString(); - toJsonInternal(o, b, pretty, options, callback); - return b.getBufferOutput(); - } - - @SuppressWarnings("unchecked") - private void toJsonInternal(Object o, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){ - - if (o == null){ - buffer.append("null"); - } else if (o instanceof Number) { - buffer.append(o.toString()); - } else if (o instanceof Boolean) { - buffer.append(o.toString()); - } else if (o instanceof String) { - EscapeJson.escapeQuote(o.toString(), buffer); - } else if (o instanceof JsonElement) { - - } else if (o instanceof Map){ - toJsonFromMap((Map)o, buffer, pretty, options, requestCallback); - - } else if (o instanceof Collection){ - toJsonFromCollection((Collection)o, buffer, pretty, options, requestCallback); - + do { + T bean = d.jsonRead(src, null); + if (bean == null) { + break; } else { - BeanDescriptor d = getDecriptor(o.getClass()); - WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server); - d.jsonWrite(ctx, (EntityBean)o); - ctx.end(); + list.add(bean); } + } while (true); + + return list; + + } catch (RuntimeException e) { + throw new TextException("Error parsing " + src, e); } - + } - private void toJsonFromCollection(Collection c, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){ - - Iterator it = c.iterator(); - if (!it.hasNext()){ - buffer.append("[]"); - return; - } - - WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server); + public Object toObject(Type genericType, String json, JsonReadOptions options) { - Object o = it.next(); - BeanDescriptor d = getDecriptor(o.getClass()); - - ctx.appendArrayBegin(); - d.jsonWrite(ctx, (EntityBean)o); - while (it.hasNext()) { - ctx.appendComma(); - T t = it.next(); - d.jsonWrite(ctx, (EntityBean)t); - } - ctx.appendArrayEnd(); - ctx.end(); + TypeInfo info = ParamTypeHelper.getTypeInfo(genericType); + Class beanType = info.getBeanType(); + if (JsonElement.class.isAssignableFrom(beanType)) { + return InternalJsonParser.parse(json); } - private void toJsonFromMap(Map map, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){ - - if (map.isEmpty()){ - buffer.append("{}"); - return; - } - - WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server); + ManyType manyType = info.getManyType(); + switch (manyType) { + case NONE: + return toBean(info.getBeanType(), json, options); - Set> entrySet = map.entrySet(); - Iterator> it = entrySet.iterator(); - - Entry entry = it.next(); + case LIST: + return toList(info.getBeanType(), json, options); - ctx.appendObjectBegin(); - toJsonMapKey(buffer, false, entry.getKey()); - toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue()); - - while (it.hasNext()) { - entry = it.next(); - ctx.appendComma(); - toJsonMapKey(buffer, pretty, entry.getKey()); - toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue()); - } - ctx.appendObjectEnd(); - ctx.end(); + default: + String msg = "ManyType " + manyType + " not supported yet"; + throw new TextException(msg); + } + } + + public Object toObject(Type genericType, Reader json, JsonReadOptions options) { + + TypeInfo info = ParamTypeHelper.getTypeInfo(genericType); + Class beanType = info.getBeanType(); + if (JsonElement.class.isAssignableFrom(beanType)) { + return InternalJsonParser.parse(json); } - private void toJsonMapKey(WriteJsonBuffer buffer, boolean pretty, Object key) { - if (pretty){ - buffer.append("\n"); - } - buffer.append("\""); - buffer.append(key.toString()); - buffer.append("\":"); - } - - private void toJsonMapValue(WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback, - Object value) { - - if (value == null){ - buffer.append("null"); - } else { - toJsonInternal(value, buffer, pretty, options, requestCallback); - } + ManyType manyType = info.getManyType(); + switch (manyType) { + case NONE: + return toBean(info.getBeanType(), json, options); + + case LIST: + return toList(info.getBeanType(), json, options); + + default: + throw new TextException("ManyType " + manyType + " not supported"); } + } + + public void toJsonWriter(Object o, Writer writer) { + toJsonWriter(o, writer, dfltPretty, null, null); + } + + public void toJsonWriter(Object o, Writer writer, boolean pretty) { + toJsonWriter(o, writer, pretty, null, null); + } + + public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options) { + toJsonWriter(o, writer, pretty, null, null); + } + + public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options, String callback) { + JsonGenerator generator = Json.createGenerator(writer); + toJsonInternal(o, generator, pretty, options, callback); + generator.close(); + } + + public String toJsonString(Object o) { + return toJsonString(o, dfltPretty, null); + } + + public String toJsonString(Object o, boolean pretty) { + return toJsonString(o, pretty, null); + } + + public String toJsonString(Object o, boolean pretty, JsonWriteOptions options) { + return toJsonString(o, pretty, options, null); + } + + public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback) { + StringWriter writer = new StringWriter(500); + JsonGenerator gen = Json.createGenerator(writer); + toJsonInternal(o, gen, pretty, options, callback); + gen.close(); + return writer.toString(); + } + + @SuppressWarnings("unchecked") + private void toJsonInternal(Object o, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) { + + if (o == null) { + gen.writeNull(); + } else if (o instanceof Number) { + gen.write(((Number) o).doubleValue()); + } else if (o instanceof Boolean) { + gen.write(((Boolean) o).booleanValue()); + } else if (o instanceof String) { + gen.write((String) o); + + // } else if (o instanceof JsonElement) { + + } else if (o instanceof Map) { + toJsonFromMap((Map) o, gen, pretty, options, requestCallback); + + } else if (o instanceof Collection) { + toJsonFromCollection((Collection) o, null, gen, pretty, options, requestCallback); + + } else if (o instanceof EntityBean) { + BeanDescriptor d = getDecriptor(o.getClass()); + WriteJson writeJson = createWriteJson(gen, options); + d.jsonWrite(writeJson, (EntityBean)o, null); + } + } + + private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) { + PathProperties pathProps = (options == null) ? null : options.getPathProperties(); + return new WriteJson(server, gen, pathProps); + } + + private void toJsonFromCollection(Collection c, String key, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) { + + if (key == null) { + gen.writeStartArray(); + } else { + gen.writeStartArray(key); + } + + WriteJson writeJson = createWriteJson(gen, options); + + Iterator it = c.iterator(); + while (it.hasNext()) { + T t = it.next(); + BeanDescriptor d = getDecriptor(t.getClass()); + //writeJson.setBean(); + d.jsonWrite(writeJson, (EntityBean)t, null); + } + gen.writeEnd(); + } + + private void toJsonFromMap(Map map, JsonGenerator gen, boolean pretty, JsonWriteOptions options, String requestCallback) { + + Set> entrySet = map.entrySet(); + Iterator> it = entrySet.iterator(); + + WriteJson writeJson = createWriteJson(gen, options); + gen.writeStartObject(); - private BeanDescriptor getDecriptor(Class cls) { - BeanDescriptor d = server.getBeanDescriptor(cls); - if (d == null){ - String msg = "No BeanDescriptor found for "+cls; - throw new RuntimeException(msg); + while (it.hasNext()) { + Entry entry = it.next(); + String key = entry.getKey().toString(); + Object value = entry.getValue(); + if (value == null) { + gen.writeNull(key); + } else { + if (value instanceof Collection) { + toJsonFromCollection((Collection) value, key, gen, pretty, options, requestCallback); + + } else if (value instanceof EntityBean) { + BeanDescriptor d = getDecriptor(value.getClass()); + d.jsonWrite(writeJson,(EntityBean) value, key); + + } else { + throw new RuntimeException("TODO process primitive"); } - return d; + } } + gen.writeEnd(); + } + + private BeanDescriptor getDecriptor(Class cls) { + BeanDescriptor d = server.getBeanDescriptor(cls); + if (d == null) { + throw new RuntimeException("No BeanDescriptor found for " + cls); + } + return d; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/text/json/PathStack.java b/src/main/java/com/avaje/ebeaninternal/server/text/json/PathStack.java index 42825abeb..b62bd1d97 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/text/json/PathStack.java +++ b/src/main/java/com/avaje/ebeaninternal/server/text/json/PathStack.java @@ -4,23 +4,23 @@ import com.avaje.ebeaninternal.server.util.ArrayStack; public class PathStack extends ArrayStack { - public String peekFullPath(String key){ - - String prefix = peekWithNull(); - if (prefix != null){ - return prefix+"."+key; - } else { - return key; - } - } - - public void pushPathKey(String key) { + public String peekFullPath(String key) { - String prefix = peekWithNull(); - if (prefix != null){ - key = prefix+"."+key; - } - push(key); + String prefix = peekWithNull(); + if (prefix != null) { + return prefix + "." + key; + } else { + return key; } + } + + public void pushPathKey(String key) { + + String prefix = peekWithNull(); + if (prefix != null) { + key = prefix + "." + key; + } + push(key); + } } 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 new file mode 100644 index 000000000..d6c8ccf03 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJson.java @@ -0,0 +1,200 @@ +package com.avaje.ebeaninternal.server.text.json; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import javax.json.stream.JsonGenerator; + +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.text.PathProperties; +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.util.ArrayStack; + +public class WriteJson { + + private final SpiEbeanServer server; + private final JsonGenerator generator; + private final PathProperties pathProperties; + + private final PathStack pathStack = new PathStack(); + + private final ArrayStack parentBeans = new ArrayStack(); + + public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties){ + this.server = server; + this.generator = generator; + this.pathProperties = pathProperties; + } + + public JsonGenerator gen() { + return generator; + } + + public boolean isParentBean(Object bean) { + if (parentBeans.isEmpty()) { + return false; + } else { + return parentBeans.contains(bean); + } + } + + public void pushParentBeanMany(Object parentBean) { + parentBeans.push(parentBean); + } + + public void popParentBeanMany() { + parentBeans.pop(); + } + + public void beginAssocOne(String key, EntityBean bean) { + parentBeans.push(bean); + pathStack.pushPathKey(key); + } + + public void endAssocOne() { + parentBeans.pop(); + pathStack.pop(); + } + + public Set getIncludeProperties() { + + if (pathProperties == null) { + return null; + } else { + return pathProperties.get(pathStack.peekWithNull()); + } + } + + public WriteBean createWriteBean(BeanDescriptor desc, EntityBean bean) { + + if (pathProperties == null) { + return new WriteBean(desc, bean); + } + + boolean explicitAllProps = false; + Set currentIncludeProps = pathProperties.get(pathStack.peekWithNull()); + if (currentIncludeProps != null) { + explicitAllProps = currentIncludeProps.contains("*"); + if (explicitAllProps || currentIncludeProps.isEmpty()) { + currentIncludeProps = null; + } + } + return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean); + } + + public class WriteBean { + + final boolean explicitAllProps; + final Set currentIncludeProps; + final BeanDescriptor desc; + final EntityBean currentBean; + + WriteBean(BeanDescriptor desc, EntityBean currentBean){ + this(desc, false, null, currentBean); + } + + WriteBean(BeanDescriptor desc, boolean explicitAllProps, Set currentIncludeProps, EntityBean currentBean) { + super(); + this.desc = desc; + this.currentBean = currentBean; + this.explicitAllProps = explicitAllProps; + this.currentIncludeProps = currentIncludeProps; + } + + private boolean isReferenceOnly() { + return !explicitAllProps && currentIncludeProps == null && currentBean._ebean_getIntercept().isReference(); + } + + private boolean isIncludeProperty(BeanProperty prop) { + if (explicitAllProps) + return true; + if (currentIncludeProps != null) { + // explicitly controlled by pathProperties + return currentIncludeProps.contains(prop.getName()); + } else { + // include only loaded properties + return currentBean._ebean_getIntercept().isLoadedProperty(prop.getPropertyIndex()); + } + } + + public void write(WriteJson writeJson) { + //EntityBean bean = writeJson.getBean(); + 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++) { + System.out.println("bean "+ currentBean+" prop:"+props[j]); + if (isIncludeProperty(props[j])) { + props[j].jsonWrite(writeJson, currentBean); + } + } + props = desc.propertiesTransient(); + for (int j = 0; j < props.length; j++) { + if (isIncludeProperty(props[j])) { + props[j].jsonWrite(writeJson, currentBean); + } + } + } + } + } + + + public Boolean includeMany(String key) { + if (pathProperties != null) { + String fullPath = pathStack.peekFullPath(key); + return pathProperties.hasPath(fullPath); + } + return null; + } + + public void toJson(String name, Collection c) { + + beginAssocMany(name); + + Iterator it = c.iterator(); + while (it.hasNext()) { + EntityBean o = (EntityBean) it.next(); + BeanDescriptor d = getDecriptor(o.getClass()); + d.jsonWrite(this, o, null); + } + endAssocMany(); + } + + private BeanDescriptor getDecriptor(Class cls) { + BeanDescriptor d = server.getBeanDescriptor(cls); + if (d == null) { + String msg = "No BeanDescriptor found for " + cls; + throw new RuntimeException(msg); + } + return d; + } + + public void beginAssocMany(String key) { + pathStack.pushPathKey(key); + generator.writeStartArray(key); + } + + public void endAssocMany() { + pathStack.pop(); + generator.writeEnd(); + } + + public void writeStartObject(String key) { + if (key == null) { + generator.writeStartObject(); + } else { + generator.writeStartObject(key); + } + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJsonContext.java b/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJsonContext.java index 7112f8a4e..f7ae2f144 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJsonContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/text/json/WriteJsonContext.java @@ -1,376 +1,376 @@ package com.avaje.ebeaninternal.server.text.json; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.bean.EntityBeanIntercept; -import com.avaje.ebean.text.PathProperties; -import com.avaje.ebean.text.json.JsonValueAdapter; -import com.avaje.ebean.text.json.JsonWriteBeanVisitor; -import com.avaje.ebean.text.json.JsonWriteOptions; -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.type.EscapeJson; -import com.avaje.ebeaninternal.server.type.ScalarType; -import com.avaje.ebeaninternal.server.util.ArrayStack; +//import java.util.Collection; +//import java.util.Iterator; +//import java.util.Map; +//import java.util.Set; +// +//import com.avaje.ebean.bean.EntityBean; +//import com.avaje.ebean.bean.EntityBeanIntercept; +//import com.avaje.ebean.text.PathProperties; +//import com.avaje.ebean.text.json.JsonValueAdapter; +//import com.avaje.ebean.text.json.JsonWriteBeanVisitor; +//import com.avaje.ebean.text.json.JsonWriteOptions; +//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.type.EscapeJson; +//import com.avaje.ebeaninternal.server.type.ScalarType; +//import com.avaje.ebeaninternal.server.util.ArrayStack; -public class WriteJsonContext implements JsonWriter { +public class WriteJsonContext {//implements JsonWriter { - private final SpiEbeanServer server; - - private final WriteJsonBuffer buffer; - - private final boolean pretty; - - private final JsonValueAdapter valueAdapter; - - private final ArrayStack parentBeans = new ArrayStack(); - - private final PathProperties pathProperties; - - private final Map> visitorMap; - - private final String callback; - - private final PathStack pathStack; - - private WriteBeanState beanState; - - private int depthOffset; - - boolean assocOne; - - public WriteJsonContext(WriteJsonBuffer buffer, boolean pretty, JsonValueAdapter dfltValueAdapter, - JsonWriteOptions options, String requestCallback, SpiEbeanServer server){ - - this.server = server; - this.buffer = buffer; - this.pretty = pretty; - this.pathStack = new PathStack(); - this.callback = getCallback(requestCallback, options); - if (options == null){ - this.valueAdapter = dfltValueAdapter; - this.visitorMap = null; - this.pathProperties = null; - - } else { - this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter()); - this.visitorMap = emptyToNull(options.getVisitorMap()); - this.pathProperties = emptyToNull(options.getPathProperties()); - } - - if (callback != null){ - buffer.append(requestCallback).append("("); - } - } - - public void toJson(String name, Collection c) { - - beginAssocMany(name); - - Iterator it = c.iterator(); - if (!it.hasNext()){ - endAssocMany(); - return; - } - - EntityBean o = (EntityBean)it.next(); - BeanDescriptor d = getDecriptor(o.getClass()); - - d.jsonWrite(this, o); - while (it.hasNext()) { - appendComma(); - EntityBean t = (EntityBean)it.next(); - d.jsonWrite(this, t); - } - endAssocMany(); - } - - private BeanDescriptor getDecriptor(Class cls) { - BeanDescriptor d = server.getBeanDescriptor(cls); - if (d == null){ - String msg = "No BeanDescriptor found for "+cls; - throw new RuntimeException(msg); - } - return d; - } - - public void appendRawValue(String key, String rawJsonValue) { - appendKeyWithComma(key, true); - buffer.append(rawJsonValue); - } - - public void appendQuoteEscapeValue(String key, String valueToEscape) { - appendKeyWithComma(key, true); - EscapeJson.escapeQuote(valueToEscape, buffer); - } - - public void end() { - if (callback != null){ - buffer.append(")"); - } - } - - private Map emptyToNull(Map m){ - if ( m == null || m.isEmpty()) { - return null; - } else { - return m; - } - } - - private PathProperties emptyToNull(PathProperties m){ - if ( m == null || m.isEmpty()) { - return null; - } else { - return m; - } - } - - private String getCallback(String requestCallback, JsonWriteOptions options) { - if (requestCallback != null){ - return requestCallback; - } - if (options != null){ - return options.getCallback(); - } - return null; - } - - private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) { - return valueAdapter == null ? dfltValueAdapter : valueAdapter; - } - - /** - * Return the set of properties to write to JSON. If null is returned then - * the default will output the properties loaded for this bean. - */ - public Set getIncludeProperties() { - if (pathProperties != null){ - String path = pathStack.peekWithNull(); - return pathProperties.get(path); - } - return null; - } - - public JsonWriteBeanVisitor getBeanVisitor() { - if (visitorMap != null){ - String path = pathStack.peekWithNull(); - return visitorMap.get(path); - } - return null; - } - - public String getJson() { - return buffer.toString(); - } - - private void appendIndent(){ - - buffer.append("\n"); - int depth = depthOffset + parentBeans.size(); - for (int i = 0; i < depth; i++) { - buffer.append(" "); - } - } - - public void appendObjectBegin(){ - if (pretty && !assocOne){ - appendIndent(); - } - buffer.append("{"); - } - public void appendObjectEnd(){ - buffer.append("}"); - } - - public void appendArrayBegin(){ - if (pretty){ - appendIndent(); - } - buffer.append("["); - depthOffset++; - } - - public void appendArrayEnd(){ - depthOffset--; - if (pretty){ - appendIndent(); - } - buffer.append("]"); - } - - public void appendComma(){ - buffer.append(","); - } - - public void addDepthOffset(int offset){ - depthOffset += offset; - } - - public void beginAssocOneIsNull(String key) { - depthOffset++; - internalAppendKeyBegin(key); - appendNull(); - depthOffset--; - } - - public void beginAssocOne(String key) { - pathStack.pushPathKey(key); - - internalAppendKeyBegin(key); - assocOne = true; - } - - public void endAssocOne() { - - pathStack.pop(); - assocOne = false; - } - - public Boolean includeMany(String key) { - if (pathProperties != null){ - String fullPath = pathStack.peekFullPath(key); - return pathProperties.hasPath(fullPath); - } - return null; - } - - public void beginAssocMany(String key) { - - pathStack.pushPathKey(key); - - depthOffset--; - internalAppendKeyBegin(key); - depthOffset++; - buffer.append("["); - } - - public void endAssocMany(){ - - pathStack.pop(); - - if (pretty){ - depthOffset--; - appendIndent(); - depthOffset++; - } - buffer.append("]"); - } - - private void internalAppendKeyBegin(String key) { - if (!beanState.isFirstKey()){ - buffer.append(","); - } - if (pretty){ - appendIndent(); - } - appendKeyWithComma(key, false); - } - - public void appendNameValue(String key, ScalarType scalarType, T value) { - appendKeyWithComma(key, true); - scalarType.jsonWrite(buffer, value, getValueAdapter()); - } - - public void appendDiscriminator(String key, String discValue) { - appendKeyWithComma(key, true); - buffer.append("\""); - buffer.append(discValue); - buffer.append("\""); - } - - private void appendKeyWithComma(String key, boolean withComma) { - if (withComma){ - if (!beanState.isFirstKey()){ - buffer.append(","); - } - } - buffer.append("\""); - if(key == null) { - buffer.append("null"); - } else { - buffer.append(key); - } - buffer.append("\":"); - } - - public void appendNull(String key) { - appendKeyWithComma(key, true); - buffer.append("null"); - } - - public void appendNull() { - buffer.append("null"); - } - - public JsonValueAdapter getValueAdapter() { - return valueAdapter; - } - - public String toString() { - return buffer.toString(); - } - - public void popParentBean(){ - parentBeans.pop(); - } - - public void pushParentBean(Object parentBean){ - parentBeans.push(parentBean); - } - - public void popParentBeanMany(){ - parentBeans.pop(); - depthOffset--; - } - - public void pushParentBeanMany(Object parentBean){ - parentBeans.push(parentBean); - depthOffset++; - } - - public boolean isParentBean(Object bean){ - if (parentBeans.isEmpty()){ - return false; - } else { - return parentBeans.contains(bean); - } - } - - public WriteBeanState pushBeanState(Object bean) { - WriteBeanState newState = new WriteBeanState();//bean); - WriteBeanState prevState = beanState; - beanState = newState; - return prevState; - } - - public void pushPreviousState(WriteBeanState previousState) { - this.beanState = previousState; - } - - - public static class WriteBeanState { - - private boolean firstKeyOut; - - public WriteBeanState() { - - } - - public boolean isFirstKey() { - if (!firstKeyOut){ - firstKeyOut = true; - return true; - } else { - return false; - } - } - - } +// private final SpiEbeanServer server; +// +// private final WriteJsonBuffer buffer; +// +// private final boolean pretty; +// +// private final JsonValueAdapter valueAdapter; +// +// private final ArrayStack parentBeans = new ArrayStack(); +// +// private final PathProperties pathProperties; +// +// private final Map> visitorMap; +// +// private final String callback; +// +// private final PathStack pathStack; +// +// private WriteBeanState beanState; +// +// private int depthOffset; +// +// boolean assocOne; +// +// public WriteJsonContext(WriteJsonBuffer buffer, boolean pretty, JsonValueAdapter dfltValueAdapter, +// JsonWriteOptions options, String requestCallback, SpiEbeanServer server){ +// +// this.server = server; +// this.buffer = buffer; +// this.pretty = pretty; +// this.pathStack = new PathStack(); +// this.callback = getCallback(requestCallback, options); +// if (options == null){ +// this.valueAdapter = dfltValueAdapter; +// this.visitorMap = null; +// this.pathProperties = null; +// +// } else { +// this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter()); +// this.visitorMap = emptyToNull(options.getVisitorMap()); +// this.pathProperties = emptyToNull(options.getPathProperties()); +// } +// +// if (callback != null){ +// buffer.append(requestCallback).append("("); +// } +// } +// +// public void toJson(String name, Collection c) { +// +// beginAssocMany(name); +// +// Iterator it = c.iterator(); +// if (!it.hasNext()){ +// endAssocMany(); +// return; +// } +// +// EntityBean o = (EntityBean)it.next(); +// BeanDescriptor d = getDecriptor(o.getClass()); +// +// d.jsonWrite(this, o); +// while (it.hasNext()) { +// appendComma(); +// EntityBean t = (EntityBean)it.next(); +// d.jsonWrite(this, t); +// } +// endAssocMany(); +// } +// +// private BeanDescriptor getDecriptor(Class cls) { +// BeanDescriptor d = server.getBeanDescriptor(cls); +// if (d == null){ +// String msg = "No BeanDescriptor found for "+cls; +// throw new RuntimeException(msg); +// } +// return d; +// } +// +// public void appendRawValue(String key, String rawJsonValue) { +// appendKeyWithComma(key, true); +// buffer.append(rawJsonValue); +// } +// +// public void appendQuoteEscapeValue(String key, String valueToEscape) { +// appendKeyWithComma(key, true); +// EscapeJson.escapeQuote(valueToEscape, buffer); +// } +// +// public void end() { +// if (callback != null){ +// buffer.append(")"); +// } +// } +// +// private Map emptyToNull(Map m){ +// if ( m == null || m.isEmpty()) { +// return null; +// } else { +// return m; +// } +// } +// +// private PathProperties emptyToNull(PathProperties m){ +// if ( m == null || m.isEmpty()) { +// return null; +// } else { +// return m; +// } +// } +// +// private String getCallback(String requestCallback, JsonWriteOptions options) { +// if (requestCallback != null){ +// return requestCallback; +// } +// if (options != null){ +// return options.getCallback(); +// } +// return null; +// } +// +// private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) { +// return valueAdapter == null ? dfltValueAdapter : valueAdapter; +// } +// +// /** +// * Return the set of properties to write to JSON. If null is returned then +// * the default will output the properties loaded for this bean. +// */ +// public Set getIncludeProperties() { +// if (pathProperties != null){ +// String path = pathStack.peekWithNull(); +// return pathProperties.get(path); +// } +// return null; +// } +// +// public JsonWriteBeanVisitor getBeanVisitor() { +// if (visitorMap != null){ +// String path = pathStack.peekWithNull(); +// return visitorMap.get(path); +// } +// return null; +// } +// +// public String getJson() { +// return buffer.toString(); +// } +// +// private void appendIndent(){ +// +// buffer.append("\n"); +// int depth = depthOffset + parentBeans.size(); +// for (int i = 0; i < depth; i++) { +// buffer.append(" "); +// } +// } +// +// public void appendObjectBegin(){ +// if (pretty && !assocOne){ +// appendIndent(); +// } +// buffer.append("{"); +// } +// public void appendObjectEnd(){ +// buffer.append("}"); +// } +// +// public void appendArrayBegin(){ +// if (pretty){ +// appendIndent(); +// } +// buffer.append("["); +// depthOffset++; +// } +// +// public void appendArrayEnd(){ +// depthOffset--; +// if (pretty){ +// appendIndent(); +// } +// buffer.append("]"); +// } +// +// public void appendComma(){ +// buffer.append(","); +// } +// +// public void addDepthOffset(int offset){ +// depthOffset += offset; +// } +// +// public void beginAssocOneIsNull(String key) { +// depthOffset++; +// internalAppendKeyBegin(key); +// appendNull(); +// depthOffset--; +// } +// +// public void beginAssocOne(String key) { +// pathStack.pushPathKey(key); +// +// internalAppendKeyBegin(key); +// assocOne = true; +// } +// +// public void endAssocOne() { +// +// pathStack.pop(); +// assocOne = false; +// } +// +// public Boolean includeMany(String key) { +// if (pathProperties != null){ +// String fullPath = pathStack.peekFullPath(key); +// return pathProperties.hasPath(fullPath); +// } +// return null; +// } +// +// public void beginAssocMany(String key) { +// +// pathStack.pushPathKey(key); +// +// depthOffset--; +// internalAppendKeyBegin(key); +// depthOffset++; +// buffer.append("["); +// } +// +// public void endAssocMany(){ +// +// pathStack.pop(); +// +// if (pretty){ +// depthOffset--; +// appendIndent(); +// depthOffset++; +// } +// buffer.append("]"); +// } +// +// private void internalAppendKeyBegin(String key) { +// if (!beanState.isFirstKey()){ +// buffer.append(","); +// } +// if (pretty){ +// appendIndent(); +// } +// appendKeyWithComma(key, false); +// } +// +// public void appendNameValue(String key, ScalarType scalarType, T value) { +// appendKeyWithComma(key, true); +// scalarType.jsonWrite(buffer, value, getValueAdapter()); +// } +// +// public void appendDiscriminator(String key, String discValue) { +// appendKeyWithComma(key, true); +// buffer.append("\""); +// buffer.append(discValue); +// buffer.append("\""); +// } +// +// private void appendKeyWithComma(String key, boolean withComma) { +// if (withComma){ +// if (!beanState.isFirstKey()){ +// buffer.append(","); +// } +// } +// buffer.append("\""); +// if(key == null) { +// buffer.append("null"); +// } else { +// buffer.append(key); +// } +// buffer.append("\":"); +// } +// +// public void appendNull(String key) { +// appendKeyWithComma(key, true); +// buffer.append("null"); +// } +// +// public void appendNull() { +// buffer.append("null"); +// } +// +// public JsonValueAdapter getValueAdapter() { +// return valueAdapter; +// } +// +// public String toString() { +// return buffer.toString(); +// } +// +// public void popParentBean(){ +// parentBeans.pop(); +// } +// +// public void pushParentBean(Object parentBean){ +// parentBeans.push(parentBean); +// } +// +// public void popParentBeanMany(){ +// parentBeans.pop(); +// depthOffset--; +// } +// +// public void pushParentBeanMany(Object parentBean){ +// parentBeans.push(parentBean); +// depthOffset++; +// } +// +// public boolean isParentBean(Object bean){ +// if (parentBeans.isEmpty()){ +// return false; +// } else { +// return parentBeans.contains(bean); +// } +// } +// +// public WriteBeanState pushBeanState(Object bean) { +// WriteBeanState newState = new WriteBeanState();//bean); +// WriteBeanState prevState = beanState; +// beanState = newState; +// return prevState; +// } +// +// public void pushPreviousState(WriteBeanState previousState) { +// this.beanState = previousState; +// } +// +// +// public static class WriteBeanState { +// +// private boolean firstKeyOut; +// +// public WriteBeanState() { +// +// } +// +// public boolean isFirstKey() { +// if (!firstKeyOut){ +// firstKeyOut = true; +// return true; +// } else { +// return false; +// } +// } +// +// } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundType.java b/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundType.java index a929f2e35..633044edd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundType.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundType.java @@ -9,8 +9,8 @@ import com.avaje.ebean.config.CompoundTypeProperty; import com.avaje.ebean.text.json.JsonElement; import com.avaje.ebean.text.json.JsonElementObject; import com.avaje.ebeaninternal.server.text.json.ReadJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; -import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState; +//import com.avaje.ebeaninternal.server.text.json.WriteJsonContext; +//import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState; /** * The internal representation of a Compound Type (Immutable Compound Value @@ -223,40 +223,40 @@ public final class CtCompoundType implements ScalarDataReader { } - public void jsonWrite(WriteJsonContext ctx, Object valueObject, String propertyName) { - - if (valueObject == null){ - ctx.beginAssocOneIsNull(propertyName); - - } else { - ctx.pushParentBean(valueObject); - ctx.beginAssocOne(propertyName); - jsonWriteProps(ctx, valueObject, propertyName); - ctx.endAssocOne(); - ctx.popParentBean(); - } - } - - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void jsonWriteProps(WriteJsonContext ctx, Object valueObject, String propertyName) { - - ctx.appendObjectBegin(); - WriteBeanState prevState = ctx.pushBeanState(valueObject); - - for (int i = 0; i < properties.length; i++) { - String propName = properties[i].getName(); - Object value = properties[i].getValue((V)valueObject); - if (propReaders[i] instanceof CtCompoundType) { - ((CtCompoundType)propReaders[i]).jsonWrite(ctx, value, propName); - - } else { - ctx.appendNameValue(propName, (ScalarType)propReaders[i], value); - } - } - - ctx.pushPreviousState(prevState); - ctx.appendObjectEnd(); - } +// public void jsonWrite(WriteJsonContext ctx, Object valueObject, String propertyName) { +// +// if (valueObject == null){ +// ctx.beginAssocOneIsNull(propertyName); +// +// } else { +// ctx.pushParentBean(valueObject); +// ctx.beginAssocOne(propertyName); +// jsonWriteProps(ctx, valueObject, propertyName); +// ctx.endAssocOne(); +// ctx.popParentBean(); +// } +// } +// +// +// @SuppressWarnings({ "unchecked", "rawtypes" }) +// private void jsonWriteProps(WriteJsonContext ctx, Object valueObject, String propertyName) { +// +// ctx.appendObjectBegin(); +// WriteBeanState prevState = ctx.pushBeanState(valueObject); +// +// for (int i = 0; i < properties.length; i++) { +// String propName = properties[i].getName(); +// Object value = properties[i].getValue((V)valueObject); +// if (propReaders[i] instanceof CtCompoundType) { +// ((CtCompoundType)propReaders[i]).jsonWrite(ctx, value, propName); +// +// } else { +// ctx.appendNameValue(propName, (ScalarType)propReaders[i], value); +// } +// } +// +// ctx.pushPreviousState(prevState); +// ctx.appendObjectEnd(); +// } } 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 1cc744142..003b78e2a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.sql.SQLException; import java.sql.Types; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; @@ -40,9 +41,12 @@ public class ScalarTypeByte extends ScalarTypeBase { public Byte toBeanType(Object value) { return BasicTypeConverter.toByte(value); } - - + @Override + public void jsonWrite(JsonGenerator ctx, String name, Object value) { + throw new TextException("Not supported"); + } + @Override public Object jsonRead(JsonParser ctx, Event event) { throw new TextException("Not supported"); 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 479b69132..a2c11e603 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java @@ -5,6 +5,7 @@ import java.io.DataOutput; import java.io.IOException; import java.sql.SQLException; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; @@ -45,6 +46,11 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { @Override + public void jsonWrite(JsonGenerator ctx, String name, Object value) { + throw new TextException("Not supported"); + } + + @Override public Object jsonRead(JsonParser ctx, Event event) { throw new TextException("Not supported"); } 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 abad19df5..85795a5f0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java @@ -5,6 +5,7 @@ import java.io.DataOutput; import java.io.IOException; import java.sql.SQLException; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; @@ -69,6 +70,11 @@ public class ScalarTypeBytesEncrypted implements ScalarType { baseType.loadIgnore(dataReader); } + @Override + public void jsonWrite(JsonGenerator ctx, String name, Object value) { + throw new TextException("Not supported"); + } + @Override public Object jsonRead(JsonParser ctx, Event event) { throw new TextException("Not supported"); 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 ef6b8427e..f0da2c0f7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTime.java @@ -7,10 +7,10 @@ import java.sql.SQLException; import java.sql.Time; import java.sql.Types; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; -import org.joda.time.DateMidnight; import org.joda.time.DateTimeZone; import org.joda.time.LocalTime; @@ -66,7 +66,10 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { return new LocalTime(value); } - + @Override + public void jsonWrite(JsonGenerator ctx, String name, Object value) { + ctx.write(value.toString()); + } @Override public Object jsonRead(JsonParser ctx, Event event) { 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 bb0f5fb1d..02a89f051 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.Map; +import javax.json.stream.JsonGenerator; import javax.json.stream.JsonParser; import javax.json.stream.JsonParser.Event; @@ -67,6 +68,11 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { return (Map)value; } + @Override + public void jsonWrite(JsonGenerator ctx, String name, Object value) { + // TODO Auto-generated method stub + } + @Override public Object jsonRead(JsonParser ctx, Event event) { // TODO Auto-generated method stub diff --git a/src/test/java/com/avaje/ebean/json/EJsonTests.java b/src/test/java/com/avaje/ebean/json/EJsonTests.java new file mode 100644 index 000000000..cd455a375 --- /dev/null +++ b/src/test/java/com/avaje/ebean/json/EJsonTests.java @@ -0,0 +1,104 @@ +package com.avaje.ebean.json; + +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +public class EJsonTests { + + @Test + public void test_map_simple() { + + String jsonInput = "{\"name\":\"rob\",\"age\":12}"; + Object result = EJson.parse(jsonInput); + + 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() { + + 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); + } +} diff --git a/src/test/java/com/avaje/ebean/text/PathPropertiesTests.java b/src/test/java/com/avaje/ebean/text/PathPropertiesTests.java new file mode 100644 index 000000000..3e48bf2a6 --- /dev/null +++ b/src/test/java/com/avaje/ebean/text/PathPropertiesTests.java @@ -0,0 +1,81 @@ +package com.avaje.ebean.text; + +import org.junit.Assert; +import org.junit.Test; + +public class PathPropertiesTests { + + + + @Test + public void test_noParentheses() { + + PathProperties s0 = PathProperties.parse("id,name"); + + Assert.assertEquals(1, s0.getPaths().size()); + Assert.assertTrue(s0.get(null).contains("id")); + Assert.assertTrue(s0.get(null).contains("name")); + Assert.assertFalse(s0.get(null).contains("status")); + } + + @Test + public void test_noParentheses_needTrim() { + + PathProperties s0 = PathProperties.parse(" id, name "); + + Assert.assertEquals(1, s0.getPaths().size()); + Assert.assertTrue(s0.get(null).contains("id")); + Assert.assertTrue(s0.get(null).contains("name")); + Assert.assertFalse(s0.get(null).contains("status")); + } + + @Test + public void test_withParentheses() { + + PathProperties s0 = PathProperties.parse("(id,name)"); + + Assert.assertEquals(1, s0.getPaths().size()); + Assert.assertTrue(s0.get(null).contains("id")); + Assert.assertTrue(s0.get(null).contains("name")); + Assert.assertFalse(s0.get(null).contains("status")); + } + + + @Test + public void test_withColon() { + + PathProperties s0 = PathProperties.parse(":(id,name)"); + + Assert.assertEquals(1, s0.getPaths().size()); + Assert.assertTrue(s0.get(null).contains("id")); + Assert.assertTrue(s0.get(null).contains("name")); + Assert.assertFalse(s0.get(null).contains("status")); + } + + @Test + public void test_nested() { + + PathProperties s1 = PathProperties.parse("id,name,shipAddr(*)"); + Assert.assertEquals(2, s1.getPaths().size()); + Assert.assertEquals(3, s1.get(null).size()); + Assert.assertTrue(s1.get(null).contains("id")); + Assert.assertTrue(s1.get(null).contains("name")); + Assert.assertTrue(s1.get(null).contains("shipAddr")); + Assert.assertTrue(s1.get("shipAddr").contains("*")); + Assert.assertEquals(1, s1.get("shipAddr").size()); + } + + @Test + public void test_withParenthesesColonNested() { + + PathProperties s1 = PathProperties.parse(":(id,name,shipAddr(*))"); + Assert.assertEquals(2, s1.getPaths().size()); + Assert.assertEquals(3, s1.get(null).size()); + Assert.assertTrue(s1.get(null).contains("id")); + Assert.assertTrue(s1.get(null).contains("name")); + Assert.assertTrue(s1.get(null).contains("shipAddr")); + Assert.assertTrue(s1.get("shipAddr").contains("*")); + Assert.assertEquals(1, s1.get("shipAddr").size()); + + } +} diff --git a/src/test/java/com/avaje/ebean/text/TestPathPropertiesParse.java b/src/test/java/com/avaje/ebean/text/TestPathPropertiesParse.java deleted file mode 100644 index c4342c74c..000000000 --- a/src/test/java/com/avaje/ebean/text/TestPathPropertiesParse.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.avaje.ebean.text; - -import org.junit.Assert; -import org.junit.Test; - -import com.avaje.ebean.BaseTestCase; - -public class TestPathPropertiesParse extends BaseTestCase { - - @Test - public void test() { - - PathProperties s0 = PathProperties.parse("(id,name)"); - - Assert.assertEquals(1, s0.getPaths().size()); - Assert.assertTrue(s0.get(null).contains("id")); - Assert.assertTrue(s0.get(null).contains("name")); - Assert.assertFalse(s0.get(null).contains("status")); - - PathProperties s1 = PathProperties.parse(":(id,name,shipAddr(*))"); - Assert.assertEquals(2, s1.getPaths().size()); - Assert.assertEquals(3, s1.get(null).size()); - Assert.assertTrue(s1.get(null).contains("id")); - Assert.assertTrue(s1.get(null).contains("name")); - Assert.assertTrue(s1.get(null).contains("shipAddr")); - Assert.assertTrue(s1.get("shipAddr").contains("*")); - Assert.assertEquals(1, s1.get("shipAddr").size()); - - } - -} diff --git a/src/test/java/com/avaje/ebean/text/json/JsonWriteOptionsTests.java b/src/test/java/com/avaje/ebean/text/json/JsonWriteOptionsTests.java new file mode 100644 index 000000000..82a570443 --- /dev/null +++ b/src/test/java/com/avaje/ebean/text/json/JsonWriteOptionsTests.java @@ -0,0 +1,24 @@ +package com.avaje.ebean.text.json; + +import org.junit.Assert; +import org.junit.Test; + +import com.avaje.ebean.text.PathProperties; +import com.avaje.ebean.text.json.JsonWriteOptions; + +public class JsonWriteOptionsTests { + + @Test + public void test_parse() { + + JsonWriteOptions options = JsonWriteOptions.parsePath("id,status,name"); + PathProperties pathProps = options.getPathProperties(); + + Assert.assertEquals(1, pathProps.getPaths().size()); + Assert.assertTrue(pathProps.get(null).contains("id")); + Assert.assertTrue(pathProps.get(null).contains("name")); + Assert.assertTrue(pathProps.get(null).contains("status")); + Assert.assertFalse(pathProps.get(null).contains("foo")); + + } +} diff --git a/src/test/java/com/avaje/tests/text/json/TestTextJsonBeanReadVisitor.java b/src/test/java/com/avaje/tests/text/json/TestTextJsonBeanReadVisitor.java index 2bddf7dd2..8f5e4f5d4 100644 --- a/src/test/java/com/avaje/tests/text/json/TestTextJsonBeanReadVisitor.java +++ b/src/test/java/com/avaje/tests/text/json/TestTextJsonBeanReadVisitor.java @@ -4,8 +4,7 @@ import java.io.StringReader; import java.util.List; import java.util.Map; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Test; import com.avaje.ebean.BaseTestCase; @@ -26,9 +25,12 @@ public class TestTextJsonBeanReadVisitor extends BaseTestCase { 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(); + 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.createJsonContext();