package com.avaje.ebeaninternal.server.deploy;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.Map;
import javax.persistence.PersistenceException;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.config.EncryptKey;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.text.StringFormatter;
import com.avaje.ebean.text.StringParser;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter;
import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
*/
public class BeanProperty implements ElPropertyValue {
/**
* Advanced bean deployment. To exclude this property from update where
* clause.
*/
public static final String EXCLUDE_FROM_UPDATE_WHERE = "EXCLUDE_FROM_UPDATE_WHERE";
/**
* Advanced bean deployment. To exclude this property from delete where
* clause.
*/
public static final String EXCLUDE_FROM_DELETE_WHERE = "EXCLUDE_FROM_DELETE_WHERE";
/**
* Advanced bean deployment. To exclude this property from insert.
*/
public static final String EXCLUDE_FROM_INSERT = "EXCLUDE_FROM_INSERT";
/**
* Advanced bean deployment. To exclude this property from update set
* clause.
*/
public static final String EXCLUDE_FROM_UPDATE = "EXCLUDE_FROM_UPDATE";
/**
* Flag to mark this at part of the unique id.
*/
final boolean id;
/**
* Flag to make this as a dummy property for unidirecitonal relationships.
*/
final boolean unidirectionalShadow;
/**
* Flag set if this maps to the inheritance discriminator column
*/
final boolean discriminator;
/**
* Flag to mark the property as embedded. This could be on
* BeanPropertyAssocOne rather than here. Put it here for checking Id type
* (embedded or not).
*/
final boolean embedded;
/**
* Flag indicating if this the version property.
*/
final boolean version;
final boolean naturalKey;
/**
* Set if this property is nullable.
*/
final boolean nullable;
final boolean unique;
/**
* Is this property include in database resultSet.
*/
final boolean dbRead;
/**
* Include in DB insert.
*/
final boolean dbInsertable;
/**
* Include in DB update.
*/
final boolean dbUpdatable;
/**
* True if the property is based on a SECONDARY table.
*/
final boolean secondaryTable;
final TableJoin secondaryTableJoin;
final String secondaryTableJoinPrefix;
/**
* The property is inherited from a super class.
*/
final boolean inherited;
final Class<?> owningType;
final boolean local;
/**
* True if the property is a Clob, Blob LongVarchar or LongVarbinary.
*/
final boolean lob;
final boolean fetchEager;
final boolean isTransient;
/**
* The logical bean property name.
*/
final String name;
final int propertyIndex;
/**
* The reflected field.
*/
final Field field;
/**
* The bean type.
*/
final Class<?> propertyType;
final String dbBind;
/**
* The database column. This can include quoted identifiers.
*/
final String dbColumn;
final String elPlaceHolder;
final String elPlaceHolderEncrypted;
/**
* Select part of a SQL Formula used to populate this property.
*/
final String sqlFormulaSelect;
/**
* Join part of a SQL Formula.
*/
final String sqlFormulaJoin;
final boolean formula;
/**
* Set to true if stored encrypted.
*/
final boolean dbEncrypted;
final boolean localEncrypted;
final int dbEncryptedType;
/**
* The jdbc data type this maps to.
*/
final int dbType;
/**
* The default value to insert if null.
*/
final Object defaultValue;
/**
* Extra deployment parameters.
*/
final Map<String, String> extraAttributeMap;
/**
* The method used to read the property.
*/
final Method readMethod;
/**
* The method used to write the property.
*/
final Method writeMethod;
/**
* Generator for insert or update timestamp etc.
*/
final GeneratedProperty generatedProperty;
final BeanReflectGetter getter;
final BeanReflectSetter setter;
final BeanDescriptor<?> descriptor;
/**
* Used for non-jdbc native types (java.util.Date Enums etc). Converts from
* logical to jdbc types.
*/
@SuppressWarnings("rawtypes")
final ScalarType scalarType;
boolean cascadeValidate;
/**
* The length or precision for DB column.
*/
final int dbLength;
/**
* The scale for DB column (decimal).
*/
final int dbScale;
/**
* Deployment defined DB column definition.
*/
final String dbColumnDefn;
/**
* DB Constraint (typically check constraint on enum)
*/
final String dbConstraintExpression;
final DbEncryptFunction dbEncryptFunction;
int deployOrder;
final boolean jsonSerialize;
final boolean jsonDeserialize;
final boolean indexed;
final String indexName;
public BeanProperty(DeployBeanProperty deploy) {
this(null, null, deploy);
}
public BeanProperty(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanProperty deploy) {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
this.indexed = deploy.isIndexed();
this.indexName = deploy.getIndexName();
this.unidirectionalShadow = deploy.isUndirectionalShadow();
this.discriminator = deploy.isDiscriminator();
this.localEncrypted = deploy.isLocalEncrypted();
this.dbEncrypted = deploy.isDbEncrypted();
this.dbEncryptedType = deploy.getDbEncryptedType();
this.dbEncryptFunction = deploy.getDbEncryptFunction();
this.dbBind = deploy.getDbBind();
this.dbRead = deploy.isDbRead();
this.dbInsertable = deploy.isDbInsertable();
this.dbUpdatable = deploy.isDbUpdateable();
this.secondaryTable = deploy.isSecondaryTable();
if (secondaryTable) {
this.secondaryTableJoin = new TableJoin(deploy.getSecondaryTableJoin(), null);
this.secondaryTableJoinPrefix = deploy.getSecondaryTableJoinPrefix();
} else {
this.secondaryTableJoin = null;
this.secondaryTableJoinPrefix = null;
}
this.fetchEager = deploy.isFetchEager();
this.isTransient = deploy.isTransient();
this.nullable = deploy.isNullable();
this.unique = deploy.isUnique();
this.naturalKey = deploy.isNaturalKey();
this.dbLength = deploy.getDbLength();
this.dbScale = deploy.getDbScale();
this.dbColumnDefn = InternString.intern(deploy.getDbColumnDefn());
this.dbConstraintExpression = InternString.intern(deploy.getDbConstraintExpression());
this.inherited = false;// deploy.isInherited();
this.owningType = deploy.getOwningType();
this.local = deploy.isLocal();
this.version = deploy.isVersionColumn();
this.embedded = deploy.isEmbedded();
this.id = deploy.isId();
this.generatedProperty = deploy.getGeneratedProperty();
this.readMethod = deploy.getReadMethod();
this.writeMethod = deploy.getWriteMethod();
this.getter = deploy.getGetter();
this.setter = deploy.getSetter();
this.dbColumn = tableAliasIntern(descriptor, deploy.getDbColumn(), false, null);
this.sqlFormulaJoin = InternString.intern(deploy.getSqlFormulaJoin());
this.sqlFormulaSelect = InternString.intern(deploy.getSqlFormulaSelect());
this.formula = sqlFormulaSelect != null;
this.extraAttributeMap = deploy.getExtraAttributeMap();
this.defaultValue = deploy.getDefaultValue();
this.dbType = deploy.getDbType();
this.scalarType = deploy.getScalarType();
this.lob = isLobType(dbType);
this.propertyType = deploy.getPropertyType();
this.field = deploy.getField();
EntityType et = descriptor == null ? null : descriptor.getEntityType();
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), false, null);
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), dbEncrypted, dbColumn);
this.jsonSerialize = deploy.isExposeSerialize();
this.jsonDeserialize = deploy.isExposeDeserialize();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
if (descriptor != null) {
s = StringHelper.replaceString(s, "${ta}.", "${}");
s = StringHelper.replaceString(s, "${ta}", "${}");
if (dbEncrypted) {
s = dbEncryptFunction.getDecryptSql(s);
String namedParam = ":encryptkey_" + descriptor.getBaseTable() + "___" + dbColumn;
s = StringHelper.replaceString(s, "?", namedParam);
}
}
return InternString.intern(s);
}
/**
* Create a Matching BeanProperty with some attributes overridden.
* <p>
* Primarily for supporting Embedded beans with overridden dbColumn
* mappings.
* </p>
*/
public BeanProperty(BeanProperty source, BeanPropertyOverride override) {
this.descriptor = source.descriptor;
this.name = InternString.intern(source.getName());
this.propertyIndex = source.propertyIndex;
this.indexed = source.isIndexed();
this.indexName = source.getIndexName();
this.dbColumn = InternString.intern(override.getDbColumn());
this.sqlFormulaJoin = InternString.intern(override.getSqlFormulaJoin());
this.sqlFormulaSelect = InternString.intern(override.getSqlFormulaSelect());
this.formula = sqlFormulaSelect != null;
this.fetchEager = source.fetchEager;
this.unidirectionalShadow = source.unidirectionalShadow;
this.discriminator = source.discriminator;
this.localEncrypted = source.isLocalEncrypted();
this.isTransient = source.isTransient();
this.secondaryTable = source.isSecondaryTable();
this.secondaryTableJoin = source.secondaryTableJoin;
this.secondaryTableJoinPrefix = source.secondaryTableJoinPrefix;
this.dbBind = source.getDbBind();
this.dbEncrypted = source.isDbEncrypted();
this.dbEncryptedType = source.getDbEncryptedType();
this.dbEncryptFunction = source.dbEncryptFunction;
this.dbRead = source.isDbRead();
this.dbInsertable = source.isDbInsertable();
this.dbUpdatable = source.isDbUpdatable();
this.nullable = source.isNullable();
this.unique = source.isUnique();
this.naturalKey = source.isNaturalKey();
this.dbLength = source.getDbLength();
this.dbScale = source.getDbScale();
this.dbColumnDefn = InternString.intern(source.getDbColumnDefn());
this.dbConstraintExpression = InternString.intern(source.getDbConstraintExpression());
this.inherited = source.isInherited();
this.owningType = source.owningType;
this.local = owningType.equals(descriptor.getBeanType());
this.version = source.isVersion();
this.embedded = source.isEmbedded();
this.id = source.isId();
this.generatedProperty = source.getGeneratedProperty();
this.readMethod = source.getReadMethod();
this.writeMethod = source.getWriteMethod();
this.getter = source.getter;
this.setter = source.setter;
this.extraAttributeMap = source.extraAttributeMap;
this.defaultValue = source.getDefaultValue();
this.dbType = source.getDbType();
this.scalarType = source.scalarType;
this.lob = isLobType(dbType);
this.propertyType = source.getPropertyType();
this.field = source.getField();
this.elPlaceHolder = override.replace(source.elPlaceHolder, source.dbColumn);
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
this.jsonSerialize = source.jsonSerialize;
this.jsonDeserialize = source.jsonDeserialize;
}
/**
* Initialise the property before returning to client code. Used to
* initialise variables that can't be done in construction due to recursive
* issues.
*/
public void initialise() {
// do nothing for normal BeanProperty
if (!isTransient && scalarType == null) {
String msg = "No ScalarType assigned to " + descriptor.getFullName() + "." + getName();
throw new RuntimeException(msg);
}
}
/**
* Return the order this property appears in the bean.
*/
public int getDeployOrder() {
return deployOrder;
}
/**
* Set the order this property appears in the bean.
*/
public void setDeployOrder(int deployOrder) {
this.deployOrder = deployOrder;
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain,
boolean propertyDeploy) {
throw new PersistenceException("Not valid on scalar bean property " + getFullBeanName());
}
/**
* Return the BeanDescriptor that owns this property.
*/
public BeanDescriptor<?> getBeanDescriptor() {
return descriptor;
}
/**
* Return true is this is a simple scalar property.
*/
public boolean isScalar() {
return true;
}
/**
* Return true if this property is based on a formula.
*/
public boolean isFormula() {
return formula;
}
/**
* Return true if this property maps to the inheritance discriminator column.
*/
public boolean isDiscriminator() {
return discriminator;
}
/**
* Return true if the underlying type is mutable.
*/
public boolean isMutableScalarType() {
if (scalarType == null) {
return false;
}
return scalarType.isMutable();
}
public void copyProperty(EntityBean sourceBean, EntityBean destBean) {
Object value = getValue(sourceBean);
setValue(destBean, value);
}
/**
* Return the encrypt key for the column matching this property.
*/
public EncryptKey getEncryptKey() {
return descriptor.getEncryptKey(this);
}
public String getDecryptProperty() {
return dbEncryptFunction.getDecryptSql(this.getName());
}
public String getDecryptProperty(String propertyName) {
return dbEncryptFunction.getDecryptSql(propertyName);
}
public String getDecryptSql() {
return dbEncryptFunction.getDecryptSql(this.getDbColumn());
}
public String getDecryptSql(String tableAlias) {
return dbEncryptFunction.getDecryptSql(tableAlias + "." + this.getDbColumn());
}
/**
* Add any extra joins required to support this property. Generally a no
* operation except for a OneToOne exported.
*/
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
if (formula && sqlFormulaJoin != null) {
ctx.appendFormulaJoin(sqlFormulaJoin, joinType);
} else if (secondaryTableJoin != null) {
String relativePrefix = ctx.getRelativePrefix(secondaryTableJoinPrefix);
secondaryTableJoin.addJoin(joinType, relativePrefix, ctx);
}
}
/**
* Returns null unless this property is using a secondary table. In that
* case this returns the logical property prefix.
*/
public String getSecondaryTableJoinPrefix() {
return secondaryTableJoinPrefix;
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (formula) {
ctx.appendFormulaSelect(sqlFormulaSelect);
} else if (!isTransient) {
if (secondaryTableJoin != null) {
String relativePrefix = ctx.getRelativePrefix(secondaryTableJoinPrefix);
ctx.pushTableAlias(relativePrefix);
}
if (dbEncrypted) {
String decryptSql = getDecryptSql(ctx.peekTableAlias());
ctx.appendRawColumn(decryptSql);
ctx.addEncryptedProp(this);
} else {
ctx.appendColumn(dbColumn);
}
if (secondaryTableJoin != null) {
ctx.popTableAlias();
}
}
}
public boolean isAssignableFrom(Class<?> type) {
return owningType.isAssignableFrom(type);
}
public Object readSetOwning(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
try {
Object value = scalarType.read(ctx.getDataReader());
if (value == null || bean == null) {
// not setting the value...
} else {
if (owningType.equals(type)) {
setValue(bean, value);
}
}
return value;
} catch (Exception e) {
String msg = "Error readSet on " + descriptor + "." + name;
throw new PersistenceException(msg, e);
}
}
public void loadIgnore(DbReadContext ctx) {
scalarType.loadIgnore(ctx.getDataReader());
}
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
sqlBeanLoad.load(this);
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
if (prefix == null) {
selectChain.add(name);
} else {
selectChain.add(prefix + "." + name);
}
}
public Object read(DbReadContext ctx) throws SQLException {
return scalarType.read(ctx.getDataReader());
}
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
try {
Object value = scalarType.read(ctx.getDataReader());
if (bean == null || (type != null && !owningType.isAssignableFrom(type))) {
// not setting the value...
} else {
setValue(bean, value);
}
return value;
} catch (Exception e) {
String msg = "Error readSet on " + descriptor + "." + name;
throw new PersistenceException(msg, e);
}
}
/**
* Convert the type to the bean type if required.
* <p>
* Generally only used to ensure id properties are converted for
* Query.setId() use.
* </p>
*/
public Object toBeanType(Object value) {
return scalarType.toBeanType(value);
}
@SuppressWarnings("unchecked")
public void bind(DataBind b, Object value) throws SQLException {
scalarType.bind(b, value);
}
public void writeData(DataOutput dataOutput, Object value) throws IOException {
scalarType.writeData(dataOutput, value);
}
public Object readData(DataInput dataInput) throws IOException {
return scalarType.readData(dataInput);
}
public boolean isCascadeValidate() {
return cascadeValidate;
}
/**
* Checks to see if a bean is a reference (will be lazy loaded) or a
* BeanCollection that has not yet been populated.
* <p>
* For base types this returns true.
* </p>
*/
public boolean isValueLoaded(Object value) {
return true;
}
public BeanProperty getBeanProperty() {
return this;
}
public boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
/**
* Return the getter method.
*/
public Method getReadMethod() {
return readMethod;
}
/**
* Return the setter method.
*/
public Method getWriteMethod() {
return writeMethod;
}
/**
* Return true if this object is part of an inheritance hierarchy.
*/
public boolean isInherited() {
return inherited;
}
/**
* Return true is this type is not from a super type.
*/
public boolean isLocal() {
return local;
}
/**
* Set the value of the property without interception or
* PropertyChangeSupport.
*/
public void setValue(EntityBean bean, Object value) {
try {
setter.set(bean, value);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
String msg = "set " + name + " on [" + descriptor + "] arg[" + value + "] type[" + beanType
+ "] threw error";
throw new RuntimeException(msg, ex);
}
}
/**
* Set the value of the property.
*/
public void setValueIntercept(EntityBean bean, Object value) {
try {
setter.setIntercept(bean, value);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
String msg = "setIntercept " + name + " on [" + descriptor + "] arg[" + value + "] type[" + beanType
+ "] threw error";
throw new RuntimeException(msg, ex);
}
}
private static Object[] NO_ARGS = new Object[0];
public Object getCacheDataValue(EntityBean bean) {
return getValue(bean);
}
public void setCacheDataValue(EntityBean bean, Object cacheData) {
setValue(bean, cacheData);
}
/**
* Return the value of the property method.
*/
public Object getValue(EntityBean bean) {
try {
return getter.get(bean);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
String msg = "get " + name + " on [" + descriptor + "] type[" + beanType + "] threw error.";
throw new RuntimeException(msg, ex);
}
}
/**
* Explicitly use reflection to get value.
*/
public Object getValueViaReflection(Object bean) {
try {
return readMethod.invoke(bean, NO_ARGS);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
String msg = "get " + name + " on [" + descriptor + "] type[" + beanType + "] threw error.";
throw new RuntimeException(msg, ex);
}
}
public Object getValueIntercept(EntityBean bean) {
try {
return getter.getIntercept(bean);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
String msg = "getIntercept " + name + " on [" + descriptor + "] type[" + beanType + "] threw error.";
throw new RuntimeException(msg, ex);
}
}
public Object elConvertType(Object value) {
if (value == null) {
return null;
}
return convertToLogicalType(value);
}
public void elSetValue(EntityBean bean, Object value, boolean populate) {
if (bean != null) {
// Not using setValueIntercept at this stage
setValue(bean, value);
}
}
public Object elGetValue(EntityBean bean) {
if (bean == null) {
return null;
}
return getValueIntercept(bean);
}
public Object elGetReference(EntityBean bean) {
throw new RuntimeException("Not expected to call this");
}
/**
* Return the name of the property.
*/
public String getName() {
return name;
}
/**
* Return the position of this property in the enhanced bean.
*/
public int getPropertyIndex() {
return propertyIndex;
}
public String getElName() {
return name;
}
/**
* This is a full ElGetValue.
*/
public boolean isDeployOnly() {
return false;
}
@Override
public boolean containsFormulaWithJoin() {
return formula && sqlFormulaJoin != null;
}
public boolean containsManySince(String sinceProperty) {
return containsMany();
}
public boolean containsMany() {
return false;
}
public Object[] getAssocOneIdValues(EntityBean bean) {
// Returns null as not an AssocOne.
return null;
}
public String getAssocOneIdExpr(String prefix, String operator) {
// Returns null as not an AssocOne.
return null;
}
public String getAssocIdInExpr(String prefix) {
// Returns null as not an AssocOne.
return null;
}
public String getAssocIdInValueExpr(int size) {
// Returns null as not an AssocOne.
return null;
}
public boolean isAssocId() {
// Returns false - override in BeanPropertyAssocOne.
return false;
}
public boolean isAssocProperty() {
// Returns false - override in BeanPropertyAssocOne.
return false;
}
public String getElPlaceholder(boolean encrypted) {
return encrypted ? elPlaceHolderEncrypted : elPlaceHolder;
}
public String getElPrefix() {
return secondaryTableJoinPrefix;
}
/**
* Return the full name of this property.
*/
public String getFullBeanName() {
return descriptor.getFullName() + "." + name;
}
/**
* Return true if the mutable value is considered dirty.
* This is only used for 'mutable' scalar types like hstore etc.
*/
public boolean isDirtyValue(Object value) {
return scalarType.isDirty(value);
}
/**
* Return the scalarType.
*/
public ScalarType<?> getScalarType() {
return scalarType;
}
public StringFormatter getStringFormatter() {
return scalarType;
}
public StringParser getStringParser() {
return scalarType;
}
public boolean isDateTimeCapable() {
return scalarType != null && scalarType.isDateTimeCapable();
}
public int getJdbcType() {
return scalarType == null ? 0 : scalarType.getJdbcType();
}
public Object parseDateTime(long systemTimeMillis) {
return scalarType.parseDateTime(systemTimeMillis);
}
/**
* Return the DB max length (varchar) or precision (decimal).
*/
public int getDbLength() {
return dbLength;
}
/**
* Return the DB scale for numeric columns.
*/
public int getDbScale() {
return dbScale;
}
/**
* Return a specific column DDL definition if specified (otherwise null).
*/
public String getDbColumnDefn() {
return dbColumnDefn;
}
/**
* Return the DB constraint expression (can be null).
* <p>
* For an Enum returns IN expression for the set of Enum values.
* </p>
*/
public String getDbConstraintExpression() {
return dbConstraintExpression;
}
/**
* Return the DB column type definition.
*/
public String renderDbType(DbType dbType) {
if (dbColumnDefn != null) {
return dbColumnDefn;
}
return dbType.renderType(dbLength, dbScale);
}
/**
* Return the bean Field associated with this property.
*/
public Field getField() {
return field;
}
/**
* Return the GeneratedValue. Used to generate update timestamp etc.
*/
public GeneratedProperty getGeneratedProperty() {
return generatedProperty;
}
/**
* Return true if this is the natural key property.
*/
public boolean isNaturalKey() {
return naturalKey;
}
/**
* Return true if this property is mandatory.
*/
public boolean isNullable() {
return nullable;
}
/**
* Return true if DDL Not NULL constraint should be defined for this column
* based on it being a version column or having a generated property.
*/
public boolean isDDLNotNull() {
return isVersion() || (generatedProperty != null && generatedProperty.isDDLNotNullable());
}
/**
* Return true if the DB column should be unique.
*/
public boolean isUnique() {
return unique;
}
/**
* Return true if the property is transient.
*/
public boolean isTransient() {
return isTransient;
}
/**
* Return true if this property is loadable from a resultSet.
*/
public boolean isLoadProperty() {
return !isTransient || formula;
}
/**
* Return true if this is a version column used for concurrency checking.
*/
public boolean isVersion() {
return version;
}
public String getDeployProperty() {
return dbColumn;
}
/**
* The database column name this is mapped to.
*/
public String getDbColumn() {
return dbColumn;
}
/**
* Return the database jdbc data type this is mapped to.
*/
public int getDbType() {
return dbType;
}
/**
* Perform DB to Logical type conversion (if necessary).
*/
public Object convertToLogicalType(Object value) {
if (scalarType != null) {
return scalarType.toBeanType(value);
}
return value;
}
/**
* Return true if by default this property is set to fetch eager.
* Lob's usually default to fetch lazy.
*/
public boolean isFetchEager() {
return fetchEager;
}
/**
* Return true if this is mapped to a Clob Blob LongVarchar or
* LongVarbinary.
*/
public boolean isLob() {
return lob;
}
private boolean isLobType(int type) {
switch (type) {
case Types.CLOB:
return true;
case Types.BLOB:
return true;
case Types.LONGVARBINARY:
return true;
case Types.LONGVARCHAR:
return true;
default:
return false;
}
}
/**
* Return the DB bind parameter. Typically is "?" but different for
* encrypted bind.
*/
public String getDbBind() {
return dbBind;
}
/**
* Returns true if DB encrypted.
*/
public boolean isLocalEncrypted() {
return localEncrypted;
}
/**
* Return true if this property is stored encrypted.
*/
public boolean isDbEncrypted() {
return dbEncrypted;
}
public int getDbEncryptedType() {
return dbEncryptedType;
}
/**
* Return true if this property should be included in an Insert.
*/
public boolean isDbInsertable() {
return dbInsertable;
}
/**
* Return true if this property should be included in an Update.
*/
public boolean isDbUpdatable() {
return dbUpdatable;
}
/**
* Return true if this property is included in database queries.
*/
public boolean isDbRead() {
return dbRead;
}
/**
* Return true if this property is based on a secondary table (not the base
* table).
*/
public boolean isSecondaryTable() {
return secondaryTable;
}
/**
* Return the property type.
*/
public Class<?> getPropertyType() {
return propertyType;
}
/**
* Return true if this is included in the unique id.
*/
public boolean isId() {
return id;
}
/**
* Return true if this is an Embedded property. In this case it shares the
* table and primary key of its owner object.
*/
public boolean isEmbedded() {
return embedded;
}
/**
* Return an extra attribute set on this property.
*/
public String getExtraAttribute(String key) {
return extraAttributeMap.get(key);
}
/**
* Return the default value.
*/
public Object getDefaultValue() {
return defaultValue;
}
public String toString() {
return name;
}
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
writeJson.writeNull(name);
} else {
scalarType.jsonWrite(writeJson.gen(), name, value);
}
}
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
JsonToken event = ctx.nextToken();
if (JsonToken.VALUE_NULL == event) {
setValue(bean, null);
} else {
// expect to read non-null json value
Object objValue = scalarType.jsonRead(ctx, event);
setValue(bean, objValue);
}
}
}