mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
262 lines
6.6 KiB
Java
262 lines
6.6 KiB
Java
package com.avaje.ebeaninternal.server.el;
|
|
|
|
import com.avaje.ebean.bean.EntityBean;
|
|
import com.avaje.ebean.text.StringParser;
|
|
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
|
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
|
import com.avaje.ebeaninternal.server.query.SplitName;
|
|
import com.avaje.ebeaninternal.server.type.ScalarType;
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
/**
|
|
* A ElGetValue based on a chain of properties.
|
|
* <p>
|
|
* Used to get the value for an compound expression like customer.name or
|
|
* customer.shippingAddress.city etc.
|
|
* </p>
|
|
* <p>
|
|
* Note that if any element in the chain returns null, then null is returned and
|
|
* no further processing of the chain occurs.
|
|
* </p>
|
|
*/
|
|
public class ElPropertyChain implements ElPropertyValue {
|
|
|
|
private final String prefix;
|
|
|
|
private final String placeHolder;
|
|
private final String placeHolderEncrypted;
|
|
|
|
private final String name;
|
|
|
|
private final String expression;
|
|
|
|
private final boolean containsMany;
|
|
|
|
private final ElPropertyValue[] chain;
|
|
|
|
private final boolean assocId;
|
|
private final int last;
|
|
private final BeanProperty lastBeanProperty;
|
|
private final ScalarType<?> scalarType;
|
|
|
|
private final ElPropertyValue lastElPropertyValue;
|
|
|
|
public ElPropertyChain(boolean containsMany, boolean embedded, String expression, ElPropertyValue[] chain) {
|
|
|
|
this.containsMany = containsMany;
|
|
this.chain = chain;
|
|
this.expression = expression;
|
|
int dotPos = expression.lastIndexOf('.');
|
|
if (dotPos > -1) {
|
|
this.name = expression.substring(dotPos + 1);
|
|
if (embedded) {
|
|
int embPos = expression.lastIndexOf('.', dotPos - 1);
|
|
this.prefix = embPos == -1 ? null : expression.substring(0, embPos);
|
|
|
|
} else {
|
|
this.prefix = expression.substring(0, dotPos);
|
|
}
|
|
} else {
|
|
this.prefix = null;
|
|
this.name = expression;
|
|
}
|
|
|
|
this.assocId = chain[chain.length - 1].isAssocId();
|
|
|
|
this.last = chain.length - 1;
|
|
this.lastBeanProperty = chain[chain.length - 1].getBeanProperty();
|
|
if (lastBeanProperty != null) {
|
|
this.scalarType = lastBeanProperty.getScalarType();
|
|
} else {
|
|
// case for nested compound type (non-scalar)
|
|
this.scalarType = null;
|
|
}
|
|
this.lastElPropertyValue = chain[chain.length - 1];
|
|
this.placeHolder = getElPlaceHolder(prefix, lastElPropertyValue, false);
|
|
this.placeHolderEncrypted = getElPlaceHolder(prefix, lastElPropertyValue, true);
|
|
}
|
|
|
|
public String toString() {
|
|
return "expr:" + expression + " chain:" + Arrays.toString(chain);
|
|
}
|
|
|
|
private String getElPlaceHolder(String prefix, ElPropertyValue lastElPropertyValue, boolean encrypted) {
|
|
if (prefix == null) {
|
|
return lastElPropertyValue.getElPlaceholder(encrypted);
|
|
}
|
|
|
|
String el = lastElPropertyValue.getElPlaceholder(encrypted);
|
|
|
|
if (!el.contains("${}")) {
|
|
// typically a secondary table property
|
|
return StringHelper.replaceString(el, "${", "${" + prefix + ".");
|
|
} else {
|
|
return StringHelper.replaceString(el, ROOT_ELPREFIX, "${" + prefix + "}");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if there is a many property from sinceProperty to
|
|
* the end of this chain.
|
|
*/
|
|
public boolean containsManySince(String sinceProperty) {
|
|
if (sinceProperty == null) {
|
|
return containsMany;
|
|
}
|
|
if (!expression.startsWith(sinceProperty)) {
|
|
return containsMany;
|
|
}
|
|
|
|
int i = 1 + SplitName.count(sinceProperty);
|
|
|
|
for (; i < chain.length; i++) {
|
|
if (chain[i].getBeanProperty().containsMany()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean containsFormulaWithJoin() {
|
|
// Not cascading the check at this stage
|
|
return false;
|
|
}
|
|
|
|
public boolean containsMany() {
|
|
return containsMany;
|
|
}
|
|
|
|
public String getElPrefix() {
|
|
return prefix;
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public String getElName() {
|
|
return expression;
|
|
}
|
|
|
|
public String getElPlaceholder(boolean encrypted) {
|
|
return encrypted ? placeHolderEncrypted : placeHolder;
|
|
}
|
|
|
|
public boolean isDbEncrypted() {
|
|
return lastElPropertyValue.isDbEncrypted();
|
|
}
|
|
|
|
public boolean isLocalEncrypted() {
|
|
return lastElPropertyValue.isLocalEncrypted();
|
|
}
|
|
|
|
public Object[] getAssocIdValues(EntityBean bean) {
|
|
// Don't navigate the object graph as bean
|
|
// is assumed to be the appropriate type
|
|
return lastElPropertyValue.getAssocIdValues(bean);
|
|
}
|
|
|
|
public String getAssocIdExpression(String prefix, String operator) {
|
|
return lastElPropertyValue.getAssocIdExpression(expression, operator);
|
|
}
|
|
|
|
public String getAssocIdInExpr(String prefix) {
|
|
return lastElPropertyValue.getAssocIdInExpr(prefix);
|
|
}
|
|
|
|
public String getAssocIdInValueExpr(int size) {
|
|
return lastElPropertyValue.getAssocIdInValueExpr(size);
|
|
}
|
|
|
|
public boolean isAssocId() {
|
|
return assocId;
|
|
}
|
|
|
|
public boolean isAssocProperty() {
|
|
for (int i = 0; i < chain.length; i++) {
|
|
if (chain[i].isAssocProperty()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public String getDbColumn() {
|
|
return lastElPropertyValue.getDbColumn();
|
|
}
|
|
|
|
public BeanProperty getBeanProperty() {
|
|
return lastBeanProperty;
|
|
}
|
|
|
|
|
|
public boolean isDateTimeCapable() {
|
|
return scalarType != null && scalarType.isDateTimeCapable();
|
|
}
|
|
|
|
public int getJdbcType() {
|
|
return scalarType == null ? 0 : scalarType.getJdbcType();
|
|
}
|
|
|
|
public Object parseDateTime(long systemTimeMillis) {
|
|
return scalarType.convertFromMillis(systemTimeMillis);
|
|
}
|
|
|
|
public StringParser getStringParser() {
|
|
return scalarType;
|
|
}
|
|
|
|
public Object convert(Object value) {
|
|
// just convert using the last one in the chain
|
|
return lastElPropertyValue.convert(value);
|
|
}
|
|
|
|
@Override
|
|
public Object pathGet(Object bean) {
|
|
for (int i = 0; i < chain.length; i++) {
|
|
bean = chain[i].pathGet(bean);
|
|
if (bean == null) {
|
|
return null;
|
|
}
|
|
}
|
|
return bean;
|
|
}
|
|
|
|
@Override
|
|
public Object pathGetNested(Object bean) {
|
|
|
|
Object prevBean = bean;
|
|
for (int i = 0; i < last; i++) {
|
|
// always return non null prevBean
|
|
prevBean = chain[i].pathGetNested(prevBean);
|
|
}
|
|
// try the last step in the chain
|
|
return chain[last].pathGet(prevBean);
|
|
}
|
|
|
|
@Override
|
|
public void pathSet(Object bean, Object value) {
|
|
|
|
Object prevBean = bean;
|
|
for (int i = 0; i < last; i++) {
|
|
prevBean = chain[i].pathGetNested(prevBean);
|
|
}
|
|
if (prevBean != null) {
|
|
if (lastBeanProperty != null) {
|
|
// last chain element maps to a real scalar property
|
|
lastBeanProperty.pathSet(prevBean, value);
|
|
|
|
} else {
|
|
// a non-scalar property of a Compound value object
|
|
lastElPropertyValue.pathSet(prevBean, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|