mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-25 15:58:40 +00:00
#593 - Refactor SPI - Move methods from ElPropertyValue to ExpressionPath
This commit is contained in:
@@ -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<T> {
|
||||
|
||||
/**
|
||||
* 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<T> {
|
||||
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.
|
||||
* <p>
|
||||
* This can return a property or nested property path.
|
||||
* </p>
|
||||
@@ -154,4 +160,28 @@ public interface BeanType<T> {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* Typically useful for converting strings to the appropriate number type etc.
|
||||
* </p>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ public final class PersistRequestBean<T> 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() {
|
||||
|
||||
@@ -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<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
private final String docStoreQueueId;
|
||||
|
||||
private DocumentMapping docMapping;
|
||||
|
||||
private final BeanDescriptorDraftHelp<T> draftHelp;
|
||||
private final BeanDescriptorCacheHelp<T> cacheHelp;
|
||||
private final BeanDescriptorJsonHelp<T> jsonHelp;
|
||||
private final DocStoreBeanAdapter<T> docStoreAdapter;
|
||||
private DocStoreBeanAdapter<T> docStoreAdapter;
|
||||
private DocumentMapping docMapping;
|
||||
|
||||
|
||||
private final String defaultSelectClause;
|
||||
|
||||
@@ -680,7 +683,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
namedUpdate.initialise(parser);
|
||||
}
|
||||
}
|
||||
docStoreAdapter.registerPaths();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -690,7 +692,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
for (int i = 0; i < propertiesMany.length; i++) {
|
||||
propertiesMany[i].initialisePostTarget();
|
||||
}
|
||||
if (inheritInfo != null && !inheritInfo.isRoot()) {
|
||||
docStoreAdapter = (DocStoreBeanAdapter<T>)inheritInfo.getRoot().getBeanDescriptor().docStoreAdapter();
|
||||
}
|
||||
docMapping = docStoreAdapter.createDocMapping();
|
||||
docStoreAdapter.registerPaths();
|
||||
}
|
||||
|
||||
public void initInheritInfo() {
|
||||
@@ -932,16 +938,44 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
/**
|
||||
* 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<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
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<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propName) {
|
||||
return getBeanProperty(propName);
|
||||
return findBeanProperty(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1976,6 +2010,30 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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<T> implements Comparator<T>, 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class ElFilter<T> implements Filter<T> {
|
||||
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<T> getElComparator(String propertyName) {
|
||||
@@ -87,8 +87,8 @@ public final class ElFilter<T> implements Filter<T> {
|
||||
public Filter<T> 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<T> elComparator = getElComparator(propertyName);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* If populate then
|
||||
* </p>
|
||||
*/
|
||||
void elSetValue(EntityBean bean, Object value, boolean populate);
|
||||
|
||||
/**
|
||||
* Convert the value to the expected type.
|
||||
* <p>
|
||||
* Typically useful for converting strings to the appropriate number type
|
||||
* etc.
|
||||
* </p>
|
||||
*/
|
||||
Object elConvertType(Object value);
|
||||
}
|
||||
|
||||
@@ -230,7 +230,6 @@ public final class CQueryPlanStats {
|
||||
return queryPlan.isAutoTuned();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getQueryPlanHash() {
|
||||
return queryPlan.getPlanKey().toString();
|
||||
|
||||
@@ -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<T> implements CsvReader<T> {
|
||||
|
||||
@@ -55,9 +55,6 @@ public class TCsvReader<T> implements CsvReader<T> {
|
||||
|
||||
private boolean addPropertiesFromHeader;
|
||||
|
||||
// private String addHeaderDateTimeFormat;
|
||||
// private Locale addHeaderLocale;
|
||||
|
||||
public TCsvReader(EbeanServer server, BeanDescriptor<T> descriptor) {
|
||||
this.server = server;
|
||||
this.descriptor = descriptor;
|
||||
@@ -114,11 +111,10 @@ public class TCsvReader<T> implements CsvReader<T> {
|
||||
|
||||
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<T> implements CsvReader<T> {
|
||||
|
||||
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<T> implements CsvReader<T> {
|
||||
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<T> implements CsvReader<T> {
|
||||
*/
|
||||
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<T> implements CsvReader<T> {
|
||||
*/
|
||||
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<T> implements CsvReader<T> {
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,4 +113,9 @@ public interface DocStoreBeanAdapter<T> extends BeanDocType<T> {
|
||||
* </p>
|
||||
*/
|
||||
String rawProperty(String property);
|
||||
|
||||
/**
|
||||
* Return true if this bean type as embedded invalidate registered.
|
||||
*/
|
||||
boolean hasEmbeddedInvalidation();
|
||||
}
|
||||
|
||||
+48
-28
@@ -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<T> 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<T> implements DocStoreBeanAdapter<
|
||||
*/
|
||||
protected final List<DocStoreEmbeddedInvalidation> embeddedInvalidation = new ArrayList<DocStoreEmbeddedInvalidation>();
|
||||
|
||||
protected final PathProperties pathProps;
|
||||
|
||||
/**
|
||||
* Map of properties to 'raw' properties.
|
||||
*/
|
||||
private Map<String, String> sortableMap;
|
||||
protected Map<String, String> sortableMap;
|
||||
|
||||
/**
|
||||
* Nested path properties defining the doc structure for indexing.
|
||||
*/
|
||||
protected DocStructure docStructure;
|
||||
|
||||
protected DocumentMapping documentMapping;
|
||||
|
||||
private boolean registerPaths;
|
||||
|
||||
public DocStoreBeanBaseAdapter(BeanDescriptor<T> desc, DeployBeanDescriptor<T> 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<T> 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<T> implements DocStoreBeanAdapter<
|
||||
*/
|
||||
@Override
|
||||
public void registerPaths() {
|
||||
if (mapped) {
|
||||
if (mapped && !registerPaths) {
|
||||
Collection<PathProperties.Props> pathProps = docStructure.doc().getPathProps();
|
||||
for (PathProperties.Props pathProp : pathProps) {
|
||||
String path = pathProp.getPath();
|
||||
@@ -170,6 +180,7 @@ public abstract class DocStoreBeanBaseAdapter<T> implements DocStoreBeanAdapter<
|
||||
targetDesc.docStoreAdapter().registerInvalidationPath(desc.getDocStoreQueueId(), fullPath, pathProp.getProperties());
|
||||
}
|
||||
}
|
||||
registerPaths = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,13 +234,8 @@ public abstract class DocStoreBeanBaseAdapter<T> 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<T> 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<T> 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<T> implements DocStoreBeanAdapter<
|
||||
/**
|
||||
* Return the supplied value or default to the bean name lower case.
|
||||
*/
|
||||
protected String derive(BeanDescriptor<T> desc, String suppliedValue) {
|
||||
protected String derive(BeanType<?> desc, String suppliedValue) {
|
||||
return (suppliedValue != null && suppliedValue.length() > 0) ? suppliedValue : desc.getName().toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public class DocStructure {
|
||||
public <T> void prepareMany(BeanDescriptor<T> desc) {
|
||||
Set<String> 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user