HHH-6498 HHH-6337 : Updates to support single-table inheritance using new metamodel

This commit is contained in:
Gail Badner 2011-08-11 18:00:28 -07:00
parent 2faeb783a4
commit dc7feab061
11 changed files with 700 additions and 140 deletions

View File

@ -83,6 +83,7 @@ import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.context.internal.ThreadLocalSessionContext; import org.hibernate.context.internal.ThreadLocalSessionContext;
import org.hibernate.context.spi.CurrentSessionContext; import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.dialect.function.SQLFunctionRegistry; import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -187,8 +188,8 @@ public final class SessionFactoryImpl
private final transient Map<String, FetchProfile> fetchProfiles; private final transient Map<String, FetchProfile> fetchProfiles;
private final transient Map<String,String> imports; private final transient Map<String,String> imports;
private final transient SessionFactoryServiceRegistry serviceRegistry; private final transient SessionFactoryServiceRegistry serviceRegistry;
private final transient JdbcServices jdbcServices; private final transient JdbcServices jdbcServices;
private final transient Dialect dialect; private final transient Dialect dialect;
private final transient Settings settings; private final transient Settings settings;
private final transient Properties properties; private final transient Properties properties;
private transient SchemaExport schemaExport; private transient SchemaExport schemaExport;
@ -530,9 +531,6 @@ public final class SessionFactoryImpl
SessionFactoryObserver observer) throws HibernateException { SessionFactoryObserver observer) throws HibernateException {
LOG.debug( "Building session factory" ); LOG.debug( "Building session factory" );
// TODO: remove initialization of final variables; just setting to null to make compiler happy
this.sqlFunctionRegistry = null;
this.sessionFactoryOptions = sessionFactoryOptions; this.sessionFactoryOptions = sessionFactoryOptions;
this.properties = createPropertiesFromMap( this.properties = createPropertiesFromMap(
@ -553,6 +551,10 @@ public final class SessionFactoryImpl
this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class ); this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class );
this.dialect = this.jdbcServices.getDialect(); this.dialect = this.jdbcServices.getDialect();
// TODO: get SQL functions from JdbcServices (HHH-6559)
//this.sqlFunctionRegistry = new SQLFunctionRegistry( this.jdbcServices.getSqlFunctions() );
this.sqlFunctionRegistry = new SQLFunctionRegistry( this.dialect, new HashMap<String, SQLFunction>() );
// TODO: get SQL functions from a new service // TODO: get SQL functions from a new service
// this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); // this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() );

View File

@ -53,6 +53,9 @@ import org.hibernate.tuple.entity.EntityTuplizer;
* @author Gail Badner * @author Gail Badner
*/ */
public class EntityBinding implements AttributeBindingContainer { public class EntityBinding implements AttributeBindingContainer {
private static final String NULL_DISCRIMINATOR_MATCH_VALUE = "null";
private static final String NOT_NULL_DISCRIMINATOR_MATCH_VALUE = "not null";
private final EntityBinding superEntityBinding; private final EntityBinding superEntityBinding;
private final List<EntityBinding> subEntityBindings = new ArrayList<EntityBinding>(); private final List<EntityBinding> subEntityBindings = new ArrayList<EntityBinding>();
private final HierarchyDetails hierarchyDetails; private final HierarchyDetails hierarchyDetails;
@ -142,28 +145,70 @@ public class EntityBinding implements AttributeBindingContainer {
return subEntityBindings.size() > 0; return subEntityBindings.size() > 0;
} }
public int getSubEntityBindingSpan() { public int getSubEntityBindingClosureSpan() {
int n = subEntityBindings.size(); int n = subEntityBindings.size();
for ( EntityBinding subEntityBinding : subEntityBindings ) { for ( EntityBinding subEntityBinding : subEntityBindings ) {
n += subEntityBinding.getSubEntityBindingSpan(); n += subEntityBinding.getSubEntityBindingClosureSpan();
} }
return n; return n;
} }
/* used for testing */
public Iterable<EntityBinding> getDirectSubEntityBindings() {
return subEntityBindings;
}
/** /**
* Iterate over subclasses in a special 'order', most derived subclasses * Returns sub-EntityBinding objects in a special 'order', most derived subclasses
* first. * first. Specifically, the sub-entity bindings follow a depth-first,
* post-order traversal
*
* Note that the returned value excludes this entity binding.
*
* @return sub-entity bindings ordered by those entity bindings that are most derived. * @return sub-entity bindings ordered by those entity bindings that are most derived.
*/ */
public Iterable<EntityBinding> getSubEntityBindingClosure() { public Iterable<EntityBinding> getPostOrderSubEntityBindingClosure() {
List<Iterable<EntityBinding>> subclassIterables = // TODO: why this order?
new ArrayList<Iterable<EntityBinding>>( subEntityBindings.size() + 1 ); List<Iterable<EntityBinding>> subclassIterables = new ArrayList<Iterable<EntityBinding>>( subEntityBindings.size() + 1 );
for ( EntityBinding subEntityBinding : subEntityBindings ) { for ( EntityBinding subEntityBinding : subEntityBindings ) {
subclassIterables.add( subEntityBinding.getSubEntityBindingClosure() ); Iterable<EntityBinding> subSubEntityBindings = subEntityBinding.getPostOrderSubEntityBindingClosure();
if ( subSubEntityBindings.iterator().hasNext() ) {
subclassIterables.add( subSubEntityBindings );
}
}
if ( ! subEntityBindings.isEmpty() ) {
subclassIterables.add( subEntityBindings );
} }
subclassIterables.add( subEntityBindings );
return new JoinedIterable<EntityBinding>( subclassIterables ); return new JoinedIterable<EntityBinding>( subclassIterables );
} }
/**
* Returns sub-EntityBinding ordered as a depth-first,
* pre-order traversal (a subclass precedes its own subclasses).
*
* Note that the returned value specifically excludes this entity binding.
*
* @return sub-entity bindings ordered as a depth-first,
* pre-order traversal
*/
public Iterable<EntityBinding> getPreOrderSubEntityBindingClosure() {
return getPreOrderSubEntityBindingClosure( false );
}
private Iterable<EntityBinding> getPreOrderSubEntityBindingClosure(boolean includeThis) {
List<Iterable<EntityBinding>> iterables = new ArrayList<Iterable<EntityBinding>>();
if ( includeThis ) {
iterables.add( java.util.Collections.singletonList( this ) );
}
for ( EntityBinding subEntityBinding : subEntityBindings ) {
Iterable<EntityBinding> subSubEntityBindingClosure = subEntityBinding.getPreOrderSubEntityBindingClosure( true );
if ( subSubEntityBindingClosure.iterator().hasNext() ) {
iterables.add( subSubEntityBindingClosure );
}
}
return new JoinedIterable<EntityBinding>( iterables );
}
public Entity getEntity() { public Entity getEntity() {
return entity; return entity;
} }
@ -212,6 +257,14 @@ public class EntityBinding implements AttributeBindingContainer {
return getHierarchyDetails().getVersioningAttributeBinding() != null; return getHierarchyDetails().getVersioningAttributeBinding() != null;
} }
public boolean isDiscriminatorMatchValueNull() {
return NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue );
}
public boolean isDiscriminatorMatchValueNotNull() {
return NOT_NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue );
}
public String getDiscriminatorMatchValue() { public String getDiscriminatorMatchValue() {
return discriminatorMatchValue; return discriminatorMatchValue;
} }
@ -521,4 +574,21 @@ public class EntityBinding implements AttributeBindingContainer {
} }
return iterable; return iterable;
} }
/**
* Gets the attribute bindings for this EntityBinding and all of its
* sub-EntityBinding, starting from the root of the hierarchy; includes
* the identifier and attribute bindings defined as part of a join.
* @return
*/
public Iterable<AttributeBinding> getSubEntityAttributeBindingClosure() {
List<Iterable<AttributeBinding>> iterables = new ArrayList<Iterable<AttributeBinding>>();
iterables.add( getAttributeBindingClosure() );
for ( EntityBinding subEntityBinding : getPreOrderSubEntityBindingClosure() ) {
// only add attribute bindings declared for the subEntityBinding
iterables.add( subEntityBinding.attributeBindings() );
// TODO: if EntityBinding.attributeBindings() excludes joined attributes, then they need to be added here
}
return new JoinedIterable<AttributeBinding>( iterables );
}
} }

View File

@ -768,7 +768,6 @@ public abstract class AbstractEntityPersister
final EntityBinding entityBinding, final EntityBinding entityBinding,
final EntityRegionAccessStrategy cacheAccessStrategy, final EntityRegionAccessStrategy cacheAccessStrategy,
final SessionFactoryImplementor factory) throws HibernateException { final SessionFactoryImplementor factory) throws HibernateException {
// TODO: Implement! Initializing final fields to make compiler happy
this.factory = factory; this.factory = factory;
this.cacheAccessStrategy = cacheAccessStrategy; this.cacheAccessStrategy = cacheAccessStrategy;
this.isLazyPropertiesCacheable = this.isLazyPropertiesCacheable =
@ -812,8 +811,6 @@ public abstract class AbstractEntityPersister
rootTableKeyColumnReaders[i] = col.getReadFragment(); rootTableKeyColumnReaders[i] = col.getReadFragment();
rootTableKeyColumnReaderTemplates[i] = getTemplateFromString( col.getReadFragment(), factory ); rootTableKeyColumnReaderTemplates[i] = getTemplateFromString( col.getReadFragment(), factory );
} }
// TODO: Fix when HHH-6337 is fixed; for now assume entityBinding is the root
// identifierAliases[i] = col.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getPrimaryTable() );
identifierAliases[i] = col.getAlias( factory.getDialect() ); identifierAliases[i] = col.getAlias( factory.getDialect() );
i++; i++;
} }
@ -915,8 +912,8 @@ public abstract class AbstractEntityPersister
propertyColumnWriters[i] = colWriters; propertyColumnWriters[i] = colWriters;
propertyColumnAliases[i] = colAliases; propertyColumnAliases[i] = colAliases;
propertyColumnUpdateable[i] = propertyColumnInsertability; propertyColumnUpdateable[i] = propertyColumnUpdatability;
propertyColumnInsertable[i] = propertyColumnUpdatability; propertyColumnInsertable[i] = propertyColumnInsertability;
if ( lazyAvailable && singularAttributeBinding.isLazy() ) { if ( lazyAvailable && singularAttributeBinding.isLazy() ) {
lazyProperties.add( singularAttributeBinding.getAttribute().getName() ); lazyProperties.add( singularAttributeBinding.getAttribute().getName() );
@ -967,9 +964,7 @@ public abstract class AbstractEntityPersister
List<Boolean> columnSelectables = new ArrayList<Boolean>(); List<Boolean> columnSelectables = new ArrayList<Boolean>();
List<Boolean> propNullables = new ArrayList<Boolean>(); List<Boolean> propNullables = new ArrayList<Boolean>();
// TODO: fix this when EntityBinding.getSubclassAttributeBindingClosure() is working for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) {
// for ( AttributeBinding prop : entityBinding.getSubclassAttributeBindingClosure() ) {
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) { if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) {
// entity identifier is not considered a "normal" property // entity identifier is not considered a "normal" property
continue; continue;

View File

@ -466,8 +466,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
isNullableTable = new boolean[joinSpan]; isNullableTable = new boolean[joinSpan];
keyColumnNames = new String[joinSpan][]; keyColumnNames = new String[joinSpan][];
// TODO: fix when EntityBinhding.getRootEntityBinding() exists (HHH-6337)
//final Table table = entityBinding.getRootEntityBinding().getPrimaryTable();
final TableSpecification table = entityBinding.getPrimaryTable(); final TableSpecification table = entityBinding.getPrimaryTable();
qualifiedTableNames[0] = table.getQualifiedName( factory.getDialect() ); qualifiedTableNames[0] = table.getQualifiedName( factory.getDialect() );
isInverseTable[0] = false; isInverseTable[0] = false;
@ -538,15 +536,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// DISCRIMINATOR // DISCRIMINATOR
// TODO: fix this when can get subclass info from EntityBinding (HHH-6337)
// for now set hasSubclasses to false
//hasSubclasses = entityBinding.hasSubclasses();
boolean hasSubclasses = false;
//polymorphic = ! entityBinding.isRoot() || entityBinding.hasSubclasses();
boolean isPolymorphic = ! entityBinding.isRoot() || hasSubclasses;
final Object discriminatorValue; final Object discriminatorValue;
if ( isPolymorphic ) { if ( entityBinding.isPolymorphic() ) {
SimpleValue discriminatorRelationalValue = entityBinding.getHierarchyDetails().getEntityDiscriminator().getBoundValue(); SimpleValue discriminatorRelationalValue = entityBinding.getHierarchyDetails().getEntityDiscriminator().getBoundValue();
if ( discriminatorRelationalValue == null ) { if ( discriminatorRelationalValue == null ) {
throw new MappingException("discriminator mapping required for single table polymorphic persistence"); throw new MappingException("discriminator mapping required for single table polymorphic persistence");
@ -569,9 +560,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) : column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) :
column.getReadFragment(); column.getReadFragment();
discriminatorColumnReaderTemplate = getTemplateFromColumn( column, factory ); discriminatorColumnReaderTemplate = getTemplateFromColumn( column, factory );
// TODO: fix this when EntityBinding.getRootEntityBinding() is implemented;
// for now, assume entityBinding is the root
//discriminatorAlias = column.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getPrimaryTable );
discriminatorAlias = column.getAlias( factory.getDialect() ); discriminatorAlias = column.getAlias( factory.getDialect() );
discriminatorFormula = null; discriminatorFormula = null;
discriminatorFormulaTemplate = null; discriminatorFormulaTemplate = null;
@ -648,9 +636,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
ArrayList formulaJoinedNumbers = new ArrayList(); ArrayList formulaJoinedNumbers = new ArrayList();
ArrayList propertyJoinNumbers = new ArrayList(); ArrayList propertyJoinNumbers = new ArrayList();
// TODO: fix when subclasses are working (HHH-6337) for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) {
//for ( AttributeBinding prop : entityBinding.getSubclassAttributeBindingClosure() ) {
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( ! attributeBinding.getAttribute().isSingular() ) { if ( ! attributeBinding.getAttribute().isSingular() ) {
continue; continue;
} }
@ -680,18 +666,41 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers); subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers);
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers); subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers);
// TODO; fix when subclasses are working (HHH-6337) int subclassSpan = entityBinding.getSubEntityBindingClosureSpan() + 1;
//int subclassSpan = entityBinding.getSubclassSpan() + 1;
int subclassSpan = 1;
subclassClosure = new String[subclassSpan]; subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName(); subclassClosure[0] = getEntityName();
if ( isPolymorphic ) { if ( entityBinding.isPolymorphic() ) {
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() ); subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
} }
// SUBCLASSES // SUBCLASSES
if ( entityBinding.isPolymorphic() ) {
// TODO; fix when subclasses are working (HHH-6337) int k=1;
for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) {
subclassClosure[k++] = subEntityBinding.getEntity().getName();
if ( subEntityBinding.isDiscriminatorMatchValueNull() ) {
subclassesByDiscriminatorValue.put( NULL_DISCRIMINATOR, subEntityBinding.getEntity().getName() );
}
else if ( subEntityBinding.isDiscriminatorMatchValueNotNull() ) {
subclassesByDiscriminatorValue.put( NOT_NULL_DISCRIMINATOR, subEntityBinding.getEntity().getName() );
}
else {
try {
DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
subclassesByDiscriminatorValue.put(
dtype.stringToObject( subEntityBinding.getDiscriminatorMatchValue() ),
subEntityBinding.getEntity().getName()
);
}
catch (ClassCastException cce) {
throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
}
catch (Exception e) {
throw new MappingException("Error parsing discriminator value", e);
}
}
}
}
initLockers(); initLockers();

View File

@ -29,6 +29,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
@ -58,14 +59,9 @@ public class DynamicMapInstantiator implements Instantiator {
public DynamicMapInstantiator(EntityBinding mappingInfo) { public DynamicMapInstantiator(EntityBinding mappingInfo) {
this.entityName = mappingInfo.getEntity().getName(); this.entityName = mappingInfo.getEntity().getName();
isInstanceEntityNames.add( entityName ); isInstanceEntityNames.add( entityName );
// TODO: fix this when can get subclass info from EntityBinding (HHH-6337) for ( EntityBinding subEntityBinding : mappingInfo.getPostOrderSubEntityBindingClosure() ) {
//if ( mappingInfo.hasSubclasses() ) { isInstanceEntityNames.add( subEntityBinding.getEntity().getName() );
// Iterator itr = mappingInfo.getSubclassClosureIterator(); }
// while ( itr.hasNext() ) {
// final PersistentClass subclassInfo = ( PersistentClass ) itr.next();
// isInstanceEntityNames.add( subclassInfo.getEntityName() );
// }
//}
} }
public final Object instantiate(Serializable id) { public final Object instantiate(Serializable id) {

View File

@ -360,9 +360,7 @@ public class EntityMetamodel implements Serializable {
name = entityBinding.getEntity().getName(); name = entityBinding.getEntity().getName();
// TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding rootName = entityBinding.getHierarchyDetails().getRootEntityBinding().getEntity().getName();
//rootName = entityBinding.getRootEntityBinding().getName();
rootName = name;
entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne( name ); entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne( name );
identifierProperty = PropertyFactory.buildIdentifierProperty( identifierProperty = PropertyFactory.buildIdentifierProperty(
@ -386,7 +384,6 @@ public class EntityMetamodel implements Serializable {
boolean hasLazy = false; boolean hasLazy = false;
// TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding // TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding
//BasicAttributeBinding rootEntityIdentifier = entityBinding.getRootEntityBinding().getEntityIdentifier().getValueBinding();
BasicAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(); BasicAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding();
// entityBinding.getAttributeClosureSpan() includes the identifier binding; // entityBinding.getAttributeClosureSpan() includes the identifier binding;
// "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null // "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null
@ -540,13 +537,8 @@ public class EntityMetamodel implements Serializable {
dynamicUpdate = entityBinding.isDynamicUpdate(); dynamicUpdate = entityBinding.isDynamicUpdate();
dynamicInsert = entityBinding.isDynamicInsert(); dynamicInsert = entityBinding.isDynamicInsert();
// TODO: fix this when can get subclass info from EntityBinding (HHH-6337) hasSubclasses = entityBinding.hasSubEntityBindings();
// for now set hasSubclasses to false polymorphic = entityBinding.isPolymorphic();
//hasSubclasses = entityBinding.hasSubclasses();
hasSubclasses = false;
//polymorphic = ! entityBinding.isRoot() || entityBinding.hasSubclasses();
polymorphic = ! entityBinding.isRoot() || hasSubclasses;
explicitPolymorphism = entityBinding.getHierarchyDetails().isExplicitPolymorphism(); explicitPolymorphism = entityBinding.getHierarchyDetails().isExplicitPolymorphism();
inherited = ! entityBinding.isRoot(); inherited = ! entityBinding.isRoot();
@ -568,24 +560,17 @@ public class EntityMetamodel implements Serializable {
hasCollections = foundCollection; hasCollections = foundCollection;
hasMutableProperties = foundMutable; hasMutableProperties = foundMutable;
// TODO: fix this when can get subclass info from EntityBinding (HHH-6337) for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) {
// TODO: uncomment when it's possible to get subclasses from an EntityBinding subclassEntityNames.add( subEntityBinding.getEntity().getName() );
//iter = entityBinding.getSubclassIterator(); if ( subEntityBinding.getEntity().getClassReference() != null ) {
//while ( iter.hasNext() ) { entityNameByInheritenceClassMap.put(
// subclassEntityNames.add( ( (PersistentClass) iter.next() ).getEntityName() ); subEntityBinding.getEntity().getClassReference(),
//} subEntityBinding.getEntity().getName() );
}
}
subclassEntityNames.add( name ); subclassEntityNames.add( name );
if ( mappedClass != null ) { if ( mappedClass != null ) {
entityNameByInheritenceClassMap.put( mappedClass, name ); entityNameByInheritenceClassMap.put( mappedClass, name );
// TODO: uncomment when it's possible to get subclasses from an EntityBinding
// iter = entityBinding.getSubclassIterator();
// while ( iter.hasNext() ) {
// final EntityBinding subclassEntityBinding = ( EntityBinding ) iter.next();
// entityNameByInheritenceClassMap.put(
// subclassEntityBinding.getEntity().getPojoEntitySpecifics().getEntityClass(),
// subclassEntityBinding.getEntity().getName() );
// }
} }
entityMode = hasPojoRepresentation ? EntityMode.POJO : EntityMode.MAP; entityMode = hasPojoRepresentation ? EntityMode.POJO : EntityMode.MAP;

View File

@ -278,21 +278,18 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
proxyInterfaces.add( mappedClass ); proxyInterfaces.add( mappedClass );
} }
// TODO: fix when it's possible to get subclasses from an EntityBinding for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) {
//Iterator subclasses = entityBinding.getSubclassIterator(); final Class subclassProxy = subEntityBinding.getProxyInterfaceType().getValue();
//while ( subclasses.hasNext() ) { final Class subclassClass = subEntityBinding.getClassReference();
// final Subclass subclass = ( Subclass ) subclasses.next(); if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) {
// final Class subclassProxy = subclass.getProxyInterface(); if ( ! subclassProxy.isInterface() ) {
// final Class subclassClass = subclass.getMappedClass(); throw new MappingException(
// if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) { "proxy must be either an interface, or the class itself: " + subEntityBinding.getEntity().getName()
// if ( !subclassProxy.isInterface() ) { );
// throw new MappingException( }
// "proxy must be either an interface, or the class itself: " + subclass.getEntityName() proxyInterfaces.add( subclassProxy );
// ); }
// } }
// proxyInterfaces.add( subclassProxy );
// }
//}
for ( AttributeBinding property : entityBinding.attributeBindings() ) { for ( AttributeBinding property : entityBinding.attributeBindings() ) {
Method method = getGetter( property ).getMethod(); Method method = getGetter( property ).getMethod();

View File

@ -23,8 +23,10 @@
*/ */
package org.hibernate.metamodel.source.annotations.entity; package org.hibernate.metamodel.source.annotations.entity;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorType;
@ -121,14 +123,31 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertSame( noInheritanceEntityBinding, getRootEntityBinding( SingleEntity.class ) ); assertSame( noInheritanceEntityBinding, getRootEntityBinding( SingleEntity.class ) );
assertFalse( noInheritanceEntityBinding.isPolymorphic() ); assertFalse( noInheritanceEntityBinding.isPolymorphic() );
assertFalse( noInheritanceEntityBinding.hasSubEntityBindings() ); assertFalse( noInheritanceEntityBinding.hasSubEntityBindings() );
assertEquals( 0, noInheritanceEntityBinding.getSubEntityBindingSpan() ); assertEquals( 0, noInheritanceEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( noInheritanceEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); assertFalse( noInheritanceEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertEquals( 1, noInheritanceEntityBinding.getAttributeBindingClosureSpan() ); assertFalse( noInheritanceEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
for ( AttributeBinding attributeBinding : noInheritanceEntityBinding.getAttributeBindingClosure() ) { Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
if ( attributeBinding == noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) { for ( AttributeBinding attributeBinding : noInheritanceEntityBinding.attributeBindings() ) {
continue; assertTrue( directAttributeBindings.add( attributeBinding ) );
}
} }
assertEquals( 1, directAttributeBindings.size() );
assertSame(
noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(),
directAttributeBindings.iterator().next()
);
assertEquals( 1, noInheritanceEntityBinding.getAttributeBindingClosureSpan() );
Iterator<AttributeBinding> iterator = noInheritanceEntityBinding.attributeBindings().iterator();
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
iterator = noInheritanceEntityBinding.getAttributeBindingClosure().iterator();
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
iterator = noInheritanceEntityBinding.getSubEntityAttributeBindingClosure().iterator();
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
} }
@Test @Test
@ -151,22 +170,110 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertSame( rootEntityBinding, getRootEntityBinding( RootOfSingleTableInheritance.class ) ); assertSame( rootEntityBinding, getRootEntityBinding( RootOfSingleTableInheritance.class ) );
assertTrue( rootEntityBinding.isPolymorphic() ); assertTrue( rootEntityBinding.isPolymorphic() );
assertTrue( rootEntityBinding.hasSubEntityBindings() ); assertTrue( rootEntityBinding.hasSubEntityBindings() );
assertEquals( 3, rootEntityBinding.getSubEntityBindingSpan() ); Iterator<EntityBinding> directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator();
Set<EntityBinding> subEntityBindings = new HashSet<EntityBinding>( ); assertTrue( directEntityBindingIterator.hasNext() );
for ( EntityBinding subEntityBinding : rootEntityBinding.getSubEntityBindingClosure() ) { EntityBinding directSubEntityBinding1 = directEntityBindingIterator.next();
subEntityBindings.add( subEntityBinding ); assertTrue( directEntityBindingIterator.hasNext() );
EntityBinding directSubEntityBinding2 = directEntityBindingIterator.next();
assertFalse( directEntityBindingIterator.hasNext() );
boolean isSubclassEntityBindingFirst = directSubEntityBinding1 == subclassEntityBinding;
if ( isSubclassEntityBindingFirst ) {
assertSame( otherSubclassEntityBinding, directSubEntityBinding2 );
} }
assertEquals( 3, subEntityBindings.size() ); else {
assertTrue( subEntityBindings.contains( subclassEntityBinding ) ); assertSame( otherSubclassEntityBinding, directSubEntityBinding1 );
assertTrue( subEntityBindings.contains( otherSubclassEntityBinding ) ); assertSame( subclassEntityBinding, directSubEntityBinding2 );
assertTrue( subEntityBindings.contains( subclassOfSubclassEntityBinding ) ); }
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : rootEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
}
assertEquals( 1, directAttributeBindings.size() );
assertTrue( directAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertEquals( 1, rootEntityBinding.getAttributeBindingClosureSpan() ); assertEquals( 1, rootEntityBinding.getAttributeBindingClosureSpan() );
Set<String> attributeNames = new HashSet<String>(); Set<AttributeBinding> attributeBindingClosure = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : rootEntityBinding.getAttributeBindingClosure() ) { for ( AttributeBinding attributeBinding : rootEntityBinding.getAttributeBindingClosure() ) {
attributeNames.add( attributeBinding.getAttribute().getName() ); assertTrue( attributeBindingClosure.add( attributeBinding ) );
} }
assertEquals( 1, attributeNames.size() ); assertEquals( 1, attributeBindingClosure.size() );
assertTrue( attributeNames.contains( "id" ) ); assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : rootEntityBinding.getSubEntityAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 4, subAttributeBindings.size() );
assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
assertTrue( subAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) );
}
@Test
@Resources(annotatedClasses = {
SubclassOfSingleTableInheritance.class,
SingleEntity.class,
RootOfSingleTableInheritance.class,
OtherSubclassOfSingleTableInheritance.class,
SubclassOfSubclassOfSingleTableInheritance.class
})
public void testPreOrderRootSubEntityClosure() {
EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class );
EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class );
EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class );
EntityBinding subclassOfSubclassEntityBinding = getEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class );
// need to figure out the order of direct subclasses, since it's indeterminate
Iterator<EntityBinding> directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator();
boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next();
assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> subEntityBindingIterator = rootEntityBinding.getPreOrderSubEntityBindingClosure().iterator();
assertTrue( subEntityBindingIterator.hasNext() );
if ( isSubclassEntityBindingFirst ) {
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
}
else {
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
}
assertFalse( subEntityBindingIterator.hasNext() );
}
@Test
@Resources(annotatedClasses = {
SubclassOfSingleTableInheritance.class,
SingleEntity.class,
RootOfSingleTableInheritance.class,
OtherSubclassOfSingleTableInheritance.class,
SubclassOfSubclassOfSingleTableInheritance.class
})
public void testPostOrderRootSubEntityClosure() {
EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class );
EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class );
EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class );
EntityBinding subclassOfSubclassEntityBinding = getEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class );
// need to figure out the order of direct subclasses, since it's indeterminate
Iterator<EntityBinding> directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator();
boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next();
assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> subEntityBindingIterator = rootEntityBinding.getPostOrderSubEntityBindingClosure().iterator();
assertTrue( subEntityBindingIterator.hasNext() );
if ( isSubclassEntityBindingFirst ) {
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
}
else {
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
}
assertFalse( subEntityBindingIterator.hasNext() );
} }
@Test @Test
@ -189,16 +296,30 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertSame( rootEntityBinding, getRootEntityBinding( OtherSubclassOfSingleTableInheritance.class) ); assertSame( rootEntityBinding, getRootEntityBinding( OtherSubclassOfSingleTableInheritance.class) );
assertTrue( otherSubclassEntityBinding.isPolymorphic() ); assertTrue( otherSubclassEntityBinding.isPolymorphic() );
assertFalse( otherSubclassEntityBinding.hasSubEntityBindings() ); assertFalse( otherSubclassEntityBinding.hasSubEntityBindings() );
assertEquals( 0, otherSubclassEntityBinding.getSubEntityBindingSpan() ); assertEquals( 0, otherSubclassEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( otherSubclassEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); assertFalse( otherSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertEquals( 2, otherSubclassEntityBinding.getAttributeBindingClosureSpan() ); assertFalse( otherSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
Set<String> attributeNames = new HashSet<String>(); Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.getAttributeBindingClosure() ) { for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.attributeBindings() ) {
attributeNames.add( attributeBinding.getAttribute().getName() ); assertTrue( directAttributeBindings.add( attributeBinding ) );
} }
assertEquals( 2, attributeNames.size() ); assertEquals( 1, directAttributeBindings.size() );
assertTrue( attributeNames.contains( "id" ) ); assertTrue( directAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) );
assertTrue( attributeNames.contains( "otherName" ) ); assertEquals( 2, otherSubclassEntityBinding.getAttributeBindingClosureSpan() );
Set<AttributeBinding> attributeBindingClosure = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.getAttributeBindingClosure() ) {
assertTrue( attributeBindingClosure.add( attributeBinding ) );
}
assertEquals(2, attributeBindingClosure.size() );
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( attributeBindingClosure.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : otherSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 2, subAttributeBindings.size() );
assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( subAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) );
} }
@Test @Test
@ -221,19 +342,37 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSingleTableInheritance.class ) ); assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSingleTableInheritance.class ) );
assertTrue( subclassEntityBinding.isPolymorphic() ); assertTrue( subclassEntityBinding.isPolymorphic() );
assertTrue( subclassEntityBinding.hasSubEntityBindings() ); assertTrue( subclassEntityBinding.hasSubEntityBindings() );
assertEquals( 1, subclassEntityBinding.getSubEntityBindingSpan() ); assertEquals( 1, subclassEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> itSubEntityBindings = subclassEntityBinding.getSubEntityBindingClosure().iterator(); Iterator<EntityBinding> itSubEntityBindings = subclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator();
assertTrue( itSubEntityBindings.hasNext() ); assertTrue( itSubEntityBindings.hasNext() );
assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() ); assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() );
assertFalse( itSubEntityBindings.hasNext() ); assertFalse( itSubEntityBindings.hasNext() );
assertEquals( 2, subclassEntityBinding.getAttributeBindingClosureSpan() ); itSubEntityBindings = subclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator();
Set<String> attributeNames = new HashSet<String>(); assertTrue( itSubEntityBindings.hasNext() );
for ( AttributeBinding attributeBinding : subclassEntityBinding.getAttributeBindingClosure() ) { assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() );
attributeNames.add( attributeBinding.getAttribute().getName() ); assertFalse( itSubEntityBindings.hasNext() );
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
} }
assertEquals( 2, attributeNames.size() ); assertEquals( 1, directAttributeBindings.size() );
assertTrue( attributeNames.contains( "id" ) ); assertTrue( directAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( attributeNames.contains( "name" ) ); assertEquals( 2, subclassEntityBinding.getAttributeBindingClosureSpan() );
Set<AttributeBinding> attributeBindingClosure = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassEntityBinding.getAttributeBindingClosure() ) {
assertTrue( attributeBindingClosure.add( attributeBinding ) );
}
assertEquals( 2, attributeBindingClosure.size() );
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : subclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 3, subAttributeBindings.size() );
assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
} }
@Test @Test
@ -256,17 +395,32 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class ) ); assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class ) );
assertTrue( subclassOfSubclassEntityBinding.isPolymorphic() ); assertTrue( subclassOfSubclassEntityBinding.isPolymorphic() );
assertFalse( subclassOfSubclassEntityBinding.hasSubEntityBindings() ); assertFalse( subclassOfSubclassEntityBinding.hasSubEntityBindings() );
assertEquals( 0, subclassOfSubclassEntityBinding.getSubEntityBindingSpan() ); assertEquals( 0, subclassOfSubclassEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( subclassOfSubclassEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); assertFalse( subclassOfSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertEquals( 3, subclassOfSubclassEntityBinding.getAttributeBindingClosureSpan() ); assertFalse( subclassOfSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
Set<String> attributeNames = new HashSet<String>(); Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.getAttributeBindingClosure() ) { for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.attributeBindings() ) {
attributeNames.add( attributeBinding.getAttribute().getName() ); assertTrue( directAttributeBindings.add( attributeBinding ) );
} }
assertEquals( 3, attributeNames.size() ); assertEquals( 1, directAttributeBindings.size() );
assertTrue( attributeNames.contains( "id" ) ); assertTrue( directAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
assertTrue( attributeNames.contains( "name" ) ); assertEquals( 3, subclassOfSubclassEntityBinding.getAttributeBindingClosureSpan() );
assertTrue( attributeNames.contains( "otherOtherName" ) ); Set<AttributeBinding> attributeBindingClosure = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.getAttributeBindingClosure() ) {
assertTrue( attributeBindingClosure.add( attributeBinding ) );
}
assertEquals( 3, attributeBindingClosure.size() );
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( attributeBindingClosure.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : subclassOfSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 3, subAttributeBindings.size() );
assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
} }
@Test @Test

View File

@ -0,0 +1,21 @@
//$Id: Employee.java 4373 2004-08-18 09:18:34Z oneovthafew $
package org.hibernate.test.discriminator;
import java.math.BigDecimal;
/**
* @author Gail Badner
*/
public class PartTimeEmployee extends Employee {
private String title;
private BigDecimal salary;
private Employee manager;
private int percent;
public int getPercent() {
return percent;
}
public void setPercent(int percent) {
this.percent = percent;
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<hibernate-mapping package="org.hibernate.test.discriminator" default-access="field"
xmlns="http://www.hibernate.org/xsd/hibernate-mapping"
xsi:schemaLocation="http://www.hibernate.org/xsd/hibernate-mapping hibernate-mapping-4.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="org.hibernate.test.discriminator"
default-access="field">
-->
<!--
This mapping demonstrates a simple table-per-hierarchy mapping strategy;
each subclass has simple properties
-->
<class name="Person"
discriminator-value="P">
<id name="id"
column="person_id"
unsaved-value="0">
<generator class="assigned"/>
</id>
<discriminator column="TYPE" type="character"/>
<property name="name"
not-null="true"
length="80"/>
<property name="sex"
not-null="true"
update="false"/>
<subclass name="Employee"
discriminator-value="E">
<property name="title" length="20"/>
<property name="salary" />
<!-- commented out until HHH-6551 is fixed
<subclass name="PartTimeEmployee" discriminator-value="M">
<property name="percent"/>
</subclass>
-->
</subclass>
<subclass name="Customer"
discriminator-value="C">
<property name="comments"/>
</subclass>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,271 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2006-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.discriminator;
import java.math.BigDecimal;
import java.util.List;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gavin King
*/
public class SimpleInheritanceTest extends BaseCoreFunctionalTestCase {
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( USE_NEW_METADATA_MAPPINGS, "true");
}
@Override
public String[] getMappings() {
return new String[] { "discriminator/SimpleInheritance.hbm.xml" };
}
@Test
public void testDiscriminatorSubclass() {
Session s = openSession();
Transaction t = s.beginTransaction();
Employee mark = new Employee();
mark.setId( 1 );
mark.setName( "Mark" );
mark.setTitle( "internal sales" );
mark.setSex( 'M' );
Customer joe = new Customer();
joe.setId( 2 );
joe.setName( "Joe" );
joe.setComments( "Very demanding" );
joe.setSex( 'M' );
Person yomomma = new Person();
yomomma.setId( 3 );
yomomma.setName("mum");
yomomma.setSex('F');
s.save(yomomma);
s.save(mark);
s.save(joe);
assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person").list().size(), 3 );
assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person p where p.class = org.hibernate.test.discriminator.Person").list().size(), 1 );
assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person p where p.class = org.hibernate.test.discriminator.Customer").list().size(), 1 );
s.clear();
List customers = s.createQuery("from org.hibernate.test.discriminator.Customer").list();
for ( Object customer : customers ) {
Customer c = (Customer) customer;
assertEquals( "Very demanding", c.getComments() );
}
assertEquals( customers.size(), 1 );
s.clear();
mark = (Employee) s.get( Employee.class, mark.getId() );
joe = (Customer) s.get( Customer.class, joe.getId() );
s.delete(mark);
s.delete(joe);
s.delete(yomomma);
assertTrue( s.createQuery("from org.hibernate.test.discriminator.Person").list().isEmpty() );
t.commit();
s.close();
}
@Test
public void testAccessAsIncorrectSubclass() {
Session s = openSession();
s.beginTransaction();
Employee e = new Employee();
e.setId( 4 );
e.setName( "Steve" );
e.setSex( 'M' );
e.setTitle( "grand poobah" );
s.save( e );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
Customer c = ( Customer ) s.get( Customer.class, e.getId() );
s.getTransaction().commit();
s.close();
assertNull( c );
s = openSession();
s.beginTransaction();
e = ( Employee ) s.get( Employee.class, e.getId() );
c = ( Customer ) s.get( Customer.class, e.getId() );
s.getTransaction().commit();
s.close();
assertNotNull( e );
assertNull( c );
s = openSession();
s.beginTransaction();
s.delete( e );
s.getTransaction().commit();
s.close();
}
@Test
public void testQuerySubclassAttribute() {
Session s = openSession();
Transaction t = s.beginTransaction();
Person p = new Person();
p.setId( 5 );
p.setName("Emmanuel");
p.setSex('M');
s.save( p );
Employee q = new Employee();
q.setId( 6 );
q.setName("Steve");
q.setSex('M');
q.setTitle("Mr");
q.setSalary( new BigDecimal(1000) );
s.save( q );
List result = s.createQuery("from org.hibernate.test.discriminator.Person where salary > 100").list();
assertEquals( result.size(), 1 );
assertSame( result.get(0), q );
result = s.createQuery("from org.hibernate.test.discriminator.Person where salary > 100 or name like 'E%'").list();
assertEquals( result.size(), 2 );
result = s.createCriteria(Person.class)
.add( Property.forName("salary").gt( new BigDecimal(100) ) )
.list();
assertEquals( result.size(), 1 );
assertSame( result.get(0), q );
//TODO: make this work:
/*result = s.createQuery("select salary from Person where salary > 100").list();
assertEquals( result.size(), 1 );
assertEquals( result.get(0), new BigDecimal(1000) );*/
s.delete(p);
s.delete(q);
t.commit();
s.close();
}
@Test
public void testLoadSuperclassProxyPolymorphicAccess() {
Session s = openSession();
s.beginTransaction();
Employee e = new Employee();
e.setId( 7 );
e.setName( "Steve" );
e.setSex( 'M' );
e.setTitle( "grand poobah" );
s.save( e );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
// load the superclass proxy.
Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) );
assertTrue( pLoad instanceof HibernateProxy);
Person pGet = ( Person ) s.get( Person.class, e.getId());
Person pQuery = ( Person ) s.createQuery( "from org.hibernate.test.discriminator.Person where id = :id" )
.setLong( "id", e.getId() )
.uniqueResult();
Person pCriteria = ( Person ) s.createCriteria( Person.class )
.add( Restrictions.idEq( e.getId() ) )
.uniqueResult();
// assert that executing the queries polymorphically returns the same proxy
assertSame( pLoad, pGet );
assertSame( pLoad, pQuery );
assertSame( pLoad, pCriteria );
// assert that the proxy is not an instance of Employee
assertFalse( pLoad instanceof Employee );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( e );
s.getTransaction().commit();
s.close();
}
@Test
public void testLoadSuperclassProxyEvictPolymorphicAccess() {
Session s = openSession();
s.beginTransaction();
Employee e = new Employee();
e.setId( 8 );
e.setName( "Steve" );
e.setSex( 'M' );
e.setTitle( "grand poobah" );
s.save( e );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
// load the superclass proxy.
Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) );
assertTrue( pLoad instanceof HibernateProxy);
// evict the proxy
s.evict( pLoad );
Employee pGet = ( Employee ) s.get( Person.class, e.getId() );
Employee pQuery = ( Employee ) s.createQuery( "from org.hibernate.test.discriminator.Person where id = :id" )
.setLong( "id", e.getId() )
.uniqueResult();
Employee pCriteria = ( Employee ) s.createCriteria( Person.class )
.add( Restrictions.idEq( e.getId() ) )
.uniqueResult();
// assert that executing the queries polymorphically returns the same Employee instance
assertSame( pGet, pQuery );
assertSame( pGet, pCriteria );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( e );
s.getTransaction().commit();
s.close();
}
}