HHH-6485 Add support for @DiscriminatorFormula
This commit is contained in:
parent
ac7feff33a
commit
236ba1d247
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue