From 583fc11945c3639bc6aad343056c1a56b25bc73d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 8 Mar 2016 21:02:39 +1300 Subject: [PATCH] #593 - Refactor SPI - Move methods from ElPropertyValue to ExpressionPath --- .../java/com/avaje/ebean/plugin/BeanType.java | 34 ++++++- .../avaje/ebean/plugin/ExpressionPath.java | 39 +++++++- .../server/core/PersistRequestBean.java | 2 +- .../server/deploy/BeanDescriptor.java | 72 ++++++++++++-- .../server/deploy/BeanFkeyProperty.java | 13 ++- .../server/deploy/BeanProperty.java | 21 ++-- .../deploy/BeanPropertyCompoundScalar.java | 4 +- .../server/deploy/InheritInfo.java | 7 ++ .../server/el/ElComparatorProperty.java | 10 +- .../ebeaninternal/server/el/ElFilter.java | 6 +- .../server/el/ElMatchBuilder.java | 18 ++-- .../server/el/ElPropertyChain.java | 41 +++----- .../server/el/ElPropertyValue.java | 43 -------- .../server/query/CQueryPlanStats.java | 1 - .../server/text/csv/TCsvReader.java | 37 +++---- .../type/CtCompoundPropertyElAdapter.java | 12 +-- .../docstore/api/DocStoreBeanAdapter.java | 5 + .../api/support/DocStoreBeanBaseAdapter.java | 76 ++++++++------ .../docstore/api/support/DocStructure.java | 2 +- .../com/avaje/ebean/plugin/BeanTypeTest.java | 51 ++++++++++ .../ebean/plugin/ExpressionPathTest.java | 4 +- .../avaje/tests/ddd/iud/TestDPersonEl.java | 99 ++++++++++--------- .../avaje/tests/el/TestElGetReference.java | 41 -------- .../avaje/tests/el/TestPathExpression.java | 81 +++++++++++++++ 24 files changed, 447 insertions(+), 272 deletions(-) delete mode 100644 src/test/java/com/avaje/tests/el/TestElGetReference.java create mode 100644 src/test/java/com/avaje/tests/el/TestPathExpression.java diff --git a/src/main/java/com/avaje/ebean/plugin/BeanType.java b/src/main/java/com/avaje/ebean/plugin/BeanType.java index 79d6c784d..3e19ca804 100644 --- a/src/main/java/com/avaje/ebean/plugin/BeanType.java +++ b/src/main/java/com/avaje/ebean/plugin/BeanType.java @@ -6,6 +6,7 @@ import com.avaje.ebean.event.BeanPersistController; import com.avaje.ebean.event.BeanPersistListener; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.text.json.JsonReadOptions; +import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping; import com.fasterxml.jackson.core.JsonParser; @@ -17,6 +18,11 @@ import java.util.Collection; */ public interface BeanType { + /** + * Return the short name of the bean type. + */ + String getName(); + /** * Return the full name of the bean type. */ @@ -53,12 +59,12 @@ public interface BeanType { Property getWhenCreatedProperty(); /** - * Return the SpiProperty for a property to read values from a bean. + * Return the Property to read values from a bean. */ Property getProperty(String propertyName); /** - * Return the SpiExpressionPath for a given property path. + * Return the ExpressionPath for a given property path. *

* This can return a property or nested property path. *

@@ -154,4 +160,28 @@ public interface BeanType { */ T jsonRead(JsonParser parser, JsonReadOptions readOptions, Object objectMapper) throws IOException; + /** + * Add the discriminator value to the query if needed. + */ + void addInheritanceWhere(SpiQuery query); + + /** + * Return the root bean type for an inheritance hierarchy. + */ + BeanType root(); + + /** + * Return true if this bean type has an inheritance hierarchy. + */ + boolean hasInheritance(); + + /** + * Return the discriminator column. + */ + String getDiscColumn(); + + /** + * Create a bean given the discriminator value. + */ + T createBeanUsingDisc(Object discValue); } diff --git a/src/main/java/com/avaje/ebean/plugin/ExpressionPath.java b/src/main/java/com/avaje/ebean/plugin/ExpressionPath.java index e1ef6fbcb..8f529c64e 100644 --- a/src/main/java/com/avaje/ebean/plugin/ExpressionPath.java +++ b/src/main/java/com/avaje/ebean/plugin/ExpressionPath.java @@ -1,5 +1,7 @@ package com.avaje.ebean.plugin; +import com.avaje.ebean.text.StringParser; + /** * A dot notation expression path. */ @@ -10,11 +12,46 @@ public interface ExpressionPath { */ boolean containsMany(); + /** + * Return the value from a given entity bean. + */ + Object pathGet(Object bean); + /** * Set a value to the bean for this expression path. * * @param bean the bean to set the value on * @param value the value to set */ - void set(Object bean, Object value); + void pathSet(Object bean, Object value); + + /** + * Convert the value to the expected type. + *

+ * Typically useful for converting strings to the appropriate number type etc. + *

+ */ + Object convert(Object value); + + /** + * Return the default StringParser for the scalar property. + */ + StringParser getStringParser(); + + /** + * For DateTime capable scalar types convert the long systemTimeMillis into + * an appropriate java time (Date,Timestamp,Time,Calendar, JODA type etc). + */ + Object parseDateTime(long systemTimeMillis); + + /** + * Return true if the last type is "DateTime capable" - can support + * {@link #parseDateTime(long)}. + */ + boolean isDateTimeCapable(); + + /** + * Return the underlying JDBC type or 0 if this is not a scalar type. + */ + int getJdbcType(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java index 11a16db0b..501de1285 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java @@ -309,7 +309,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private boolean isDocStoreNotify() { // Either queue or directly update the document store - return docStoreMode != DocStoreMode.IGNORE; + return docStoreMode != DocStoreMode.IGNORE || beanDescriptor.docStoreAdapter().hasEmbeddedInvalidation(); } public boolean isNotifyPersistListener() { 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 2aa19e6fe..c949f2836 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -71,6 +71,8 @@ import com.avaje.ebeanservice.docstore.api.DocStoreBeanAdapter; import com.avaje.ebeanservice.docstore.api.DocStoreUpdateContext; import com.avaje.ebeanservice.docstore.api.DocStoreUpdates; import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder; +import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping; +import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType; import com.avaje.ebeanservice.docstore.api.mapping.DocumentMapping; import com.fasterxml.jackson.core.JsonParser; import org.slf4j.Logger; @@ -80,6 +82,7 @@ import javax.persistence.PersistenceException; import java.io.IOException; import java.lang.reflect.Modifier; import java.sql.SQLException; +import java.sql.Types; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -358,12 +361,12 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { private final String docStoreQueueId; - private DocumentMapping docMapping; - private final BeanDescriptorDraftHelp draftHelp; private final BeanDescriptorCacheHelp cacheHelp; private final BeanDescriptorJsonHelp jsonHelp; - private final DocStoreBeanAdapter docStoreAdapter; + private DocStoreBeanAdapter docStoreAdapter; + private DocumentMapping docMapping; + private final String defaultSelectClause; @@ -680,7 +683,6 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { namedUpdate.initialise(parser); } } - docStoreAdapter.registerPaths(); } /** @@ -690,7 +692,11 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { for (int i = 0; i < propertiesMany.length; i++) { propertiesMany[i].initialisePostTarget(); } + if (inheritInfo != null && !inheritInfo.isRoot()) { + docStoreAdapter = (DocStoreBeanAdapter)inheritInfo.getRoot().getBeanDescriptor().docStoreAdapter(); + } docMapping = docStoreAdapter.createDocMapping(); + docStoreAdapter.registerPaths(); } public void initInheritInfo() { @@ -932,16 +938,44 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { /** * Build the Document mapping recursively with the given prefix relative to the root of the document. */ - public void docStoreMapping(DocMappingBuilder mapping, String prefix) { + public void docStoreMapping(final DocMappingBuilder mapping, final String prefix) { if (prefix != null && idProperty != null) { // id property not included in the idProperty.docStoreMapping(mapping, prefix); } + if (inheritInfo != null) { + String discCol = inheritInfo.getDiscriminatorColumn(); + if (Types.VARCHAR == inheritInfo.getDiscriminatorType()) { + mapping.add(new DocPropertyMapping(discCol, DocPropertyType.ENUM)); + } else { + mapping.add(new DocPropertyMapping(discCol, DocPropertyType.INTEGER)); + } + } for (BeanProperty prop: propertiesNonTransient) { prop.docStoreMapping(mapping, prefix); } + if (inheritInfo != null) { + inheritInfo.visitChildren(new InheritInfoVisitor() { + @Override + public void visit(InheritInfo inheritInfo) { + for (BeanProperty localProperty : inheritInfo.localProperties()) { + localProperty.docStoreMapping(mapping, prefix); + } + } + }); + } + } + + /** + * Return the root bean type if part of inheritance hierarchy. + */ + public BeanType root() { + if (inheritInfo != null && !inheritInfo.isRoot()) { + return inheritInfo.getRoot().getBeanDescriptor(); + } + return this; } /** @@ -1539,7 +1573,7 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { } String[] splitBegin = SplitName.splitBegin(path); - BeanProperty beanProperty = propMap.get(splitBegin[0]); + BeanProperty beanProperty = findBeanProperty(splitBegin[0]); if (beanProperty instanceof BeanPropertyAssoc) { BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; return assocProp.getTargetDescriptor().getBeanDescriptor(splitBegin[1]); @@ -1709,7 +1743,7 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { @Override public Property getProperty(String propName) { - return getBeanProperty(propName); + return findBeanProperty(propName); } /** @@ -1976,6 +2010,30 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { return inheritInfo; } + @Override + public boolean hasInheritance() { + return inheritInfo != null; + } + + @Override + public String getDiscColumn() { + return inheritInfo.getDiscriminatorColumn(); + } + + @Override + @SuppressWarnings("unchecked") + public T createBeanUsingDisc(Object discValue) { + InheritInfo type = inheritInfo.getType(discValue.toString()); + return (T)type.getBeanDescriptor().createBean(); + } + + @Override + public void addInheritanceWhere(SpiQuery query) { + if (inheritInfo != null && !inheritInfo.isRoot()) { + query.where().eq(inheritInfo.getDiscriminatorColumn(), inheritInfo.getDiscriminatorValue()); + } + } + /** * Return true if this is an embedded bean. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanFkeyProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanFkeyProperty.java index 15521d4a4..27b8a118b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanFkeyProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanFkeyProperty.java @@ -162,23 +162,22 @@ public final class BeanFkeyProperty implements ElPropertyValue { throw new RuntimeException("ElPropertyDeploy only - not implemented"); } - public Object elConvertType(Object value) { + @Override + public Object convert(Object value) { throw new RuntimeException("ElPropertyDeploy only - not implemented"); } @Override - public void set(Object bean, Object value) { + public void pathSet(Object bean, Object value) { throw new RuntimeException("ElPropertyDeploy only - not implemented"); } - public void elSetValue(EntityBean bean, Object value, boolean populate) { - throw new RuntimeException("ElPropertyDeploy only - not implemented"); - } - - public Object elGetValue(EntityBean bean) { + @Override + public Object pathGet(Object bean) { throw new RuntimeException("ElPropertyDeploy only - not implemented"); } + @Override public Object elGetReference(EntityBean bean) { throw new RuntimeException("ElPropertyDeploy only - not implemented"); } 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 3c8b6e112..8defbe7af 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java @@ -767,7 +767,7 @@ public class BeanProperty implements ElPropertyValue, Property { } } - public Object elConvertType(Object value) { + public Object convert(Object value) { if (value == null) { return null; } @@ -775,25 +775,20 @@ public class BeanProperty implements ElPropertyValue, Property { } @Override - public void set(Object bean, Object value) { + public void pathSet(Object bean, Object value) { - // convert for Enums etc - Object logicalVal = convertToLogicalType(value); - elSetValue((EntityBean) bean, logicalVal, true); - } - - public void elSetValue(EntityBean bean, Object value, boolean populate) { if (bean != null) { - // Not using setValueIntercept at this stage - setValue(bean, value); + Object logicalVal = convertToLogicalType(value); + setValue((EntityBean)bean, logicalVal); } } - public Object elGetValue(EntityBean bean) { + @Override + public Object pathGet(Object bean) { if (bean == null) { return null; } - return getValueIntercept(bean); + return getValueIntercept((EntityBean)bean); } public Object elGetReference(EntityBean bean) { @@ -1330,7 +1325,7 @@ public class BeanProperty implements ElPropertyValue, Property { * Return true if this is a String Id property and should be treated as a code by the document store. */ private boolean isStringId(DocPropertyType type) { - return DocPropertyType.STRING == type && id; + return DocPropertyType.STRING == type && (id || discriminator); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java index d3fa6b68b..285afe984 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java @@ -77,8 +77,8 @@ public class BeanPropertyCompoundScalar extends BeanProperty { } @Override - public Object elGetValue(EntityBean bean) { - return getValue(bean); + public Object pathGet(Object bean) { + return ctProperty.getValue(bean); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java index b85c6c1f0..28ba06a7d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java @@ -145,6 +145,13 @@ public class InheritInfo { return descriptor; } + /** + * Return the local properties for this node in the hierarchy. + */ + public BeanProperty[] localProperties() { + return descriptor.propertiesLocal(); + } + /** * Get the bean property additionally looking in the sub types. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElComparatorProperty.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElComparatorProperty.java index 6348fd5cc..54aeb0b1b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElComparatorProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElComparatorProperty.java @@ -2,8 +2,6 @@ package com.avaje.ebeaninternal.server.el; import java.util.Comparator; -import com.avaje.ebean.bean.EntityBean; - /** * Comparator based on a ElGetValue. */ @@ -23,16 +21,14 @@ public final class ElComparatorProperty implements Comparator, ElComparato public int compare(T o1, T o2) { - Object val1 = elGetValue.elGetValue((EntityBean) o1); - Object val2 = elGetValue.elGetValue((EntityBean) o2); - + Object val1 = elGetValue.pathGet(o1); + Object val2 = elGetValue.pathGet(o2); return compareValues(val1, val2); } public int compareValue(Object value, T o2) { - Object val2 = elGetValue.elGetValue((EntityBean) o2); - + Object val2 = elGetValue.pathGet(o2); return compareValues(value, val2); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElFilter.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElFilter.java index d65fe8eb4..9ef9a520c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElFilter.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElFilter.java @@ -28,7 +28,7 @@ public final class ElFilter implements Filter { private Object convertValue(String propertyName, Object value) { // convert type of value to match expected type ElPropertyValue elGetValue = beanDescriptor.getElGetValue(propertyName); - return elGetValue.elConvertType(value); + return elGetValue.convert(value); } private ElComparator getElComparator(String propertyName) { @@ -87,8 +87,8 @@ public final class ElFilter implements Filter { public Filter between(String propertyName, Object min, Object max) { ElPropertyValue elGetValue = getElGetValue(propertyName); - min = elGetValue.elConvertType(min); - max = elGetValue.elConvertType(max); + min = elGetValue.convert(min); + max = elGetValue.convert(max); ElComparator elComparator = getElComparator(propertyName); diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java index 4b0892196..343f8e904 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java @@ -28,7 +28,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return pattern.matcher(v).matches(); } } @@ -55,7 +55,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return value.equalsIgnoreCase(v); } } @@ -75,7 +75,7 @@ class ElMatchBuilder { public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return charMatch.startsWith(v); } } @@ -95,7 +95,7 @@ class ElMatchBuilder { public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return charMatch.endsWith(v); } } @@ -106,7 +106,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return value.startsWith(v); } } @@ -117,7 +117,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - String v = (String) elGetValue.elGetValue((EntityBean) bean); + String v = (String) elGetValue.pathGet(bean); return value.endsWith(v); } } @@ -131,7 +131,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - return (null == elGetValue.elGetValue((EntityBean) bean)); + return (null == elGetValue.pathGet(bean)); } } @@ -144,7 +144,7 @@ class ElMatchBuilder { } public boolean isMatch(T bean) { - return (null != elGetValue.elGetValue((EntityBean) bean)); + return (null != elGetValue.pathGet(bean)); } } @@ -175,7 +175,7 @@ class ElMatchBuilder { public boolean isMatch(T bean) { - Object value = elGetValue.elGetValue((EntityBean) bean); + Object value = elGetValue.pathGet(bean); return value != null && set.contains(value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java index 9f7214eaa..8c5817ff0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java @@ -220,20 +220,19 @@ public class ElPropertyChain implements ElPropertyValue { return scalarType; } - public Object elConvertType(Object value) { + public Object convert(Object value) { // just convert using the last one in the chain - return lastElPropertyValue.elConvertType(value); + return lastElPropertyValue.convert(value); } - public Object elGetValue(EntityBean bean) { - + @Override + public Object pathGet(Object bean) { for (int i = 0; i < chain.length; i++) { - bean = (EntityBean) chain[i].elGetValue(bean); + bean = chain[i].pathGet(bean); if (bean == null) { return null; } } - return bean; } @@ -245,39 +244,25 @@ public class ElPropertyChain implements ElPropertyValue { prevBean = (EntityBean) chain[i].elGetReference(prevBean); } // try the last step in the chain - return chain[last].elGetValue(prevBean); + return chain[last].pathGet(prevBean); } @Override - public void set(Object bean, Object value) { - elSetValue((EntityBean)bean, value, true); - } + public void pathSet(Object bean, Object value) { - public void elSetValue(EntityBean bean, Object value, boolean populate) { - - EntityBean prevBean = bean; - if (populate) { - for (int i = 0; i < last; i++) { - // always return non null prevBean - prevBean = (EntityBean) chain[i].elGetReference(prevBean); - } - } else { - for (int i = 0; i < last; i++) { - // always return non null prevBean - prevBean = (EntityBean) chain[i].elGetValue(prevBean); - if (prevBean == null) { - break; - } - } + EntityBean prevBean = (EntityBean)bean; + for (int i = 0; i < last; i++) { + // always return non null prevBean + prevBean = (EntityBean) chain[i].elGetReference(prevBean); } if (prevBean != null) { if (lastBeanProperty != null) { // last chain element maps to a real scalar property - lastBeanProperty.setValueIntercept(prevBean, value); + lastBeanProperty.pathSet(prevBean, value); } else { // a non-scalar property of a Compound value object - lastElPropertyValue.elSetValue(prevBean, value, populate); + lastElPropertyValue.pathSet(prevBean, value); } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyValue.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyValue.java index 8ba64b744..d48361efd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyValue.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyValue.java @@ -60,53 +60,10 @@ public interface ElPropertyValue extends ElPropertyDeploy, ExpressionPath { */ int getDeployOrder(); - /** - * Return the default StringParser for the scalar property. - */ - StringParser getStringParser(); - - /** - * Return true if the last type is "DateTime capable" - can support - * {@link #parseDateTime(long)}. - */ - boolean isDateTimeCapable(); - - /** - * Return the underlying JDBC type or 0 if this is not a scalar type. - */ - int getJdbcType(); - - /** - * For DateTime capable scalar types convert the long systemTimeMillis into - * an appropriate java time (Date,Timestamp,Time,Calendar, JODA type etc). - */ - Object parseDateTime(long systemTimeMillis); - - /** - * Return the value from a given entity bean. - */ - Object elGetValue(EntityBean bean); - /** * Return the value ensuring objects prior to the top scalar property are * automatically populated. */ Object elGetReference(EntityBean bean); - /** - * Set a value given a root level bean. - *

- * If populate then - *

- */ - void elSetValue(EntityBean bean, Object value, boolean populate); - - /** - * Convert the value to the expected type. - *

- * Typically useful for converting strings to the appropriate number type - * etc. - *

- */ - Object elConvertType(Object value); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java index 6196867ac..c1cd7ca85 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java @@ -230,7 +230,6 @@ public final class CQueryPlanStats { return queryPlan.isAutoTuned(); } - @Override public String getQueryPlanHash() { return queryPlan.getPlanKey().toString(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/text/csv/TCsvReader.java b/src/main/java/com/avaje/ebeaninternal/server/text/csv/TCsvReader.java index 9cef2cb9a..ec98b1ed7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/text/csv/TCsvReader.java +++ b/src/main/java/com/avaje/ebeaninternal/server/text/csv/TCsvReader.java @@ -13,6 +13,7 @@ import java.util.Locale; import com.avaje.ebean.EbeanServer; import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.plugin.ExpressionPath; import com.avaje.ebean.text.StringParser; import com.avaje.ebean.text.TextException; import com.avaje.ebean.text.TimeStringParser; @@ -24,8 +25,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; import com.avaje.ebeaninternal.server.el.ElPropertyValue; /** - * - * @author rbygrave + * Implementation of the CsvReader */ public class TCsvReader implements CsvReader { @@ -55,9 +55,6 @@ public class TCsvReader implements CsvReader { private boolean addPropertiesFromHeader; - // private String addHeaderDateTimeFormat; - // private Locale addHeaderLocale; - public TCsvReader(EbeanServer server, BeanDescriptor descriptor) { this.server = server; this.descriptor = descriptor; @@ -114,11 +111,10 @@ public class TCsvReader implements CsvReader { public void addDateTime(String propertyName, String dateTimeFormat, Locale locale) { - ElPropertyValue elProp = descriptor.getElGetValue(propertyName); + ExpressionPath elProp = descriptor.getExpressionPath(propertyName); if (!elProp.isDateTimeCapable()) { throw new TextException("Property " + propertyName + " is not DateTime capable"); } - if (dateTimeFormat == null) { dateTimeFormat = getDefaultDateTimeFormat(elProp.getJdbcType()); } @@ -150,7 +146,7 @@ public class TCsvReader implements CsvReader { public void addProperty(String propertyName, StringParser parser) { - ElPropertyValue elProp = descriptor.getElGetValue(propertyName); + ExpressionPath elProp = descriptor.getExpressionPath(propertyName); if (parser == null) { parser = elProp.getStringParser(); } @@ -214,7 +210,7 @@ public class TCsvReader implements CsvReader { callback.end(row); } catch (Exception e) { - // notify that an error occured so that any + // notify that an error occurred so that any // transaction can be rolled back if required callback.endWithError(row, e); throw e; @@ -285,26 +281,23 @@ public class TCsvReader implements CsvReader { */ public static class CsvColumn { - private final ElPropertyValue elProp; + private final ExpressionPath path; private final StringParser parser; - private final boolean ignore; /** * Constructor for the IGNORE column. */ private CsvColumn() { - this.elProp = null; + this.path = null; this.parser = null; - this.ignore = true; } /** * Construct with a property and parser. */ - public CsvColumn(ElPropertyValue elProp, StringParser parser) { - this.elProp = elProp; + public CsvColumn(ExpressionPath path, StringParser parser) { + this.path = path; this.parser = parser; - this.ignore = false; } /** @@ -312,9 +305,9 @@ public class TCsvReader implements CsvReader { */ public void convertAndSet(String strValue, EntityBean bean) { - if (!ignore) { + if (parser != null && path != null) { Object value = parser.parse(strValue); - elProp.elSetValue(bean, value, true); + path.pathSet(bean, value); } } } @@ -327,19 +320,19 @@ public class TCsvReader implements CsvReader { private static class DateTimeParser implements StringParser { private final DateFormat dateFormat; - private final ElPropertyValue elProp; + private final ExpressionPath path; private final String format; - DateTimeParser(DateFormat dateFormat, String format, ElPropertyValue elProp) { + DateTimeParser(DateFormat dateFormat, String format, ExpressionPath path) { this.dateFormat = dateFormat; - this.elProp = elProp; + this.path = path; this.format = format; } public Object parse(String value) { try { Date dt = dateFormat.parse(value); - return elProp.parseDateTime(dt.getTime()); + return path.parseDateTime(dt.getTime()); } catch (ParseException e) { throw new TextException("Error parsing [" + value + "] using format[" + format + "]", e); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundPropertyElAdapter.java b/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundPropertyElAdapter.java index ef7255fdc..f7171beac 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundPropertyElAdapter.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/CtCompoundPropertyElAdapter.java @@ -28,7 +28,8 @@ public class CtCompoundPropertyElAdapter implements ElPropertyValue { this.deployOrder = deployOrder; } - public Object elConvertType(Object value) { + @Override + public Object convert(Object value) { return value; } @@ -36,16 +37,13 @@ public class CtCompoundPropertyElAdapter implements ElPropertyValue { return bean; } - public Object elGetValue(EntityBean bean) { + @Override + public Object pathGet(Object bean) { return prop.getValue(bean); } @Override - public void set(Object bean, Object value) { - elSetValue((EntityBean) bean, value, true); - } - - public void elSetValue(EntityBean bean, Object value, boolean populate) { + public void pathSet(Object bean, Object value) { prop.setValue(bean, value); } diff --git a/src/main/java/com/avaje/ebeanservice/docstore/api/DocStoreBeanAdapter.java b/src/main/java/com/avaje/ebeanservice/docstore/api/DocStoreBeanAdapter.java index 2e97058ab..73e1c3e6f 100644 --- a/src/main/java/com/avaje/ebeanservice/docstore/api/DocStoreBeanAdapter.java +++ b/src/main/java/com/avaje/ebeanservice/docstore/api/DocStoreBeanAdapter.java @@ -113,4 +113,9 @@ public interface DocStoreBeanAdapter extends BeanDocType { *

*/ String rawProperty(String property); + + /** + * Return true if this bean type as embedded invalidate registered. + */ + boolean hasEmbeddedInvalidation(); } diff --git a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStoreBeanBaseAdapter.java b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStoreBeanBaseAdapter.java index 48de04387..168af4037 100644 --- a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStoreBeanBaseAdapter.java +++ b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStoreBeanBaseAdapter.java @@ -4,12 +4,15 @@ import com.avaje.ebean.FetchPath; import com.avaje.ebean.Query; import com.avaje.ebean.annotation.DocStore; import com.avaje.ebean.annotation.DocStoreMode; +import com.avaje.ebean.plugin.BeanType; import com.avaje.ebean.text.PathProperties; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.server.core.PersistRequest; import com.avaje.ebeaninternal.server.core.PersistRequestBean; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanProperty; +import com.avaje.ebeaninternal.server.deploy.InheritInfo; +import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor; import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import com.avaje.ebeanservice.docstore.api.DocStoreBeanAdapter; import com.avaje.ebeanservice.docstore.api.DocStoreUpdateContext; @@ -41,11 +44,6 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< */ protected final boolean mapped; - /** - * Nested path properties defining the doc structure for indexing. - */ - protected final DocStructure docStructure; - /** * Identifier used in the queue system to identify the index. */ @@ -87,18 +85,28 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< */ protected final List embeddedInvalidation = new ArrayList(); + protected final PathProperties pathProps; + /** * Map of properties to 'raw' properties. */ - private Map sortableMap; + protected Map sortableMap; + /** + * Nested path properties defining the doc structure for indexing. + */ + protected DocStructure docStructure; + + protected DocumentMapping documentMapping; + + private boolean registerPaths; public DocStoreBeanBaseAdapter(BeanDescriptor desc, DeployBeanDescriptor deploy) { this.desc = desc; this.server = desc.getEbeanServer(); this.mapped = deploy.isDocStoreMapped(); - this.docStructure = (!mapped) ? null : derivePathProperties(deploy); + this.pathProps = deploy.getDocStorePathProperties(); this.docStore = deploy.getDocStore(); this.queueId = derive(desc, deploy.getDocStoreQueueId()); this.indexName = derive(desc, deploy.getDocStoreIndexName()); @@ -108,28 +116,30 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< this.delete = deploy.getDocStoreDeleteEvent(); } + @Override + public boolean hasEmbeddedInvalidation() { + return !embeddedInvalidation.isEmpty(); + } + @Override public DocumentMapping createDocMapping() { + if (documentMapping != null) { + return documentMapping; + } + if (!mapped) return null; - PathProperties paths = docStructure.doc(); + this.docStructure = derivePathProperties(pathProps); - DocMappingBuilder mappingBuilder = new DocMappingBuilder(paths, docStore); + DocMappingBuilder mappingBuilder = new DocMappingBuilder(docStructure.doc(), docStore); desc.docStoreMapping(mappingBuilder, null); - mappingBuilder.applyMapping(); - prepareMapping(mappingBuilder); sortableMap = mappingBuilder.collectSortable(); - docStructure.prepareMany(desc); - - return mappingBuilder.create(queueId, indexName, indexType); - } - - protected void prepareMapping(DocMappingBuilder mappingBuilder) { - // do nothing by default + documentMapping = mappingBuilder.create(queueId, indexName, indexType); + return documentMapping; } @Override @@ -159,7 +169,7 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< */ @Override public void registerPaths() { - if (mapped) { + if (mapped && !registerPaths) { Collection pathProps = docStructure.doc().getPathProps(); for (PathProperties.Props pathProp : pathProps) { String path = pathProp.getPath(); @@ -170,6 +180,7 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< targetDesc.docStoreAdapter().registerInvalidationPath(desc.getDocStoreQueueId(), fullPath, pathProp.getProperties()); } } + registerPaths = true; } } @@ -223,13 +234,8 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< * Return the pathProperties which defines the JSON document to index. * This can add derived/embedded/nested parts to the document. */ - protected DocStructure derivePathProperties(DeployBeanDescriptor deploy) { + protected DocStructure derivePathProperties(PathProperties pathProps) { - if (!mapped) { - return null; - } - - PathProperties pathProps = deploy.getDocStorePathProperties(); boolean includeByDefault = (pathProps == null); if (pathProps == null) { pathProps = new PathProperties(); @@ -238,13 +244,27 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< return getDocStructure(pathProps, includeByDefault); } - protected DocStructure getDocStructure(PathProperties pathProps, boolean includeByDefault) { + protected DocStructure getDocStructure(PathProperties pathProps, final boolean includeByDefault) { + + final DocStructure docStructure = new DocStructure(pathProps); - DocStructure docStructure = new DocStructure(pathProps); BeanProperty[] properties = desc.propertiesNonTransient(); for (int i = 0; i < properties.length; i++) { properties[i].docStoreInclude(includeByDefault, docStructure); } + + InheritInfo inheritInfo = desc.getInheritInfo(); + if (inheritInfo != null) { + inheritInfo.visitChildren(new InheritInfoVisitor() { + @Override + public void visit(InheritInfo inheritInfo) { + for (BeanProperty localProperty : inheritInfo.localProperties()) { + localProperty.docStoreInclude(includeByDefault, docStructure); + } + } + }); + } + return docStructure; } @@ -293,7 +313,7 @@ public abstract class DocStoreBeanBaseAdapter implements DocStoreBeanAdapter< /** * Return the supplied value or default to the bean name lower case. */ - protected String derive(BeanDescriptor desc, String suppliedValue) { + protected String derive(BeanType desc, String suppliedValue) { return (suppliedValue != null && suppliedValue.length() > 0) ? suppliedValue : desc.getName().toLowerCase(); } diff --git a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java index 87a07a01b..adb658759 100644 --- a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java +++ b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java @@ -73,7 +73,7 @@ public class DocStructure { public void prepareMany(BeanDescriptor desc) { Set strings = embedded.keySet(); for (String prop : strings) { - BeanPropertyAssoc embProp = (BeanPropertyAssoc)desc.getBeanProperty(prop); + BeanPropertyAssoc embProp = (BeanPropertyAssoc)desc.findBeanProperty(prop); if (embProp.isMany()) { prepare(prop, embProp); } diff --git a/src/test/java/com/avaje/ebean/plugin/BeanTypeTest.java b/src/test/java/com/avaje/ebean/plugin/BeanTypeTest.java index 917d9653a..1ca3b45db 100644 --- a/src/test/java/com/avaje/ebean/plugin/BeanTypeTest.java +++ b/src/test/java/com/avaje/ebean/plugin/BeanTypeTest.java @@ -3,17 +3,24 @@ package com.avaje.ebean.plugin; import com.avaje.ebean.Ebean; import com.avaje.ebean.EbeanServer; import com.avaje.ebean.FetchPath; +import com.avaje.ebean.Query; import com.avaje.ebean.text.PathProperties; import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail; +import com.avaje.tests.inheritance.Stockforecast; +import com.avaje.tests.model.basic.Car; import com.avaje.tests.model.basic.Customer; import com.avaje.tests.model.basic.Order; import com.avaje.tests.model.basic.OrderDetail; import com.avaje.tests.model.basic.Person; import com.avaje.tests.model.basic.Product; +import com.avaje.tests.model.basic.Vehicle; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class BeanTypeTest { @@ -189,4 +196,48 @@ public class BeanTypeTest { public void docStoreUpdateEmbedded() throws Exception { beanType(Order.class).docStore().updateEmbedded(1, "customer", "someJson", null); } + + @Test + public void hasInheritance_when_not() { + assertFalse(beanType(Order.class).hasInheritance()); + } + + @Test + public void hasInheritance_when_root() { + assertTrue(beanType(Vehicle.class).hasInheritance()); + } + + @Test + public void hasInheritance_when_leaf() { + assertTrue(beanType(Car.class).hasInheritance()); + } + + @Test + public void getDiscColumn_when_default() { + assertEquals(beanType(Car.class).getDiscColumn(),"dtype"); + } + + @Test + public void getDiscColumn_when_set() { + assertEquals(beanType(Stockforecast.class).getDiscColumn(),"type"); + } + + @Test + public void createBeanUsingDisc_when_set() { + Vehicle vehicle = beanType(Vehicle.class).createBeanUsingDisc("C"); + assertTrue(vehicle instanceof Car); + } + + @Test + public void addInheritanceWhere_when_leaf() { + Query query = server.find(Vehicle.class); + beanType(Car.class).addInheritanceWhere((SpiQuery)query); + } + + @Test + public void addInheritanceWhere_when_root() { + Query query = server.find(Vehicle.class); + beanType(Vehicle.class).addInheritanceWhere((SpiQuery)query); + } + } \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/plugin/ExpressionPathTest.java b/src/test/java/com/avaje/ebean/plugin/ExpressionPathTest.java index 54ba6bd46..809e92200 100644 --- a/src/test/java/com/avaje/ebean/plugin/ExpressionPathTest.java +++ b/src/test/java/com/avaje/ebean/plugin/ExpressionPathTest.java @@ -63,7 +63,7 @@ public class ExpressionPathTest { BeanType beanType = beanType(Order.class); Order order = new Order(); - beanType.getExpressionPath("id").set(order, 42); + beanType.getExpressionPath("id").pathSet(order, 42); assertThat(order.getId()).isEqualTo(42); } @@ -72,7 +72,7 @@ public class ExpressionPathTest { BeanType beanType = beanType(Order.class); Order order = new Order(); - beanType.getExpressionPath("customer.name").set(order, "Rob"); + beanType.getExpressionPath("customer.name").pathSet(order, "Rob"); assertThat(order.getCustomer().getName()).isEqualTo("Rob"); } diff --git a/src/test/java/com/avaje/tests/ddd/iud/TestDPersonEl.java b/src/test/java/com/avaje/tests/ddd/iud/TestDPersonEl.java index 2f28f7d26..8f1157b4b 100644 --- a/src/test/java/com/avaje/tests/ddd/iud/TestDPersonEl.java +++ b/src/test/java/com/avaje/tests/ddd/iud/TestDPersonEl.java @@ -2,62 +2,67 @@ package com.avaje.tests.ddd.iud; import com.avaje.ebean.Ebean; import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.plugin.BeanType; +import com.avaje.ebean.plugin.ExpressionPath; +import com.avaje.ebean.plugin.SpiServer; import com.avaje.ebean.text.json.JsonContext; -import com.avaje.ebeaninternal.api.SpiEbeanServer; -import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.tests.model.ddd.DPerson; import com.avaje.tests.model.ivo.CMoney; import com.avaje.tests.model.ivo.Money; -import junit.framework.TestCase; -import org.junit.Assert; +import org.junit.Test; import java.io.IOException; import java.util.Currency; -public class TestDPersonEl extends TestCase { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; - public void test() throws IOException { +public class TestDPersonEl { - Currency NZD = Currency.getInstance("NZD"); - - DPerson p = new DPerson(); - p.setFirstName("first"); - p.setLastName("last"); - p.setSalary(new Money("12200")); - p.setCmoney(new CMoney(new Money("12"), NZD)); - - SpiEbeanServer server = (SpiEbeanServer)Ebean.getServer(null); - - BeanDescriptor descriptor = server.getBeanDescriptor(DPerson.class); - - ElPropertyValue elCmoney = descriptor.getElGetValue("cmoney"); -// ElPropertyValue elCmoneyAmt = descriptor.getElGetValue("cmoney.amount"); -// ElPropertyValue elCmoneyCur = descriptor.getElGetValue("cmoney.currency"); - - JsonContext jsonContext = server.json(); - String json = jsonContext.toJson(p); - - DPerson bean = jsonContext.toBean(DPerson.class, json); - Assert.assertEquals("first", bean.getFirstName()); - Assert.assertEquals(new Money("12200"), bean.getSalary()); - Assert.assertEquals(new Money("12"), bean.getCmoney().getAmount()); - Assert.assertEquals(NZD, bean.getCmoney().getCurrency()); - - - EntityBean entityBean = (EntityBean)p; - - Object cmoney = elCmoney.elGetValue(entityBean); -// Object amt = elCmoneyAmt.elGetValue(entityBean); -// Object cur = elCmoneyCur.elGetValue(entityBean); - - Assert.assertNotNull(cmoney); -// Assert.assertEquals(new Money("12"), amt); -// Assert.assertEquals(NZD, cur); - - p.setCmoney(null); - Assert.assertNull(p.getCmoney()); + @Test + public void test() throws IOException { + + Currency NZD = Currency.getInstance("NZD"); + + DPerson p = new DPerson(); + p.setFirstName("first"); + p.setLastName("last"); + p.setSalary(new Money("12200")); + p.setCmoney(new CMoney(new Money("12"), NZD)); + + SpiServer server = Ebean.getDefaultServer().getPluginApi(); + + BeanType descriptor = server.getBeanType(DPerson.class); + + + JsonContext jsonContext = server.json(); + String json = jsonContext.toJson(p); + + DPerson bean = jsonContext.toBean(DPerson.class, json); + assertEquals("first", bean.getFirstName()); + assertEquals(new Money("12200"), bean.getSalary()); + assertEquals(new Money("12"), bean.getCmoney().getAmount()); + assertEquals(NZD, bean.getCmoney().getCurrency()); + + + EntityBean entityBean = (EntityBean) p; + + ExpressionPath elCmoney = descriptor.getExpressionPath("cmoney"); + ExpressionPath elCmoneyAmt = descriptor.getExpressionPath("cmoney.amount"); + ExpressionPath elCmoneyCur = descriptor.getExpressionPath("cmoney.currency"); + + Object cmoney = elCmoney.pathGet(entityBean); + Object amt = elCmoneyAmt.pathGet(entityBean); + Object cur = elCmoneyCur.pathGet(entityBean); + + assertNotNull(cmoney); + assertEquals(new Money("12"), amt); + assertEquals(NZD, cur); + + p.setCmoney(null); + assertNull(p.getCmoney()); + + } - } - } diff --git a/src/test/java/com/avaje/tests/el/TestElGetReference.java b/src/test/java/com/avaje/tests/el/TestElGetReference.java deleted file mode 100644 index a6ecf5f02..000000000 --- a/src/test/java/com/avaje/tests/el/TestElGetReference.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.avaje.tests.el; - -import junit.framework.TestCase; - -import com.avaje.ebean.Ebean; -import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebeaninternal.api.SpiEbeanServer; -import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.el.ElPropertyValue; -import com.avaje.tests.model.basic.Address; -import com.avaje.tests.model.basic.Customer; - -public class TestElGetReference extends TestCase { - - - public void test() { - - Address a = new Address(); - a.setId((short)12); - a.setLine1("line1"); - a.setCity("Auckland"); - - Customer c0 = new Customer(); - c0.setBillingAddress(a); - - Customer c1 = new Customer(); - - SpiEbeanServer server = (SpiEbeanServer)Ebean.getServer(null); - BeanDescriptor descriptor = server.getBeanDescriptor(Customer.class); - - ElPropertyValue elProp = descriptor.getElGetValue("billingAddress.id"); - ElPropertyValue addrLine1Prop = descriptor.getElGetValue("billingAddress.line1"); - ElPropertyValue addrCityProp = descriptor.getElGetValue("billingAddress.city"); - - elProp.elGetReference((EntityBean)c0); - elProp.elGetReference((EntityBean)c1); - - addrLine1Prop.elSetValue((EntityBean)c1, "12 someplace", true); - addrCityProp.elSetValue((EntityBean)c1, "Auckland", true); - } -} diff --git a/src/test/java/com/avaje/tests/el/TestPathExpression.java b/src/test/java/com/avaje/tests/el/TestPathExpression.java new file mode 100644 index 000000000..c9526b0db --- /dev/null +++ b/src/test/java/com/avaje/tests/el/TestPathExpression.java @@ -0,0 +1,81 @@ +package com.avaje.tests.el; + +import com.avaje.ebean.Ebean; +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.plugin.BeanType; +import com.avaje.ebean.plugin.ExpressionPath; +import com.avaje.ebean.plugin.SpiServer; +import com.avaje.tests.model.basic.Address; +import com.avaje.tests.model.basic.Country; +import com.avaje.tests.model.basic.Customer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TestPathExpression { + + final BeanType beanType; + final ExpressionPath billingId; + final ExpressionPath line1; + final ExpressionPath city; + + public TestPathExpression() { + SpiServer server = Ebean.getDefaultServer().getPluginApi(); + beanType = server.getBeanType(Customer.class); + billingId = beanType.getExpressionPath("billingAddress.id"); + line1 = beanType.getExpressionPath("billingAddress.line1"); + city = beanType.getExpressionPath("billingAddress.city"); + } + + @Test + public void pathSet() { + + Customer c1 = new Customer(); + line1.pathSet(c1, "12 someplace"); + city.pathSet(c1, "Auckland"); + billingId.pathSet(c1, 4); + + beanType.getExpressionPath("id").pathSet(c1, 42L); + beanType.getExpressionPath("name").pathSet(c1, "jimmy"); + beanType.getExpressionPath("status").pathSet(c1, "ACTIVE"); + beanType.getExpressionPath("billingAddress.country.code").pathSet(c1, "NZ"); + beanType.getExpressionPath("billingAddress.country.name").pathSet(c1, "New Zealand"); + + + assertEquals(c1.getId(), Integer.valueOf(42)); + assertEquals(c1.getName(), "jimmy"); + assertEquals(c1.getStatus(), Customer.Status.ACTIVE); + assertEquals(c1.getBillingAddress().getLine1(), "12 someplace"); + assertEquals(c1.getBillingAddress().getCity(), "Auckland"); + assertEquals(c1.getBillingAddress().getId(), Short.valueOf("4")); + + assertEquals(c1.getBillingAddress().getCountry().getCode(), "NZ"); + assertEquals(c1.getBillingAddress().getCountry().getName(), "New Zealand"); + } + + @Test + public void pathGet() { + + Address billingAddress = new Address(); + billingAddress.setId((short)12); + billingAddress.setLine1("line1"); + billingAddress.setCity("Auckland"); + + Country nz = new Country(); + nz.setCode("NZ"); + nz.setName("New Zealand"); + billingAddress.setCountry(nz); + + Customer c0 = new Customer(); + c0.setBillingAddress(billingAddress); + + EntityBean e0 = (EntityBean)c0; + assertEquals(line1.pathGet(e0), "line1"); + assertEquals(city.pathGet(e0), "Auckland"); + assertEquals(billingId.pathGet(e0), Short.valueOf("12")); + + + assertEquals(beanType.getExpressionPath("billingAddress.country.code").pathGet(e0), "NZ"); + assertEquals(beanType.getExpressionPath("billingAddress.country.name").pathGet(e0), "New Zealand"); + } +}