Merge branch 'master' of github.com:ebean-orm/avaje-ebeanorm

This commit is contained in:
rbygrave
2014-07-29 23:44:38 +12:00
8 changed files with 257 additions and 109 deletions
@@ -0,0 +1,24 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for declaring an index on a single column.
*
* @author rvbiljouw
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
*/
String value() default "";
}
@@ -0,0 +1,87 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* A visitor that creates indexes for columns annotated with ColumnIndex
*
* @author rvbiljouw
* @see com.avaje.ebean.annotation.Index
*/
public class CreateIndexVisitor extends AbstractBeanVisitor {
private final IndexPropertyVisitor iv;
public CreateIndexVisitor(DdlGenContext ctx) {
this.iv = new IndexPropertyVisitor(ctx);
}
@Override
public void visitBegin() {
}
@Override
public boolean visitBean(BeanDescriptor<?> descriptor) {
return descriptor.isInheritanceRoot();
}
@Override
public PropertyVisitor visitProperty(BeanProperty p) {
return iv;
}
@Override
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
visitInheritanceProperties(descriptor, iv);
}
@Override
public void visitEnd() {
}
private static final class IndexPropertyVisitor extends BaseTablePropertyVisitor {
private final DdlGenContext ctx;
public IndexPropertyVisitor(DdlGenContext ctx) {
this.ctx = ctx;
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
}
@Override
public void visitScalar(BeanProperty p) {
String baseTable = p.getBeanDescriptor().getBaseTable();
if (p.isIndexed()) {
String indexName = p.getIndexName();
if (indexName.length() == 0) {
indexName = ctx.getDdlSyntax().getIndexName(baseTable, p.getDbColumn(), ctx.incrementIxCount());
}
ctx.write("create index ")
.write(indexName)
.write(" on ")
.write(baseTable)
.write("(")
.write(p.getDbColumn())
.write(");")
.writeNewLine();
}
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
}
}
}
@@ -98,17 +98,17 @@ public class DdlGenerator implements SpiEbeanPlugin {
}
}
protected void writeDrop(String dropFile) {
protected void writeDrop(String dropFile) {
try {
String c = generateDropDdl();
writeFile(dropFile, c);
try {
String c = generateDropDdl();
writeFile(dropFile, c);
} catch (IOException e) {
String msg = "Error generating Drop DDL";
throw new PersistenceException(msg, e);
}
}
} catch (IOException e) {
String msg = "Error generating Drop DDL";
throw new PersistenceException(msg, e);
}
}
protected void writeCreate(String createFile) {
@@ -149,6 +149,9 @@ public class DdlGenerator implements SpiEbeanPlugin {
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(ctx);
VisitorUtil.visit(server, fkeys);
CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
VisitorUtil.visit(server, indexes);
ctx.flush();
createContent = ctx.getContent();
return createContent;
@@ -78,7 +78,7 @@ public class BeanProperty implements ElPropertyValue {
* Flag set if this maps to the inheritance discriminator column
*/
final boolean discriminator;
/**
* Flag to mark the property as embedded. This could be on
* BeanPropertyAssocOne rather than here. Put it here for checking Id type
@@ -92,7 +92,7 @@ public class BeanProperty implements ElPropertyValue {
final boolean version;
final boolean naturalKey;
/**
* Set if this property is nullable.
*/
@@ -136,7 +136,7 @@ public class BeanProperty implements ElPropertyValue {
* True if the property is a Clob, Blob LongVarchar or LongVarbinary.
*/
final boolean lob;
final boolean fetchEager;
final boolean isTransient;
@@ -147,7 +147,7 @@ public class BeanProperty implements ElPropertyValue {
final String name;
final int propertyIndex;
/**
* The reflected field.
*/
@@ -262,6 +262,10 @@ public class BeanProperty implements ElPropertyValue {
final boolean jsonDeserialize;
final boolean indexed;
final String indexName;
public BeanProperty(DeployBeanProperty deploy) {
this(null, null, deploy);
}
@@ -271,7 +275,10 @@ public class BeanProperty implements ElPropertyValue {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
this.indexed = deploy.isIndexed();
this.indexName = deploy.getIndexName();
this.unidirectionalShadow = deploy.isUndirectionalShadow();
this.discriminator = deploy.isDiscriminator();
this.localEncrypted = deploy.isLocalEncrypted();
@@ -326,7 +333,7 @@ public class BeanProperty implements ElPropertyValue {
this.lob = isLobType(dbType);
this.propertyType = deploy.getPropertyType();
this.field = deploy.getField();
EntityType et = descriptor == null ? null : descriptor.getEntityType();
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), false, null);
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), dbEncrypted, dbColumn);
@@ -362,6 +369,9 @@ public class BeanProperty implements ElPropertyValue {
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());
@@ -410,7 +420,7 @@ public class BeanProperty implements ElPropertyValue {
this.lob = isLobType(dbType);
this.propertyType = source.getPropertyType();
this.field = source.getField();
this.elPlaceHolder = override.replace(source.elPlaceHolder, source.dbColumn);
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
@@ -446,7 +456,7 @@ public class BeanProperty implements ElPropertyValue {
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain,
boolean propertyDeploy) {
boolean propertyDeploy) {
throw new PersistenceException("Not valid on scalar bean property " + getFullBeanName());
}
@@ -475,17 +485,17 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this property maps to the inheritance discriminator column.
*/
public boolean isDiscriminator() {
return discriminator;
return discriminator;
}
/**
* Return true if the underlying type is mutable.
*/
public boolean isMutableScalarType() {
if (scalarType == null) {
return false;
}
return scalarType.isMutable();
if (scalarType == null) {
return false;
}
return scalarType.isMutable();
}
public void copyProperty(EntityBean sourceBean, EntityBean destBean) {
@@ -725,14 +735,14 @@ public class BeanProperty implements ElPropertyValue {
private static Object[] NO_ARGS = new Object[0];
public Object getCacheDataValue(EntityBean bean){
return getValue(bean);
public Object getCacheDataValue(EntityBean bean) {
return getValue(bean);
}
public void setCacheDataValue(EntityBean bean, Object cacheData){
setValue(bean, cacheData);
public void setCacheDataValue(EntityBean bean, Object cacheData) {
setValue(bean, cacheData);
}
/**
* Return the value of the property method.
*/
@@ -745,12 +755,12 @@ public class BeanProperty implements ElPropertyValue {
throw new RuntimeException(msg, ex);
}
}
/**
* Explicitly use reflection to get value.
*/
public Object getValueViaReflection(Object bean) {
try {
try {
return readMethod.invoke(bean, NO_ARGS);
} catch (Exception ex) {
String beanType = bean == null ? "null" : bean.getClass().getName();
@@ -805,7 +815,7 @@ public class BeanProperty implements ElPropertyValue {
* Return the position of this property in the enhanced bean.
*/
public int getPropertyIndex() {
return propertyIndex;
return propertyIndex;
}
public String getElName() {
@@ -819,10 +829,10 @@ public class BeanProperty implements ElPropertyValue {
return false;
}
@Override
public boolean containsFormulaWithJoin() {
return formula && sqlFormulaJoin != null;
return formula && sqlFormulaJoin != null;
}
public boolean containsManySince(String sinceProperty) {
@@ -880,12 +890,12 @@ public class BeanProperty implements ElPropertyValue {
/**
* Return true if the mutable value is considered dirty.
* This is only used for 'mutable' scalar types like hstore etc.
* This is only used for 'mutable' scalar types like hstore etc.
*/
public boolean isDirtyValue(Object value) {
return scalarType.isDirty(value);
return scalarType.isDirty(value);
}
/**
* Return the scalarType.
*/
@@ -904,12 +914,12 @@ public class BeanProperty implements ElPropertyValue {
public boolean isDateTimeCapable() {
return scalarType != null && scalarType.isDateTimeCapable();
}
public int getJdbcType() {
return scalarType == null ? 0 : scalarType.getJdbcType();
return scalarType == null ? 0 : scalarType.getJdbcType();
}
public Object parseDateTime(long systemTimeMillis) {
public Object parseDateTime(long systemTimeMillis) {
return scalarType.parseDateTime(systemTimeMillis);
}
@@ -972,10 +982,10 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this is the natural key property.
*/
public boolean isNaturalKey() {
return naturalKey;
return naturalKey;
}
/**
/**
* Return true if this property is mandatory.
*/
public boolean isNullable() {
@@ -1008,9 +1018,9 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this property is loadable from a resultSet.
*/
public boolean isLoadProperty() {
return !isTransient || formula;
return !isTransient || formula;
}
/**
* Return true if this is a version column used for concurrency checking.
*/
@@ -1051,10 +1061,10 @@ public class BeanProperty implements ElPropertyValue {
* Lob's usually default to fetch lazy.
*/
public boolean isFetchEager() {
return fetchEager;
return fetchEager;
}
/**
/**
* Return true if this is mapped to a Clob Blob LongVarchar or
* LongVarbinary.
*/
@@ -1064,17 +1074,17 @@ public class BeanProperty implements ElPropertyValue {
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;
case Types.CLOB:
return true;
case Types.BLOB:
return true;
case Types.LONGVARBINARY:
return true;
case Types.LONGVARCHAR:
return true;
default:
return false;
default:
return false;
}
}
@@ -1175,7 +1185,7 @@ public class BeanProperty implements ElPropertyValue {
@SuppressWarnings("unchecked")
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
if(!jsonSerialize){
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
@@ -1187,15 +1197,15 @@ public class BeanProperty implements ElPropertyValue {
}
public void jsonRead(ReadJsonContext ctx, EntityBean bean) {
if(!jsonDeserialize){
if (!jsonDeserialize) {
return;
}
String jsonValue;
try {
jsonValue = ctx.readScalarValue();
} catch (TextException e){
throw new TextException("Error reading property "+getFullBeanName(), e);
}
String jsonValue;
try {
jsonValue = ctx.readScalarValue();
} catch (TextException e) {
throw new TextException("Error reading property " + getFullBeanName(), e);
}
Object objValue;
if (jsonValue == null) {
objValue = null;
@@ -1204,4 +1214,12 @@ public class BeanProperty implements ElPropertyValue {
}
setValue(bean, objValue);
}
public boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
}
@@ -217,6 +217,9 @@ public class DeployBeanProperty {
private int sortOrder;
private boolean indexed;
private String indexName;
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
this.desc = desc;
this.propertyType = propertyType;
@@ -930,4 +933,19 @@ public class DeployBeanProperty {
return desc.getFullName() + "." + name;
}
public boolean isIndexed() {
return indexed;
}
public void setIndexed(boolean indexed) {
this.indexed = indexed;
}
public String getIndexName() {
return indexName;
}
public void setIndexName(String indexName) {
this.indexName = indexName;
}
}
@@ -4,36 +4,18 @@ import java.sql.Types;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.PersistenceException;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.avaje.ebean.annotation.CreatedTimestamp;
import com.avaje.ebean.annotation.EmbeddedColumns;
import com.avaje.ebean.annotation.Encrypted;
import com.avaje.ebean.annotation.Expose;
import com.avaje.ebean.annotation.Formula;
import com.avaje.ebean.annotation.UpdatedTimestamp;
import com.avaje.ebean.annotation.*;
import com.avaje.ebean.config.EncryptDeploy;
import com.avaje.ebean.config.EncryptDeploy.Mode;
import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
@@ -65,7 +47,7 @@ public class AnnotationFields extends AnnotationParser {
if (GlobalProperties.getBoolean("ebean.lobEagerFetch", false)) {
defaultLobFetchType = FetchType.EAGER;
}
}
}
/**
@@ -104,7 +86,7 @@ public class AnnotationFields extends AnnotationParser {
if (prop.isId() && !prop.isEmbedded()) {
prop.setEmbedded(true);
}
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>)prop);
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>) prop);
}
}
@@ -149,7 +131,7 @@ public class AnnotationFields extends AnnotationParser {
if (id != null) {
readId(id, prop);
}
// determine the JDBC type using Lob/Temporal
// otherwise based on the property Class
Lob lob = get(prop, Lob.class);
@@ -199,9 +181,9 @@ public class AnnotationFields extends AnnotationParser {
if (notNull != null && isNotNullOnAllValidationGroups(notNull.groups())) {
// Not null on all validation groups so enable
// DDL generation of Not Null Constraint
prop.setNullable(false);
prop.setNullable(false);
}
Size size = get(prop, Size.class);
if (size != null) {
if (size.max() < Integer.MAX_VALUE) {
@@ -229,7 +211,7 @@ public class AnnotationFields extends AnnotationParser {
} else {
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType "
+ prop.getFullBeanName());
+ prop.getFullBeanName());
}
}
@@ -246,7 +228,7 @@ public class AnnotationFields extends AnnotationParser {
if (!prop.isTransient()) {
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(),
prop.getDbColumn());
prop.getDbColumn());
if (encryptDeploy == null || encryptDeploy.getMode().equals(Mode.MODE_ANNOTATION)) {
Encrypted encrypted = get(prop, Encrypted.class);
if (encrypted != null) {
@@ -257,6 +239,20 @@ public class AnnotationFields extends AnnotationParser {
}
}
Index index = get(prop, Index.class);
if (index != null) {
if(hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
prop.setIndexed(true);
prop.setIndexName(index.value());
}
}
private boolean hasRelationshipItem(DeployBeanProperty prop) {
return get(prop, OneToMany.class) != null ||
get(prop, ManyToOne.class) != null ||
get(prop, OneToOne.class) != null;
}
/**
@@ -313,7 +309,7 @@ public class AnnotationFields extends AnnotationParser {
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
private ScalarTypeEncryptedWrapper<?> createScalarType(DeployBeanProperty prop, ScalarType<?> st) {
// Use Java Encryptor wrapping the logical scalar type