Merge from JSON refactoring branch

This commit is contained in:
Rob Bygrave
2014-11-06 23:32:27 +13:00
115 changed files with 4180 additions and 3334 deletions
@@ -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<T> {
/**
* 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);
}
@@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.json.stream.JsonParser;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
@@ -34,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;
@@ -62,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;
@@ -195,12 +191,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
/**
* Inheritance information. Server side only.
*/
private final InheritInfo inheritInfo;
protected final InheritInfo inheritInfo;
/**
* Derived list of properties that make up the unique id.
*/
private final BeanProperty idProperty;
protected final BeanProperty idProperty;
private final int idPropertyIndex;
/**
@@ -327,7 +323,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
private final boolean cacheSharableBeans;
private final BeanDescriptorCacheHelp<T> cacheHelp;
private final BeanDescriptorJsonHelp<T> jsonHelp;
private final String defaultSelectClause;
private final Set<String> defaultSelectClauseSet;
@@ -422,7 +419,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<T>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = new BeanDescriptorJsonHelp<T>(this);
// Check if there are no cascade save associated beans ( subject to change
// in initialiseOther()). Note that if we are in an inheritance hierarchy
@@ -2115,167 +2112,23 @@ public class BeanDescriptor<T> 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();
}
}
@SuppressWarnings("unchecked")
private void jsonWriteProperties(WriteJsonContext ctx, EntityBean bean) {
JsonWriteBeanVisitor<T> beanVisitor = (JsonWriteBeanVisitor<T>) ctx.getBeanVisitor();
Set<String> 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);
}
}
@SuppressWarnings("unchecked")
public T jsonReadBean(ReadJsonContext ctx, String path) {
ReadBeanState beanState = jsonRead(ctx, path);
if (beanState == null) {
return null;
} else {
return (T) beanState.getBean();
}
}
public ReadBeanState jsonRead(ReadJsonContext ctx, String path) {
if (!ctx.readObjectBegin()) {
// the object is null
return null;
}
if (inheritInfo == null) {
return jsonReadObject(ctx, path);
} else {
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
if (!ctx.readKeyNext()) {
String msg = "Error reading inheritance discriminator - expected [" + discColumn + "] but no json key?";
throw new TextException(msg);
}
String propName = ctx.getTokenKey();
String discValue;
if (propName.equalsIgnoreCase(discColumn)) {
discValue = ctx.readScalarValue();
if (!ctx.readValueNext()) {
// Expected to read a comma to setup for reading the real properties of the bean
String msg = "Error reading inheritance discriminator [" + discColumn + "]. Expected more json name values?";
throw new TextException(msg);
}
} else {
// Assume that the we are just reading using this bean type
// Push the token key back so that it is re-read as it is one
// of the real properties of the bean itself
ctx.pushTokenKey();
discValue = inheritInfo.getDiscriminatorStringValue();
}
// determine the sub type for this particular json object
InheritInfo localInheritInfo = inheritInfo.readType(discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
return localDescriptor.jsonReadObject(ctx, path);
}
}
public void jsonWrite(WriteJson writeJson, EntityBean bean) {
jsonHelp.jsonWrite(writeJson, bean, null);
}
private ReadBeanState jsonReadObject(ReadJsonContext ctx, String path) {
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) {
jsonHelp.jsonWrite(writeJson, bean, key);
}
EntityBean bean = createEntityBean();
ctx.pushBean(bean, path, this);
do {
if (!ctx.readKeyNext()) {
break;
} else {
// we read a property key ...
String propName = ctx.getTokenKey();
BeanProperty p = getBeanProperty(propName);
if (p != null) {
p.jsonRead(ctx, bean);
ctx.setProperty(propName);
} else {
// unknown property key ...
ctx.readUnmappedJson(propName);
}
if (!ctx.readValueNext()) {
break;
}
}
} while (true);
return ctx.popBeanState();
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) {
jsonHelp.jsonWriteProperties(writeJson, bean);
}
public T jsonRead(JsonParser parser, String path) {
return jsonHelp.jsonRead(parser, path);
}
protected T jsonReadObject(JsonParser parser, String path) {
return jsonHelp.jsonReadObject(parser, path);
}
}
@@ -0,0 +1,145 @@
package com.avaje.ebeaninternal.server.deploy;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson.WriteBean;
public class BeanDescriptorJsonHelp<T> {
private final BeanDescriptor<T> desc;
private final InheritInfo inheritInfo;
public BeanDescriptorJsonHelp(BeanDescriptor<T> desc) {
this.desc = desc;
this.inheritInfo = desc.inheritInfo;
}
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) {
// if (writeJson.hasBean()) {
writeJson.writeStartObject(key);
//WriteBeanState prevState = ctx.pushBeanState(bean);
if (inheritInfo == null) {
jsonWriteProperties(writeJson, bean);
} else {
InheritInfo localInheritInfo = inheritInfo.readType(bean.getClass());
String discValue = localInheritInfo.getDiscriminatorStringValue();
String discColumn = localInheritInfo.getDiscriminatorColumn();
writeJson.gen().write(discColumn, discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
localDescriptor.jsonWriteProperties(writeJson, bean);
}
//ctx.pushPreviousState(prevState);
writeJson.gen().writeEnd();
}
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) {
WriteBean writeBean = writeJson.createWriteBean(desc, bean);
writeBean.write(writeJson);
}
@SuppressWarnings("unchecked")
public T jsonRead(JsonParser parser, String path) {
if (!parser.hasNext()) {
return null;
}
Event event = parser.next();
if (Event.VALUE_NULL == event || Event.END_ARRAY == event) {
return null;
}
if (Event.START_OBJECT != event) {
throw new RuntimeException("Unexpected token "+event+" - expecting start_object at: "+parser.getLocation());
}
if (desc.inheritInfo == null) {
return jsonReadObject(parser, path);
}
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
if (!parser.hasNext() || ((event = parser.next()) != Event.KEY_NAME)) {
String msg = "Error reading inheritance discriminator - expected [" + discColumn + "] but no json key?";
throw new TextException(msg);
}
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);
}
if (!parser.hasNext() || ((event = parser.next()) != Event.VALUE_STRING)) {
String msg = "Error reading inheritance discriminator - expected value_string token but got [" + event + "] at ["+parser.getLocation()+"]?";
throw new TextException(msg);
}
String discValue = parser.getString();
// determine the sub type for this particular json object
InheritInfo localInheritInfo = inheritInfo.readType(discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
return (T) localDescriptor.jsonReadObject(parser, path);
}
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()) {
Event event = parser.next();
if (Event.KEY_NAME == event) {
String key = parser.getString();
BeanProperty p = desc.getBeanProperty(key);
if (p != null) {
p.jsonRead(parser, bean);
} else {
//Object rawValue = EJson.parse(parser);
// unknown property key ...
//ctx.readUnmappedJson(propName);
}
} else if (Event.END_OBJECT == event) {
break;
} else {
throw new RuntimeException("Unexpected token "+event+" - expecting key or end_object at: "+parser.getLocation());
}
}
} while (true);
return (T)bean;
}
}
@@ -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<T> implements BeanCollectionHelp<T> {
}
}
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<T> implements BeanCollectionHelp<T> {
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();
}
}
@@ -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<T> implements BeanCollectionHelp<T> {
}
}
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<T> implements BeanCollectionHelp<T> {
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();
}
}
@@ -10,6 +10,8 @@ import java.sql.Types;
import java.util.List;
import java.util.Map;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import javax.persistence.PersistenceException;
import com.avaje.ebean.bean.EntityBean;
@@ -18,7 +20,6 @@ import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.text.StringFormatter;
import com.avaje.ebean.text.StringParser;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
@@ -30,8 +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.ReadJsonContext;
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;
@@ -78,7 +78,7 @@ public class BeanProperty implements ElPropertyValue {
* Flag set if this maps to the inheritance discriminator column
*/
final boolean discriminator;
/**
* Flag to mark the property as embedded. This could be on
* BeanPropertyAssocOne rather than here. Put it here for checking Id type
@@ -92,7 +92,7 @@ public class BeanProperty implements ElPropertyValue {
final boolean version;
final boolean naturalKey;
/**
* Set if this property is nullable.
*/
@@ -136,7 +136,7 @@ public class BeanProperty implements ElPropertyValue {
* True if the property is a Clob, Blob LongVarchar or LongVarbinary.
*/
final boolean lob;
final boolean fetchEager;
final boolean isTransient;
@@ -147,7 +147,7 @@ public class BeanProperty implements ElPropertyValue {
final String name;
final int propertyIndex;
/**
* The reflected field.
*/
@@ -265,7 +265,6 @@ public class BeanProperty implements ElPropertyValue {
final boolean indexed;
final String indexName;
public BeanProperty(DeployBeanProperty deploy) {
this(null, null, deploy);
}
@@ -275,10 +274,8 @@ public class BeanProperty implements ElPropertyValue {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
this.indexed = deploy.isIndexed();
this.indexName = deploy.getIndexName();
this.unidirectionalShadow = deploy.isUndirectionalShadow();
this.discriminator = deploy.isDiscriminator();
this.localEncrypted = deploy.isLocalEncrypted();
@@ -333,7 +330,7 @@ public class BeanProperty implements ElPropertyValue {
this.lob = isLobType(dbType);
this.propertyType = deploy.getPropertyType();
this.field = deploy.getField();
EntityType et = descriptor == null ? null : descriptor.getEntityType();
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), false, null);
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), dbEncrypted, dbColumn);
@@ -371,7 +368,6 @@ public class BeanProperty implements ElPropertyValue {
this.indexed = source.isIndexed();
this.indexName = source.getIndexName();
this.dbColumn = InternString.intern(override.getDbColumn());
this.sqlFormulaJoin = InternString.intern(override.getSqlFormulaJoin());
this.sqlFormulaSelect = InternString.intern(override.getSqlFormulaSelect());
@@ -420,7 +416,7 @@ public class BeanProperty implements ElPropertyValue {
this.lob = isLobType(dbType);
this.propertyType = source.getPropertyType();
this.field = source.getField();
this.elPlaceHolder = override.replace(source.elPlaceHolder, source.dbColumn);
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
@@ -487,7 +483,7 @@ public class BeanProperty implements ElPropertyValue {
public boolean isDiscriminator() {
return discriminator;
}
/**
* Return true if the underlying type is mutable.
*/
@@ -675,6 +671,14 @@ public class BeanProperty implements ElPropertyValue {
public BeanProperty getBeanProperty() {
return this;
}
public boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
/**
* Return the getter method.
@@ -737,12 +741,12 @@ public class BeanProperty implements ElPropertyValue {
public Object getCacheDataValue(EntityBean bean) {
return getValue(bean);
}
}
public void setCacheDataValue(EntityBean bean, Object cacheData) {
setValue(bean, cacheData);
}
/**
* Return the value of the property method.
*/
@@ -755,12 +759,12 @@ public class BeanProperty implements ElPropertyValue {
throw new RuntimeException(msg, ex);
}
}
/**
* Explicitly use reflection to get value.
*/
public Object getValueViaReflection(Object bean) {
try {
try {
return readMethod.invoke(bean, NO_ARGS);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
@@ -815,7 +819,7 @@ public class BeanProperty implements ElPropertyValue {
* Return the position of this property in the enhanced bean.
*/
public int getPropertyIndex() {
return propertyIndex;
return propertyIndex;
}
public String getElName() {
@@ -829,7 +833,6 @@ public class BeanProperty implements ElPropertyValue {
return false;
}
@Override
public boolean containsFormulaWithJoin() {
return formula && sqlFormulaJoin != null;
@@ -895,7 +898,7 @@ public class BeanProperty implements ElPropertyValue {
public boolean isDirtyValue(Object value) {
return scalarType.isDirty(value);
}
/**
* Return the scalarType.
*/
@@ -914,7 +917,7 @@ public class BeanProperty implements ElPropertyValue {
public boolean isDateTimeCapable() {
return scalarType != null && scalarType.isDateTimeCapable();
}
public int getJdbcType() {
return scalarType == null ? 0 : scalarType.getJdbcType();
}
@@ -1020,7 +1023,7 @@ public class BeanProperty implements ElPropertyValue {
public boolean isLoadProperty() {
return !isTransient || formula;
}
/**
* Return true if this is a version column used for concurrency checking.
*/
@@ -1183,43 +1186,32 @@ public class BeanProperty implements ElPropertyValue {
return name;
}
@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);
}
public void jsonWrite(WriteJson writeJson, EntityBean bean) {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
writeJson.gen().writeNull(name);
} else {
scalarType.jsonWrite(writeJson.gen(), name, value);
}
}
public void jsonRead(JsonParser ctx, EntityBean bean) {
if (!jsonDeserialize) {
return;
}
if (!ctx.hasNext()) {
throw new RuntimeException(ctx.getLocation().toString());
}
Event event = ctx.next();
if (Event.VALUE_NULL == event) {
setValue(bean, null);
} else {
Object objValue = scalarType.jsonRead(ctx, event);
setValue(bean, objValue);
}
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 boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.json.stream.JsonParser;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
@@ -28,9 +29,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.
@@ -39,6 +38,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssocMany.class);
private final BeanPropertyAssocManyJsonHelp jsonHelp;
/**
* Join for manyToMany intersection table.
*/
@@ -90,7 +91,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
/**
* Property on the 'child' bean that links back to the 'master'.
*/
private BeanPropertyAssocOne<?> childMasterProperty;
protected BeanPropertyAssocOne<?> childMasterProperty;
private boolean embeddedExportedProperties;
@@ -115,6 +116,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
this.intersectionJoin = deploy.createIntersectionTableJoin();
this.inverseJoin = deploy.createInverseTableJoin();
this.modifyListenMode = deploy.getModifyListenMode();
this.jsonHelp = new BeanPropertyAssocManyJsonHelp(this);
}
public void initialise() {
@@ -875,7 +877,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
return null != targetDescriptor.getId(otherBean);
}
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
public void jsonWrite(WriteJson ctx, EntityBean bean) {
if(!this.jsonSerialize){
return;
}
@@ -896,37 +898,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
}
}
public void jsonRead(ReadJsonContext ctx, EntityBean bean){
if(!this.jsonDeserialize){
return;
}
if (!ctx.readArrayBegin()) {
// the array is null
return;
}
Object collection = help.createEmpty(false);
BeanCollectionAdd add = getBeanCollectionAdd(collection, null);
do {
ReadBeanState detailBeanState = targetDescriptor.jsonRead(ctx, name);
if (detailBeanState == null){
// probably empty array
break;
}
EntityBean detailBean = (EntityBean)detailBeanState.getBean();
add.addBean(detailBean);
if (bean != null && childMasterProperty != null){
// bind detail bean back to master via mappedBy property
childMasterProperty.setValue(detailBean, bean);
detailBeanState.setLoaded(childMasterProperty.getName());
}
if (!ctx.readArrayNext()){
break;
}
} while(true);
setValue(bean, collection);
public void jsonRead(JsonParser parser, EntityBean parentBean) {
jsonHelp.jsonRead(parser, parentBean);
}
}
@@ -0,0 +1,49 @@
package com.avaje.ebeaninternal.server.deploy;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.TextException;
public class BeanPropertyAssocManyJsonHelp {
private final BeanPropertyAssocMany<?> many;
public BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany<?> many) {
this.many = many;
}
public void jsonRead(JsonParser parser, EntityBean parentBean) {
if (!this.many.jsonDeserialize || !parser.hasNext()) {
return;
}
Event event = parser.next();
if (Event.VALUE_NULL == event) {
return;
}
if (Event.START_ARRAY != event) {
throw new TextException("Unexpected token "+event+" - expecting start_array at: "+parser.getLocation());
}
Object collection = many.createEmpty(false);
BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null);
do {
EntityBean detailBean = (EntityBean)many.targetDescriptor.jsonRead(parser, many.name);
if (detailBean == null) {
// read the entire array
break;
}
add.addBean(detailBean);
if (parentBean != null && many.childMasterProperty != null) {
// bind detail bean back to master via mappedBy property
many.childMasterProperty.setValue(detailBean, parentBean);
}
} while (true);
many.setValue(parentBean, collection);
}
}
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.json.stream.JsonParser;
import javax.persistence.PersistenceException;
import com.avaje.ebean.EbeanServer;
@@ -24,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.
@@ -831,36 +831,34 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
}
@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();
}
}
}
}
@Override
public void jsonRead(ReadJsonContext ctx, EntityBean bean){
if (targetDescriptor != null) {
T assocBean = targetDescriptor.jsonReadBean(ctx, name);
setValue(bean, assocBean);
}
public void jsonRead(JsonParser parser, EntityBean bean) {
if (targetDescriptor != null) {
T assocBean = targetDescriptor.jsonRead(parser, name);
setValue(bean, assocBean);
}
}
public boolean isReference(Object detailBean) {
@@ -3,15 +3,18 @@ package com.avaje.ebeaninternal.server.deploy;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.json.stream.JsonParser;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.json.EJson;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
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,15 +180,32 @@ public class BeanPropertyCompound extends BeanProperty {
return bean;
}
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
Object valueObject = getValueIntercept(bean);
compoundType.jsonWrite(ctx, valueObject, name);
public void jsonWrite(WriteJson ctx, EntityBean bean) {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.gen().writeNull(name);
} else {
compoundType.jsonWrite(ctx, value, name);
}
}
public void jsonRead(ReadJsonContext ctx, EntityBean bean){
Object objValue = compoundType.jsonRead(ctx);
public void jsonRead(JsonParser ctx, EntityBean bean) {
if (!jsonDeserialize) {
return;
}
Object value = EJson.parsePartial(ctx);
if (value == null) {
setValue(bean, null);
} else {
@SuppressWarnings("unchecked")
Map<String,Object> map = (Map<String,Object>)value;
Object objValue = compoundType.jsonConvert(map);
setValue(bean, objValue);
}
}
}
@@ -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<T> implements BeanCollectionHelp<T> {
}
}
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<T> implements BeanCollectionHelp<T> {
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();
}
}
@@ -0,0 +1,215 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
public class EJsonReader {
@SuppressWarnings("unchecked")
public static Map<String, Object> parseObject(String json) {
return (Map<String, Object>) parse(json);
}
@SuppressWarnings("unchecked")
public static List<Object> parseList(String json) {
return (List<Object>) parse(json);
}
public static Object parse(String json) {
return parse(new StringReader(json));
}
public static Object parse(Reader reader) {
return parse(Json.createParser(reader));
}
public static Object parse(JsonParser parser) {
return new EJsonReader(parser).parseJson();
}
private final JsonParser parser;
private final Stack stack = new Stack();
private Context currentContext;
EJsonReader(JsonParser parser) {
this.parser = parser;
}
private void startArray() {
stack.push(currentContext);
currentContext = new ArrayContext();
}
private void startObject() {
stack.push(currentContext);
currentContext = new ObjectContext();
}
private void endArray() {
end();
}
private void endObject() {
end();
}
private void end() {
if (!stack.isEmpty()) {
currentContext = stack.pop();
}
}
private void setValue(Object value) {
currentContext.setValue(value);
}
private void setValueNull() {
currentContext.setValueNull();
}
private Object parseJson() {
while (parser.hasNext()) {
Event event = parser.next();
switch (event) {
case START_ARRAY:
startArray();
break;
case START_OBJECT:
startObject();
break;
case KEY_NAME:
currentContext.setKey(parser.getString());
break;
case VALUE_STRING:
setValue(parser.getString());
break;
case VALUE_NUMBER:
if (parser.isIntegralNumber()) {
setValue(parser.getLong());
} else {
setValue(parser.getBigDecimal());
}
break;
case VALUE_TRUE:
setValue(Boolean.TRUE);
break;
case VALUE_FALSE:
setValue(Boolean.FALSE);
break;
case VALUE_NULL:
setValueNull();
break;
case END_OBJECT:
endObject();
break;
case END_ARRAY:
endArray();
break;
default:
break;
}
}
return currentContext.getValue();
}
private static final class Stack {
private Context head;
private void push(Context context) {
if (context != null) {
context.next = head;
head = context;
}
}
private Context pop() {
if (head == null) {
throw new NoSuchElementException();
}
Context temp = head;
head = head.next;
return temp;
}
private boolean isEmpty() {
return head == null;
}
}
private static abstract class Context {
Context next;
abstract Object getValue();
abstract void setKey(String key);
abstract void setValue(Object value);
abstract void setValueNull();
}
private static class ObjectContext extends Context {
private String key;
Map<String, Object> map = new LinkedHashMap<String,Object>();
Object getValue() {
return map;
}
public void setKey(String key) {
this.key = key;
}
void setValue(Object value) {
map.put(key, value);
}
void setValueNull() {
map.put(key, null);
}
}
private static class ArrayContext extends Context {
List<Object> values = new ArrayList<Object>();
Object getValue() {
return values;
}
void setValue(Object value) {
values.add(value);
}
void setValueNull() {
}
void setKey(String key) {
}
}
}
@@ -0,0 +1,9 @@
package com.avaje.ebeaninternal.server.deploy;
import javax.json.stream.JsonParser;
public class ReadJson {
JsonParser parser;
}