HHH-6485 Add support for @DiscriminatorFormula

This commit is contained in:
Strong Liu 2011-07-28 00:49:26 +08:00
parent ac7feff33a
commit 236ba1d247
10 changed files with 172 additions and 77 deletions

View File

@ -127,4 +127,20 @@ public final class CollectionHelper {
public static <T> List<T> arrayList(int anticipatedSize) {
return new ArrayList<T>( anticipatedSize );
}
public static boolean isEmpty(Collection collection) {
return collection == null || collection.isEmpty();
}
public static boolean isEmpty(Map map) {
return map == null || map.isEmpty();
}
public static boolean isNotEmpty(Collection collection) {
return !isEmpty( collection );
}
public static boolean isNotEmpty(Map map) {
return !isEmpty( map );
}
}

View File

@ -54,6 +54,7 @@ public class EntityBinding implements AttributeBindingContainer {
private Entity entity;
private TableSpecification primaryTable;
private String primaryTableName;
private Map<String, TableSpecification> secondaryTables = new HashMap<String, TableSpecification>();
private Value<Class<?>> proxyInterfaceType;
@ -143,16 +144,28 @@ public class EntityBinding implements AttributeBindingContainer {
}
public TableSpecification locateTable(String tableName) {
if ( tableName == null ) {
if ( tableName == null || tableName.equals( getPrimaryTableName() ) ) {
return primaryTable;
}
TableSpecification tableSpec = secondaryTables.get( tableName );
if ( tableSpec == null ) {
throw new AssertionFailure( String.format("Unable to find table %s amongst tables %s", tableName, secondaryTables.keySet()) );
throw new AssertionFailure(
String.format(
"Unable to find table %s amongst tables %s",
tableName,
secondaryTables.keySet()
)
);
}
return tableSpec;
}
public String getPrimaryTableName() {
return primaryTableName;
}
public void setPrimaryTableName(String primaryTableName) {
this.primaryTableName = primaryTableName;
}
public void addSecondaryTable(String tableName, TableSpecification table) {
secondaryTables.put( tableName, table );

View File

@ -34,7 +34,7 @@ import org.hibernate.metamodel.relational.state.ColumnRelationalState;
* @author Gavin King
* @author Steve Ebersole
*/
public class Column extends AbstractSimpleValue implements SimpleValue {
public class Column extends AbstractSimpleValue {
private final Identifier columnName;
private boolean nullable;
private boolean unique;

View File

@ -30,7 +30,7 @@ import org.hibernate.dialect.Dialect;
*
* @author Steve Ebersole
*/
public class DerivedValue extends AbstractSimpleValue implements SimpleValue {
public class DerivedValue extends AbstractSimpleValue {
private final String expression;
public DerivedValue(TableSpecification table, int position, String expression) {

View File

@ -35,6 +35,7 @@ import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.source.MetadataSourceProcessor;
@ -97,7 +98,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
index = parseAndUpdateIndex( mappings, index );
}
if ( index.getAnnotations( PseudoJpaDotNames.DEFAULT_DELIMITED_IDENTIFIERS ) != null ) {
if ( CollectionHelper.isNotEmpty( index.getAnnotations( PseudoJpaDotNames.DEFAULT_DELIMITED_IDENTIFIERS ) ) ) {
// todo : this needs to move to AnnotationBindingContext
// what happens right now is that specifying this in an orm.xml causes it to effect all orm.xmls
metadata.setGloballyQuotedIdentifiers( true );

View File

@ -49,7 +49,9 @@ public class DiscriminatorSourceImpl implements DiscriminatorSource {
@Override
public RelationalValueSource getDiscriminatorRelationalValueSource() {
return new ColumnValuesSourceImpl( entityClass.getDiscriminatorColumnValues() );
return entityClass.getDiscriminatorFormula() != null ? entityClass.getDiscriminatorFormula() : new ColumnValuesSourceImpl(
entityClass.getDiscriminatorColumnValues()
);
}
@Override

View File

@ -56,6 +56,7 @@ import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;
import org.hibernate.metamodel.source.annotations.attribute.ColumnValues;
import org.hibernate.metamodel.source.binder.ConstraintSource;
import org.hibernate.metamodel.source.binder.DerivedValueSource;
import org.hibernate.metamodel.source.binder.TableSource;
/**
@ -96,6 +97,7 @@ public class EntityClass extends ConfiguredClass {
private String proxy;
private ColumnValues discriminatorColumnValues;
private DerivedValueSource discriminatorFormula;
private Class<?> discriminatorType;
private String discriminatorMatchValue;
private boolean isDiscriminatorForced = true;
@ -144,6 +146,10 @@ public class EntityClass extends ConfiguredClass {
return discriminatorColumnValues;
}
public DerivedValueSource getDiscriminatorFormula() {
return discriminatorFormula;
}
public Class<?> getDiscriminatorType() {
return discriminatorType;
}
@ -339,10 +345,22 @@ public class EntityClass extends ConfiguredClass {
final AnnotationInstance discriminatorColumnAnnotation = JandexHelper.getSingleAnnotation(
getClassInfo(), JPADotNames.DISCRIMINATOR_COLUMN
);
discriminatorColumnValues = new ColumnValues( discriminatorColumnAnnotation );
discriminatorColumnValues.setNullable( false ); // discriminator column cannot be null
final AnnotationInstance discriminatorFormulaAnnotation = JandexHelper.getSingleAnnotation(
getClassInfo(),
HibernateDotNames.DISCRIMINATOR_FORMULA
);
Class<?> type = String.class; // string is the discriminator default
if ( discriminatorFormulaAnnotation != null ) {
String expression = JandexHelper.getValue( discriminatorFormulaAnnotation, "value", String.class );
discriminatorFormula = new FormulaImpl( getPrimaryTableSource().getExplicitTableName(), expression );
}
discriminatorColumnValues = new ColumnValues( null ); //(stliu) give null here, will populate values below
discriminatorColumnValues.setNullable( false ); // discriminator column cannot be null
if ( discriminatorColumnAnnotation != null ) {
DiscriminatorType discriminatorType = Enum.valueOf(
DiscriminatorType.class, discriminatorColumnAnnotation.value( "discriminatorType" ).asEnum()
);
@ -378,13 +396,14 @@ public class EntityClass extends ConfiguredClass {
Integer.class
)
);
if ( discriminatorColumnAnnotation.value( "columnDefinition" ) != null ) {
discriminatorColumnValues.setColumnDefinition(
discriminatorColumnAnnotation.value( "columnDefinition" )
.asString()
JandexHelper.getValue(
discriminatorColumnAnnotation,
"columnDefinition",
String.class
)
);
}
}
discriminatorType = type;
AnnotationInstance discriminatorOptionsAnnotation = JandexHelper.getSingleAnnotation(
@ -547,58 +566,30 @@ public class EntityClass extends ConfiguredClass {
}
/**
* todo see {@code Binder#createTable}
* @param tableAnnotation a annotation instance, either {@link javax.persistence.Table} or {@link javax.persistence.SecondaryTable}
*
* @return A table source for the specified annotation instance
*/
private TableSource createTableSource(AnnotationInstance tableAnnotation) {
String schema = getLocalBindingContext().getMappingDefaults().getSchemaName();
String catalog = getLocalBindingContext().getMappingDefaults().getCatalogName();
String schema = null;
String catalog = null;
if ( tableAnnotation != null ) {
final AnnotationValue schemaValue = tableAnnotation.value( "schema" );
if ( schemaValue != null ) {
schema = schemaValue.asString();
schema = JandexHelper.getValue( tableAnnotation, "schema", String.class );
catalog = JandexHelper.getValue( tableAnnotation, "catalog", String.class );
}
final AnnotationValue catalogValue = tableAnnotation.value( "catalog" );
if ( catalogValue != null ) {
catalog = catalogValue.asString();
}
}
if ( getLocalBindingContext().isGloballyQuotedIdentifiers() ) {
schema = StringHelper.quote( schema );
catalog = StringHelper.quote( catalog );
}
// process the table name
String tableName = null;
String explicitTableName = null;
String logicalTableName = null;
if ( tableAnnotation != null ) {
explicitTableName = JandexHelper.getValue( tableAnnotation, "name", String.class );
if ( StringHelper.isNotEmpty( explicitTableName ) ) {
tableName = getLocalBindingContext().getNamingStrategy().tableName( explicitTableName );
if ( getLocalBindingContext().isGloballyQuotedIdentifiers() && !Identifier.isQuoted( explicitTableName ) ) {
tableName = StringHelper.quote( tableName );
}
logicalTableName = JandexHelper.getValue( tableAnnotation, "name", String.class );
if ( StringHelper.isNotEmpty( logicalTableName ) ) {
tableName = logicalTableName;
}
createUniqueConstraints( tableAnnotation, tableName );
}
// use the simple table name as default in case there was no table annotation
if ( tableName == null ) {
if ( explicitEntityName == null ) {
tableName = getConfiguredClass().getSimpleName();
}
else {
tableName = explicitEntityName;
}
}
TableSourceImpl tableSourceImpl;
if ( tableAnnotation == null || JPADotNames.TABLE.equals( tableAnnotation.name() ) ) {
// for the main table @Table we use 'null' as logical name
@ -606,24 +597,29 @@ public class EntityClass extends ConfiguredClass {
}
else {
// for secondary tables a name must be specified which is used as logical table name
tableSourceImpl = new TableSourceImpl( schema, catalog, tableName, explicitTableName );
tableSourceImpl = new TableSourceImpl( schema, catalog, tableName, logicalTableName );
}
return tableSourceImpl;
}
private Set<TableSource> createSecondaryTableSources() {
Set<TableSource> secondaryTableSources = new HashSet<TableSource>();
// collect all @secondaryTable annotations
List<AnnotationInstance> secondaryTableAnnotations = new ArrayList<AnnotationInstance>();
secondaryTableAnnotations.add(
JandexHelper.getSingleAnnotation( getClassInfo(), JPADotNames.SECONDARY_TABLE )
);
AnnotationInstance secondaryTables = JandexHelper.getSingleAnnotation(
getClassInfo(),
JPADotNames.SECONDARY_TABLES
);
AnnotationInstance secondaryTable = JandexHelper.getSingleAnnotation(
getClassInfo(),
JPADotNames.SECONDARY_TABLE
);
// collect all @secondaryTable annotations
List<AnnotationInstance> secondaryTableAnnotations = new ArrayList<AnnotationInstance>();
if ( secondaryTable != null ) {
secondaryTableAnnotations.add(
secondaryTable
);
}
if ( secondaryTables != null ) {
secondaryTableAnnotations.addAll(
Arrays.asList(

View File

@ -0,0 +1,26 @@
package org.hibernate.metamodel.source.annotations.entity;
import org.hibernate.metamodel.source.binder.DerivedValueSource;
/**
* @author Strong Liu
*/
public class FormulaImpl implements DerivedValueSource{
private String tableName;
private final String expression;
FormulaImpl(String tableName, String expression) {
this.tableName = tableName;
this.expression = expression;
}
@Override
public String getExpression() {
return expression;
}
@Override
public String getContainingTableName() {
return tableName;
}
}

View File

@ -269,7 +269,7 @@ public class Binder {
final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding );
entityBinding.setPrimaryTable( superEntityBinding.getPrimaryTable() );
entityBinding.setPrimaryTableName( superEntityBinding.getPrimaryTableName() );
bindDiscriminatorValue( entitySource, entityBinding );
return entityBinding;
@ -439,7 +439,9 @@ public class Binder {
}
private void bindPersistentCollection(PluralAttributeSource attributeSource, AttributeBindingContainer attributeBindingContainer) {
final PluralAttribute existingAttribute = attributeBindingContainer.getAttributeContainer().locatePluralAttribute( attributeSource.getName() );
final PluralAttribute existingAttribute = attributeBindingContainer.getAttributeContainer().locatePluralAttribute(
attributeSource.getName()
);
final AbstractPluralAttributeBinding pluralAttributeBinding;
if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) {
@ -471,7 +473,9 @@ public class Binder {
private BasicAttributeBinding doBasicSingularAttributeBindingCreation(
SingularAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer) {
final SingularAttribute existingAttribute = attributeBindingContainer.getAttributeContainer().locateSingularAttribute( attributeSource.getName() );
final SingularAttribute existingAttribute = attributeBindingContainer.getAttributeContainer().locateSingularAttribute(
attributeSource.getName()
);
final SingularAttribute attribute;
if ( existingAttribute != null ) {
attribute = existingAttribute;
@ -641,6 +645,7 @@ public class Binder {
final TableSource tableSource = entitySource.getPrimaryTable();
final Table table = createTable( entityBinding, tableSource );
entityBinding.setPrimaryTable( table );
entityBinding.setPrimaryTableName( table.getTableName().getName() );
}
private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) {
@ -653,12 +658,12 @@ public class Binder {
private Table createTable(EntityBinding entityBinding, TableSource tableSource) {
final String schemaName = StringHelper.isEmpty( tableSource.getExplicitSchemaName() )
? currentBindingContext.getMappingDefaults().getSchemaName()
: currentBindingContext.getMetadataImplementor().getOptions().isGloballyQuotedIdentifiers()
: currentBindingContext.isGloballyQuotedIdentifiers()
? StringHelper.quote( tableSource.getExplicitSchemaName() )
: tableSource.getExplicitSchemaName();
final String catalogName = StringHelper.isEmpty( tableSource.getExplicitCatalogName() )
? currentBindingContext.getMappingDefaults().getCatalogName()
: currentBindingContext.getMetadataImplementor().getOptions().isGloballyQuotedIdentifiers()
: currentBindingContext.isGloballyQuotedIdentifiers()
? StringHelper.quote( tableSource.getExplicitCatalogName() )
: tableSource.getExplicitCatalogName();

View File

@ -23,6 +23,8 @@
*/
package org.hibernate.metamodel.source.annotations.entity;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
@ -30,9 +32,12 @@ import javax.persistence.Id;
import org.junit.Test;
import org.hibernate.annotations.DiscriminatorFormula;
import org.hibernate.annotations.DiscriminatorOptions;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityDiscriminator;
import org.hibernate.metamodel.relational.DerivedValue;
import org.hibernate.metamodel.relational.SimpleValue;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@ -114,6 +119,22 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertFalse( "Wrong default value", discriminator.isInserted() );
}
@Test
@Resources(annotatedClasses = { Fruit.class, Apple.class })
public void testDiscriminatorFormula() {
EntityBinding rootEntityBinding = getEntityBinding( Fruit.class );
assertTrue( rootEntityBinding.isRoot() );
EntityBinding entityBinding = getEntityBinding( Apple.class );
assertFalse( entityBinding.isRoot() );
EntityDiscriminator discriminator = rootEntityBinding.getHierarchyDetails().getEntityDiscriminator();
SimpleValue simpleValue = discriminator.getBoundValue();
assertTrue( simpleValue instanceof DerivedValue);
DerivedValue derivedValue = (DerivedValue)simpleValue;
assertEquals( "case when zik_type is null then 0 else zik_type end", derivedValue.getExpression() );
assertTrue( "Wrong default value", discriminator.isForced() );
assertFalse( "Wrong default value", discriminator.isInserted() );
}
@Entity
class SingleEntity {
@Id
@ -144,6 +165,21 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
@Entity
class Jump extends Base {
}
@Entity
@DiscriminatorColumn(discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorFormula("case when zik_type is null then 0 else zik_type end")
@DiscriminatorOptions(force = true, insert = false)
class Fruit {
@Id
private int id;
}
@Entity
class Apple extends Fruit {
}
}