HHH-7736 join subclass support

This commit is contained in:
Strong Liu 2013-01-12 07:09:58 +08:00
parent ecf0114a63
commit 0671761c14
29 changed files with 1111 additions and 576 deletions

View File

@ -56,7 +56,7 @@ public class SchemaModificationHelper {
}
public static Column getSingleColumn(AttributeBinding attributeBinding) {
if ( !( attributeBinding instanceof SingularAttributeBinding ) ) {
if ( !( attributeBinding.getAttribute().isSingular() ) ) {
// TODO verify that's correct (HF)
return null;
}
@ -65,7 +65,7 @@ public class SchemaModificationHelper {
RelationalValueBinding valueBinding = basicAttributeBinding.getRelationalValueBindings().get( 0 );
Value value = valueBinding.getValue();
if ( !( value instanceof Column ) ) {
if ( valueBinding.isDerived() ) {
return null;
}

View File

@ -170,7 +170,7 @@ public class LoadQueryInfluencers implements Serializable {
return enabledFetchProfileNames != null && !enabledFetchProfileNames.isEmpty();
}
public Set getEnabledFetchProfileNames() {
public Set<String> getEnabledFetchProfileNames() {
return enabledFetchProfileNames;
}

View File

@ -163,6 +163,21 @@ public final class ArrayHelper {
return list;
}
public static <T> T[] reverse(T[] objects) {
return reverse( objects, objects.length );
}
public static <T> T[] reverse(T[] objects, int n) {
final int size = objects.length;
final T[] temp = (T[]) Array.newInstance( objects.getClass().getComponentType(), size );
for ( int i = 0; i < n; i++ ) {
temp[i] = objects[n - i - 1];
}
System.arraycopy( objects, n, temp, n, size - n );
return temp;
}
public static String[] join(String[] x, String[] y) {
String[] result = new String[ x.length + y.length ];
System.arraycopy( x, 0, result, 0, x.length );
@ -181,7 +196,12 @@ public final class ArrayHelper {
}
return result;
}
public static boolean[] join(boolean[] x, boolean[] y) {
boolean[] result = new boolean[ x.length + y.length ];
System.arraycopy( x, 0, result, 0, x.length );
System.arraycopy( y, 0, result, x.length, y.length );
return result;
}
public static int[] join(int[] x, int[] y) {
int[] result = new int[ x.length + y.length ];
System.arraycopy( x, 0, result, 0, x.length );

View File

@ -457,7 +457,7 @@ public class AttributeBuilder {
return null;
}
if ( SingularAttributeBinding.class.isInstance( attributeBinding ) ) {
if ( attributeBinding.getAttribute().isSingular() ) {
final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
final PersistentAttributeType jpaAttributeType;

View File

@ -531,7 +531,7 @@ public class Binder {
// ensure version is non-nullable
for ( RelationalValueBinding valueBinding : version.getVersioningAttributeBinding()
.getRelationalValueBindings() ) {
if ( valueBinding.getValue() instanceof Column ) {
if ( !valueBinding.isDerived() ) {
( (Column) valueBinding.getValue() ).setNullable( false );
}
}
@ -2283,7 +2283,7 @@ public class Binder {
primaryKey.addColumn( foreignKeyColumn );
}
for ( final RelationalValueBinding elementValueBinding : elementBinding.getRelationalValueBindings() ) {
if ( elementValueBinding.getValue() instanceof Column && !elementValueBinding.isNullable() ) {
if ( !elementValueBinding.isDerived() && !elementValueBinding.isNullable() ) {
primaryKey.addColumn( (Column) elementValueBinding.getValue() );
}
}
@ -3023,7 +3023,7 @@ public class Binder {
primaryKey.addColumn( foreignKeyColumn );
}
for ( RelationalValueBinding relationalValueBinding : indexBinding.getRelationalValueBindings() ) {
if ( relationalValueBinding.getValue() instanceof Column ) {
if ( !relationalValueBinding.isDerived() ) {
primaryKey.addColumn( (Column) relationalValueBinding.getValue() );
}
}

View File

@ -367,16 +367,16 @@ public class BindHelper {
private static AttributeBinding getRecursiveAttributeBinding(
EntityBinding entityBinding, String propertyPath) {
Iterable<AttributeBinding> attributeBindings
= entityBinding.getAttributeBindingClosure();
StringTokenizer st = new StringTokenizer( propertyPath, "." );
// Iterable<AttributeBinding> attributeBindings
// = entityBinding.getAttributeBindingClosure();
// StringTokenizer st = new StringTokenizer( propertyPath, "." );
AttributeBinding attributeBinding = null;
while ( st.hasMoreElements() ) {
String element = st.nextToken();
for ( AttributeBinding binding : attributeBindings ) {
}
}
// while ( st.hasMoreElements() ) {
// String element = st.nextToken();
// for ( AttributeBinding binding : attributeBindings ) {
//
// }
// }
return attributeBinding;
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.metamodel.internal.source.hbm;
import org.hibernate.metamodel.spi.source.ColumnSource;
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class PrimaryKeyJoinColumnSourceImpl implements PrimaryKeyJoinColumnSource {
private final ColumnSource columnSource;
public PrimaryKeyJoinColumnSourceImpl(ColumnSource relationalValueSource) {
this.columnSource = relationalValueSource;
}
@Override
public String getColumnName() {
return columnSource.getName();
}
@Override
public String getReferencedColumnName() {
return null;
}
@Override
public String getColumnDefinition() {
return columnSource.getSqlType();
}
}

View File

@ -23,14 +23,19 @@
*/
package org.hibernate.metamodel.internal.source.hbm;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.jaxb.spi.hbm.EntityElement;
import org.hibernate.jaxb.spi.hbm.JaxbColumnElement;
import org.hibernate.jaxb.spi.hbm.JaxbJoinedSubclassElement;
import org.hibernate.jaxb.spi.hbm.JaxbKeyElement;
import org.hibernate.jaxb.spi.hbm.JaxbSubclassElement;
import org.hibernate.jaxb.spi.hbm.TableInformationSource;
import org.hibernate.metamodel.spi.source.ColumnSource;
import org.hibernate.metamodel.spi.source.EntitySource;
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.SubclassEntitySource;
import org.hibernate.metamodel.spi.source.TableSpecificationSource;
@ -40,7 +45,9 @@ import org.hibernate.metamodel.spi.source.TableSpecificationSource;
public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implements SubclassEntitySource {
private final EntitySource container;
private final TableSpecificationSource primaryTable;
private final boolean isJoinedSubclass;
private final JaxbKeyElement key;
private final List<PrimaryKeyJoinColumnSource> primaryKeyJoinColumnSources;
protected SubclassEntitySourceImpl(
MappingDocument sourceMappingDocument,
EntityElement entityElement,
@ -50,6 +57,45 @@ public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implement
this.primaryTable = TableInformationSource.class.isInstance( entityElement )
? Helper.createTableSource( sourceMappingDocument(), (TableInformationSource) entityElement, this )
: null;
this.isJoinedSubclass = JaxbJoinedSubclassElement.class.isInstance( entityElement );
this.key = isJoinedSubclass? ( (JaxbJoinedSubclassElement) entityElement() ).getKey() : null;
if ( isJoinedSubclass ) {
List<RelationalValueSource> valueSources = Helper.buildValueSources(
sourceMappingDocument(),
new Helper.ValueSourcesAdapter() {
@Override
public boolean isIncludedInInsertByDefault() {
return true;
}
@Override
public boolean isIncludedInUpdateByDefault() {
return Helper.getValue( key.isUpdate(), true );
}
@Override
public String getColumnAttribute() {
return key.getColumnAttribute();
}
@Override
public List<JaxbColumnElement> getColumn() {
return key.getColumn();
}
@Override
public boolean isForceNotNull() {
return Helper.getValue( key.isNotNull(), false );
}
}
);
this.primaryKeyJoinColumnSources = new ArrayList<PrimaryKeyJoinColumnSource>( valueSources.size() );
for(final RelationalValueSource valueSource : valueSources){
primaryKeyJoinColumnSources.add( new PrimaryKeyJoinColumnSourceImpl( ColumnSource.class.cast( valueSource ) ) );
}
} else {
this.primaryKeyJoinColumnSources = null;
}
afterInstantiation();
}
@ -73,14 +119,14 @@ public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implement
@Override
public String getJoinedForeignKeyName() {
if ( JaxbJoinedSubclassElement.class.isInstance( entityElement() ) ) {
return ( (JaxbJoinedSubclassElement) entityElement() ).getKey().getForeignKey();
if ( isJoinedSubclass ) {
return key.getForeignKey();
}
return null;
}
@Override
public List<PrimaryKeyJoinColumnSource> getPrimaryKeyJoinColumnSources() {
return null;
return primaryKeyJoinColumnSources;
}
}

View File

@ -49,7 +49,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
@Override
public AttributeBinding locateAttributeBinding(List<Value> values) {
for ( AttributeBinding attributeBinding : attributeBindingMapInternal().values() ) {
if ( !SingularAttributeBinding.class.isInstance( attributeBinding ) ) {
if ( !attributeBinding.getAttribute().isSingular() ) {
continue;
}
SingularAttributeBinding basicAttributeBinding = (SingularAttributeBinding) attributeBinding;

View File

@ -24,18 +24,16 @@
package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
@ -158,7 +156,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
}
public boolean isPolymorphic() {
return superEntityBinding != null ||
return !isRoot() ||
hierarchyDetails.getEntityDiscriminator() != null ||
!subEntityBindings.isEmpty();
}
@ -167,71 +165,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
return !subEntityBindings.isEmpty();
}
public int getSubEntityBindingClosureSpan() {
int n = subEntityBindings.size();
for ( EntityBinding subEntityBinding : subEntityBindings ) {
n += subEntityBinding.getSubEntityBindingClosureSpan();
}
return n;
}
/* used for testing */
public Iterable<EntityBinding> getDirectSubEntityBindings() {
return subEntityBindings;
}
/**
* Returns sub-EntityBinding objects in a special 'order', most derived subclasses
* 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.
*/
public Iterable<EntityBinding> getPostOrderSubEntityBindingClosure() {
// TODO: why this order?
List<Iterable<EntityBinding>> subclassIterables = new ArrayList<Iterable<EntityBinding>>( subEntityBindings.size() + 1 );
for ( EntityBinding subEntityBinding : subEntityBindings ) {
Iterable<EntityBinding> subSubEntityBindings = subEntityBinding.getPostOrderSubEntityBindingClosure();
if ( subSubEntityBindings.iterator().hasNext() ) {
subclassIterables.add( subSubEntityBindings );
}
}
if ( !subEntityBindings.isEmpty() ) {
subclassIterables.add( subEntityBindings );
}
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() {
return entity;
@ -317,79 +251,8 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
public void addSecondaryTable(SecondaryTable secondaryTable) {
secondaryTables.put( secondaryTable.getSecondaryTableReference().getLogicalName().getText(), secondaryTable );
}
public int getSecondaryTableClosureSpan() {
return superEntityBinding != null ?
superEntityBinding.getSecondaryTableClosureSpan() + secondaryTables.size() :
secondaryTables.size();
}
/**
* Gets the attribute bindings defined on this class, including the
* identifier attribute binding and attribute bindings defined
* as part of a join.
*
* @return The attribute bindings.
*/
public Iterable<SecondaryTable> getSecondaryTableClosure() {
Iterable<SecondaryTable> iterable;
if ( superEntityBinding != null ) {
List<Iterable<SecondaryTable>> iterables = new ArrayList<Iterable<SecondaryTable>>( 2 );
iterables.add( superEntityBinding.getSecondaryTableClosure() );
iterables.add( secondaryTables.values() );
iterable = new JoinedIterable<SecondaryTable>( iterables );
}
else {
iterable = secondaryTables.values();
}
return iterable;
}
private Iterable<SecondaryTable> getSubclassSecondaryTables() {
List<Iterable<SecondaryTable>> iterables = new ArrayList<Iterable<SecondaryTable>>( subEntityBindings.size() );
for ( EntityBinding subEntityBinding : subEntityBindings ) {
iterables.add( subEntityBinding.secondaryTables.values() );
if ( ! subEntityBinding.subEntityBindings.isEmpty() ) {
iterables.add( subEntityBinding.getSubclassSecondaryTables() );
}
}
return new JoinedIterable<SecondaryTable>( iterables );
}
public Iterable<SecondaryTable> getSubclassSecondaryTableClosure() {
Iterable<SecondaryTable> iterable;
if ( ! subEntityBindings.isEmpty() ) {
List<Iterable<SecondaryTable>> iterables = new ArrayList<Iterable<SecondaryTable>>( 2 );
iterables.add( getSecondaryTableClosure() );
iterables.add( getSubclassSecondaryTables() );
iterable = new JoinedIterable<SecondaryTable>( iterables );
}
else {
iterable = getSecondaryTableClosure();
}
return iterable;
}
public boolean isClassOrSuperclassSecondaryTable(SecondaryTable secondaryTable) {
String secondaryTableName = secondaryTable.getSecondaryTableReference().getLogicalName().getText();
return secondaryTables.containsKey( secondaryTableName ) ||
( superEntityBinding != null && superEntityBinding.isClassOrSuperclassSecondaryTable( secondaryTable ) );
}
public int getSecondaryTableNumber(SingularAttributeBinding attributeBinding) {
if ( attributeBinding.getRelationalValueBindings().isEmpty() ) {
return 0;
}
int result=1;
Value value = attributeBinding.getRelationalValueBindings().get( 0 ).getValue();
TableSpecification table = value.getTable();
for ( SecondaryTable secondaryTable : getSubclassSecondaryTableClosure() ) {
if ( secondaryTable.getSecondaryTableReference() == table ) {
return result;
}
result++;
}
return 0;
public Map<String, SecondaryTable> getSecondaryTables() {
return secondaryTables;
}
@ -669,28 +532,57 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
return binding;
}
public AttributeBinding locateAttributeBindingByPath(String path) {
if ( path == null ) {
throw new IllegalArgumentException( "path must be non-null." );
}
final String pathDelimiter = "\\.";
String[] tokens = path.split( pathDelimiter );
AttributeBinding attributeBinding = locateAttributeBinding( tokens[ 0 ] );
if ( attributeBinding == null ) {
return superEntityBinding == null ? null : superEntityBinding.locateAttributeBindingByPath( path );
}
for ( int i = 1 ; i < tokens.length && attributeBinding != null ; i++ ) {
if ( ! attributeBinding.getAttribute().isSingular() ||
! ( (SingularAttribute) attributeBinding.getAttribute() ).getSingularAttributeType().isAggregate() ) {
// TODO: improve this message!!!
throw new MappingException( "improve this!!!" );
}
AttributeBindingContainer attributeBindingContainer = (AttributeBindingContainer) attributeBinding;
attributeBinding = attributeBindingContainer.locateAttributeBinding( tokens[ i ] );
}
return attributeBinding;
public void setJpaCallbackClasses(List<JpaCallbackSource> jpaCallbackClasses) {
this.jpaCallbackClasses = jpaCallbackClasses;
}
public Iterable<JpaCallbackSource> getJpaCallbackClasses() {
return jpaCallbackClasses;
}
//--------------------------
//meta methods for persister , to improve performance, these methods below should really be replaced as ValueHolder
//and only be called in persister -- after build MetadataImpl
public TableSpecification[] getTableClosure() {
if ( isRoot() ) {
return new TableSpecification[] { getPrimaryTable() };
}
return ArrayHelper.join( superEntityBinding.getTableClosure(), getPrimaryTable() );
}
public EntityBinding[] getEntityBindingClosure() {
if ( isRoot() ) {
return new EntityBinding[] { this };
}
return ArrayHelper.join( superEntityBinding.getEntityBindingClosure(), this );
}
public int getSecondaryTableClosureSpan() {
return isRoot() ? secondaryTables.size() : superEntityBinding.getSecondaryTableClosureSpan() + secondaryTables.size();
}
public SecondaryTable[] getSecondaryTableClosure() {
if ( isRoot() ) {
return secondaryTables.values().toArray( new SecondaryTable[secondaryTables.size()] );
}
else {
return ArrayHelper.join(
superEntityBinding.getSecondaryTableClosure(),
secondaryTables.values().toArray( new SecondaryTable[secondaryTables.size()] )
);
}
}
public String[] getSynchronizedTableNameClosure() {
if ( isRoot() ) {
return getSynchronizedTableNames();
}
return ArrayHelper.join( superEntityBinding.getSynchronizedTableNameClosure(), getSynchronizedTableNames() );
}
/**
* Gets the number of attribute bindings defined on this class, including the
* identifier attribute binding and attribute bindings defined
@ -700,9 +592,8 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
*/
public int getAttributeBindingClosureSpan() {
// TODO: update account for join attribute bindings
return superEntityBinding != null ?
superEntityBinding.getAttributeBindingClosureSpan() + attributeBindingMap.size() :
attributeBindingMap.size();
return isRoot() ? getNonIdAttributeBindingClosure().length :
superEntityBinding.getAttributeBindingClosureSpan() + getNonIdAttributeBindingClosure().length;
}
/**
@ -712,19 +603,127 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
*
* @return The attribute bindings.
*/
public Iterable<AttributeBinding> getAttributeBindingClosure() {
public AttributeBinding[] getAttributeBindingClosure() {
// TODO: update size to account for joins
Iterable<AttributeBinding> iterable;
if ( superEntityBinding != null ) {
List<Iterable<AttributeBinding>> iterables = new ArrayList<Iterable<AttributeBinding>>( 2 );
iterables.add( superEntityBinding.getAttributeBindingClosure() );
iterables.add( attributeBindings() );
iterable = new JoinedIterable<AttributeBinding>( iterables );
if ( isRoot() ) {
return getNonIdAttributeBindingClosure();
}
else {
iterable = attributeBindings();
return ArrayHelper.join(
superEntityBinding.getAttributeBindingClosure(),
getNonIdAttributeBindingClosure()
);
}
return iterable;
}
private AttributeBinding[] getNonIdAttributeBindingClosure() {
List<AttributeBinding> list = new ArrayList<AttributeBinding>();
attributeBindings();
for ( final AttributeBinding ab : attributeBindings() ) {
if(ab instanceof CompositeAttributeBinding){
}
boolean isId = getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( ab );
if ( !isId ) {
list.add( ab );
}
}
return list.toArray( new AttributeBinding[list.size()] );
}
/* used for testing */
public List<EntityBinding> getDirectSubEntityBindings() {
return subEntityBindings;
}
/**
* Returns sub-EntityBinding objects in a special 'order', most derived subclasses
* 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.
*/
public EntityBinding[] getPostOrderSubEntityBindingClosure() {
EntityBinding[] results = new EntityBinding[0];
if ( subEntityBindings.isEmpty() ) {
return results;
}
for ( EntityBinding subEntityBinding : subEntityBindings ) {
EntityBinding[] subSubEntityBindings = subEntityBinding.getPostOrderSubEntityBindingClosure();
results = ArrayHelper.join( results, subSubEntityBindings );
}
if ( !subEntityBindings.isEmpty() ) {
results = ArrayHelper.join( results, subEntityBindings.toArray( new EntityBinding[subEntityBindings.size()] ) );
}
return results;
}
/**
* 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 EntityBinding[] getPreOrderSubEntityBindingClosure() {
return getPreOrderSubEntityBindingClosure( false, new EntityBinding[0] );
}
private EntityBinding[] getPreOrderSubEntityBindingClosure(boolean includeThis, EntityBinding[] results) {
if ( includeThis ) {
results = ArrayHelper.join( results, this );
}
for ( EntityBinding subEntityBinding : subEntityBindings ) {
results = subEntityBinding.getPreOrderSubEntityBindingClosure(
true, results
);
}
return results;
}
public TableSpecification[] getPreOrderSubTableClosure(){
EntityBinding[] subEntityBindings = getPreOrderSubEntityBindingClosure();
TableSpecification [] tables = new TableSpecification[subEntityBindings.length];
for(int i=0;i<subEntityBindings.length;i++){
tables[i] = subEntityBindings[i].getPrimaryTable();
}
return tables;
}
public SecondaryTable[] getSubEntitySecondaryTables() {
SecondaryTable[] results = new SecondaryTable[0];
for ( EntityBinding eb : getPreOrderSubEntityBindingClosure() ) {
Collection<SecondaryTable> sts = eb.getSecondaryTables().values();
int size = sts.size();
if ( size == 0 ) {
continue;
}
results = ArrayHelper.join( results, sts.toArray( new SecondaryTable[size] ) );
}
return results;
}
public SecondaryTable[] getEntitiesSecondaryTableClosure() {
if ( ! subEntityBindings.isEmpty() ) {
return ArrayHelper.join( getSecondaryTableClosure(), getSubEntitySecondaryTables() );
}
else {
return getSecondaryTableClosure();
}
}
public int getSubEntityBindingClosureSpan() {
int n = subEntityBindings.size();
for ( final EntityBinding seb : subEntityBindings ) {
n += seb.getSubEntityBindingClosureSpan();
}
return n;
}
/**
@ -732,37 +731,42 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
* sub-EntityBinding, starting from the root of the hierarchy; includes
* the identifier and attribute bindings defined as part of a join.
*/
public Iterable<AttributeBinding> getSubEntityAttributeBindingClosure() {
List<Iterable<AttributeBinding>> iterables = new ArrayList<Iterable<AttributeBinding>>();
iterables.add( getAttributeBindingClosure() );
public AttributeBinding[] getEntitiesAttributeBindingClosure() {
AttributeBinding[] results = getAttributeBindingClosure();
for ( EntityBinding subEntityBinding : getPreOrderSubEntityBindingClosure() ) {
// only add attribute bindings declared for the subEntityBinding
iterables.add( subEntityBinding.attributeBindings() );
results = ArrayHelper.join(
results,
subEntityBinding.getNonIdAttributeBindingClosure()
);
// TODO: if EntityBinding.attributeBindings() excludes joined attributes, then they need to be added here
}
return new JoinedIterable<AttributeBinding>( iterables );
return results;
}
public Iterator<TableSpecification> getTableClosureIterator() {
if ( superEntityBinding == null ) {
return new SingletonIterator<TableSpecification>( getPrimaryTable() );
public boolean isClassOrSuperclassSecondaryTable(SecondaryTable secondaryTable) {
String secondaryTableName = secondaryTable.getSecondaryTableReference().getLogicalName().getText();
return secondaryTables.containsKey( secondaryTableName ) ||
( superEntityBinding != null && superEntityBinding.isClassOrSuperclassSecondaryTable( secondaryTable ) );
}
public int getSecondaryTableNumber(SingularAttributeBinding attributeBinding) {
if ( attributeBinding.getRelationalValueBindings().isEmpty() ) {
return 0;
}
else {
return new JoinedIterator<TableSpecification>(
superEntityBinding.getTableClosureIterator(),
new SingletonIterator<TableSpecification>( getPrimaryTable() )
);
int result=1;
Value value = attributeBinding.getRelationalValueBindings().get( 0 ).getValue();
TableSpecification table = value.getTable();
for ( SecondaryTable secondaryTable : getEntitiesSecondaryTableClosure() ) {
if ( secondaryTable.getSecondaryTableReference() == table ) {
return result;
}
result++;
}
}
public Iterator getKeyClosureIterator(){
return null;
return 0;
}
public void setJpaCallbackClasses(List<JpaCallbackSource> jpaCallbackClasses) {
this.jpaCallbackClasses = jpaCallbackClasses;
}
public Iterable<JpaCallbackSource> getJpaCallbackClasses() {
return jpaCallbackClasses;
}
}

View File

@ -119,6 +119,14 @@ public class EntityIdentifier {
return entityIdentifierBinding.isIdentifierAttributeBinding( attributeBinding );
}
public boolean isCascadeDeleteEnabled() {
if ( getAttributeBinding() instanceof Cascadeable ) {
Cascadeable cascadeable = Cascadeable.class.cast( getAttributeBinding() );
cascadeable.getCascadeStyle();//todo
}
return false;
}
public String getUnsavedValue() {
ensureBound();
return entityIdentifierBinding.getUnsavedValue();

View File

@ -25,14 +25,11 @@ package org.hibernate.metamodel.spi.relational;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.internal.util.collections.JoinedIterable;
/**
* @author Strong Liu <stliu@hibernate.org>
*/

View File

@ -702,7 +702,7 @@ public abstract class AbstractCollectionPersister
// isSorted = collection.isSorted();
isArray = collectionType.isArrayType();
isPrimitiveArray =
collectionType.isArrayType() &&
isArray &&
PrimitiveType.class.isInstance(
collection.getPluralAttributeElementBinding()
.getHibernateTypeDescriptor()
@ -840,9 +840,10 @@ public abstract class AbstractCollectionPersister
indexColumnIsSettable = new boolean[indexSpan];
indexColumnAliases = new String[indexSpan];
for ( int i = 0 ; i < indexSpan ; i++ ) {
final Value value = indexRelationalValueBindings.get( i ).getValue();
final RelationalValueBinding rb = indexRelationalValueBindings.get( i );
final Value value = rb.getValue();
indexColumnAliases[ i ] = value.getAlias( dialect, null );
if ( value instanceof Column ) {
if ( !rb.isDerived() ) {
indexColumnIsSettable[ i ] = true;
Column column = ( Column ) value;
indexColumnNames[ i ] = column.getColumnName().getText( dialect );

View File

@ -73,7 +73,6 @@ import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.PersistenceContext.NaturalIdHelper;
@ -86,7 +85,6 @@ import org.hibernate.id.PostInsertIdentityPersister;
import org.hibernate.id.insert.Binder;
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
@ -94,7 +92,6 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.jdbc.TooManyRowsAffectedException;
import org.hibernate.loader.entity.BatchingEntityLoader;
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
import org.hibernate.loader.entity.CascadeEntityLoader;
import org.hibernate.loader.entity.EntityLoader;
@ -109,15 +106,15 @@ import org.hibernate.metamodel.spi.binding.Cascadeable;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.Fetchable;
import org.hibernate.metamodel.spi.binding.PluralAttributeAssociationElementBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.PrimaryKey;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor;
@ -169,6 +166,7 @@ public abstract class AbstractEntityPersister
private final String[] rootTableKeyColumnReaders;
private final String[] rootTableKeyColumnReaderTemplates;
private final String[] identifierAliases;
//how many columns are mapped by the identifier?
private final int identifierColumnSpan;
private final String versionColumnName;
private final boolean hasFormulaProperties;
@ -237,8 +235,8 @@ public abstract class AbstractEntityPersister
private final Set affectingFetchProfileNames = new HashSet();
private final Map uniqueKeyLoaders = new HashMap();
private final Map lockers = new HashMap();
private final Map<String, EntityLoader> uniqueKeyLoaders = new HashMap<String, EntityLoader>();
private final Map<LockMode, LockingStrategy> lockers = new HashMap<LockMode, LockingStrategy>();
private final Map loaders = new HashMap();
// SQL strings
@ -280,8 +278,8 @@ public abstract class AbstractEntityPersister
private final String temporaryIdTableName;
private final String temporaryIdTableDDL;
private final Map subclassPropertyAliases = new HashMap();
private final Map subclassPropertyColumnNames = new HashMap();
private final Map<String, String[]> subclassPropertyAliases = new HashMap<String, String[]>();
private final Map<String, String[]> subclassPropertyColumnNames = new HashMap<String, String[]>();
protected final BasicEntityPropertyMapping propertyMapping;
@ -390,6 +388,19 @@ public abstract class AbstractEntityPersister
}
return result;
}
protected static void initializeCustomSql(
CustomSQL customSql,
int i,
String[] sqlStrings,
boolean[] callable,
ExecuteUpdateResultCheckStyle[] checkStyles) {
sqlStrings[i] = customSql != null ? customSql.getSql(): null;
callable[i] = customSql != null && customSql.isCallable();
checkStyles[i] = customSql != null && customSql.getCheckStyle() != null ?
customSql.getCheckStyle() :
ExecuteUpdateResultCheckStyle.determineDefault( sqlStrings[i], callable[i] );
}
protected String getSQLSnapshotSelectString() {
return sqlSnapshotSelectString;
@ -866,9 +877,11 @@ public abstract class AbstractEntityPersister
rootTableKeyColumnReaderTemplates = new String[identifierColumnSpan];
identifierAliases = new String[identifierColumnSpan];
int i = 0;
for ( org.hibernate.metamodel.spi.relational.Column col : entityBinding.getPrimaryTable().getPrimaryKey().getColumns() ) {
for ( int i = 0; i < identifierColumnSpan; i++ ) {
org.hibernate.metamodel.spi.relational.Column col = entityBinding.getPrimaryTable()
.getPrimaryKey()
.getColumns()
.get( i );
rootTableKeyColumnNames[i] = col.getColumnName().getText( factory.getDialect() );
if ( col.getReadFragment() == null ) {
rootTableKeyColumnReaders[i] = rootTableKeyColumnNames[i];
@ -878,8 +891,7 @@ public abstract class AbstractEntityPersister
rootTableKeyColumnReaders[i] = col.getReadFragment();
rootTableKeyColumnReaderTemplates[i] = getTemplateFromString( col.getReadFragment(), factory );
}
identifierAliases[i] = col.getAlias( factory.getDialect(), entityBinding.getPrimaryTable() );
i++;
identifierAliases[i] = col.getAlias( factory.getDialect(), entityBinding.getHierarchyDetails().getRootEntityBinding().getPrimaryTable() );
}
// VERSION
@ -937,7 +949,7 @@ public abstract class AbstractEntityPersister
List<String[]> lazyColAliases = new ArrayList<String[]>();
i = 0;
int i = 0;
boolean foundFormula = false;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
@ -1042,7 +1054,7 @@ public abstract class AbstractEntityPersister
List<Boolean> columnSelectables = new ArrayList<Boolean>();
List<Boolean> propNullables = new ArrayList<Boolean>();
for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding attributeBinding : entityBinding.getEntitiesAttributeBindingClosure() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
// entity identifier is not considered a "normal" property
continue;
@ -1835,7 +1847,7 @@ public abstract class AbstractEntityPersister
}
private LockingStrategy getLocker(LockMode lockMode) {
return ( LockingStrategy ) lockers.get( lockMode );
return lockers.get( lockMode );
}
public void lock(
@ -2085,7 +2097,7 @@ public abstract class AbstractEntityPersister
}
public String[] getSubclassPropertyColumnAliases(String propertyName, String suffix) {
String rawAliases[] = ( String[] ) subclassPropertyAliases.get( propertyName );
String rawAliases[] = subclassPropertyAliases.get( propertyName );
if ( rawAliases == null ) {
return null;
@ -2097,10 +2109,10 @@ public abstract class AbstractEntityPersister
}
return result;
}
@Override
public String[] getSubclassPropertyColumnNames(String propertyName) {
//TODO: should we allow suffixes on these ?
return ( String[] ) subclassPropertyColumnNames.get( propertyName );
return subclassPropertyColumnNames.get( propertyName );
}
@ -2179,7 +2191,7 @@ public abstract class AbstractEntityPersister
// ALIASES
// TODO: Fix when subclasses are working (HHH-6337)
internalInitSubclassPropertyAliasesMap( null, entityBinding.getSubEntityAttributeBindingClosure() );
internalInitSubclassPropertyAliasesMap( null, entityBinding.getEntitiesAttributeBindingClosure() );
// aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id'
if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
@ -2266,10 +2278,12 @@ public abstract class AbstractEntityPersister
}
}
private void internalInitSubclassPropertyAliasesMap(String path, Iterable<AttributeBinding> attributeBindings) {
protected static boolean isIdentifierAttributeBinding(final AttributeBinding prop){
return prop.getContainer().seekEntityBinding().getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( prop );
}
private void internalInitSubclassPropertyAliasesMap(String path, AttributeBinding[] attributeBindings) {
for ( AttributeBinding prop : attributeBindings ) {
if ( prop.getContainer().seekEntityBinding().getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( prop ) ) {
if ( isIdentifierAttributeBinding( prop ) ) {
// ID propertie aliases are dealt with elsewhere.
continue;
}
@ -2281,7 +2295,12 @@ public abstract class AbstractEntityPersister
String propname = path == null ? prop.getAttribute().getName() : path + "." + prop.getAttribute().getName();
if ( prop instanceof CompositeAttributeBinding ) {
CompositeAttributeBinding component = (CompositeAttributeBinding) prop;
internalInitSubclassPropertyAliasesMap( propname, component.attributeBindings() );
AttributeBinding[] abs = new AttributeBinding[component.attributeBindingSpan()];
int i=0;
for(AttributeBinding ab : component.attributeBindings()){
abs[i++] = ab;
}
internalInitSubclassPropertyAliasesMap( propname, abs );
}
else {
int span = singularProp.getRelationalValueBindings().size();
@ -2324,7 +2343,7 @@ public abstract class AbstractEntityPersister
&& propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
if ( useStaticLoader ) {
return ( EntityLoader ) uniqueKeyLoaders.get( propertyName );
return uniqueKeyLoaders.get( propertyName );
}
else {
return createUniqueKeyLoader(
@ -3898,10 +3917,11 @@ public abstract class AbstractEntityPersister
}
private boolean isAffectedByEnabledFetchProfiles(SessionImplementor session) {
Iterator itr = session.getLoadQueryInfluencers().getEnabledFetchProfileNames().iterator();
while ( itr.hasNext() ) {
if ( affectingFetchProfileNames.contains( itr.next() ) ) {
return true;
if ( session.getLoadQueryInfluencers().hasEnabledFetchProfiles() ) {
for ( String name : session.getLoadQueryInfluencers().getEnabledFetchProfileNames() ) {
if ( affectingFetchProfileNames.contains( name ) ) {
return true;
}
}
}
return false;
@ -3962,8 +3982,7 @@ public abstract class AbstractEntityPersister
protected final boolean[] getPropertiesToUpdate(final int[] dirtyProperties, final boolean hasDirtyCollection) {
final boolean[] propsToUpdate = new boolean[ entityMetamodel.getPropertySpan() ];
final boolean[] updateability = getPropertyUpdateability(); //no need to check laziness, dirty checking handles that
for ( int j = 0; j < dirtyProperties.length; j++ ) {
int property = dirtyProperties[j];
for ( int property : dirtyProperties ) {
if ( updateability[property] ) {
propsToUpdate[property] = true;
}
@ -4058,8 +4077,8 @@ public abstract class AbstractEntityPersister
private void logDirtyProperties(int[] props) {
if ( LOG.isTraceEnabled() ) {
for ( int i = 0; i < props.length; i++ ) {
String propertyName = entityMetamodel.getProperties()[ props[i] ].getName();
for ( int prop : props ) {
String propertyName = entityMetamodel.getProperties()[prop].getName();
LOG.trace( StringHelper.qualify( getEntityName(), propertyName ) + " is dirty" );
}
}
@ -4220,13 +4239,7 @@ public abstract class AbstractEntityPersister
}
public Boolean isTransient(Object entity, SessionImplementor session) throws HibernateException {
final Serializable id;
if ( canExtractIdOutOfEntity() ) {
id = getIdentifier( entity, session );
}
else {
id = null;
}
final Serializable id = canExtractIdOutOfEntity() ? getIdentifier( entity, session ) : null;
// we *always* assume an instance with a null
// identifier or no identifier property is unsaved!
if ( id == null ) {
@ -4276,7 +4289,6 @@ public abstract class AbstractEntityPersister
}
private boolean isModifiableEntity(EntityEntry entry) {
return ( entry == null ? isMutable() : entry.isModifiableEntity() );
}
@ -4566,6 +4578,20 @@ public abstract class AbstractEntityPersister
return temporaryIdTableDDL;
}
/**
* Here, we want to know how many properties of this persister know about.
* <p/>
* The properties including:
* <ul>
* <li>properties belongs to the current entity</li>
* <li>properties belongs to the join entity</li>
* <li>parent's properties, recursively</li>
* </ul>
*
* note: id property is not included here
*
* @return
*/
protected int getPropertySpan() {
return entityMetamodel.getPropertySpan();
}

View File

@ -27,6 +27,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.AssertionFailure;
@ -35,6 +36,7 @@ import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
@ -50,9 +52,12 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.EntityDiscriminator;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SecondaryTable;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.PrimaryKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.sql.CaseFragment;
@ -67,32 +72,192 @@ import org.hibernate.type.*;
*/
public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
// the class hierarchy structure
/**
* Tables' count, which tables are mapped directly by the current entity ( and its parent entity, recursively, if any ),
* including the joined tables, but sub-entities of the current entity are not included.
*/
private final int tableSpan;
private final String[] tableNames;
/**
* Span of the tables directly mapped by this entity and super-classes, if any.
* <p/>
* so, <code>coreTableSpan = tableSpan - join tables span</code>
*/
private final int coreTableSpan;
/**
* Tables' name, the tables' scope is same as {@code tableSpan}.
* <p/>
*
* This array ( the table names ) is order by the following roles:
* <ul>
* <li>Table mapped by the root entity of current one if any</li>
* <li>Table mapped by sub entity of the root one, recursively, till the current entity in the hierarchy level</li>
* <li>Joined tables, also, in the top-down order of the hierarchy</li>
* </ul>
*
* <p/>
*
* Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
* For the Client entity:
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
* added to the meta-data when the annotated entities are processed.
* However, in some instances, for example when generating joins, the CLIENT table needs to be
* the first table as it will the driving table.
* tableNames -> CLIENT, PERSON
*
* <p>
* The length of this array is <code>tableSpan</code>
* </p>
*/
private final String[] naturalOrderTableNames;
private final String[][] tableKeyColumns;
private final String[][] tableKeyColumnReaders;
private final String[][] tableKeyColumnReaderTemplates;
/**
* This contains same elements as naturalOrderTableNames, but in different order.
* <p/>
*
* As said above, elements in this array are actually composited by two parts:
*
* <ul>
* <li>Table names mapped directly by the entities of the hierarchy</li>
* <li>Table names mapped by "join"</li>
* </ul>
*
* In the first part of elements, the naturalOrderTableNames follows "root" -> "sub-entities" -> "current entity"
*
* here, we have a reversed order, so "current entity" -> "parent entity" -> "root entity"
*
* <p/>
*
* The order of the second part is same.
*
* <p>
* The length of this array is <code>tableSpan</code>
* </p>
*
*/
private final String[] tableNames;
/**
* These two follow same role as above, but for the primary key columns
*
* <p>
* The first dimension length of this array is <code>tableSpan</code>
* </p>
*/
private final String[][] naturalOrderTableKeyColumns;
private final String[][] tableKeyColumns;
/**
* Same as above, just for different column metadata.
*/
private final String[][] tableKeyColumnReaders;
private final String[][] naturalOrderTableKeyColumnReaders;
/**
* Same as above, just for different column metadata.
*/
private final String[][] tableKeyColumnReaderTemplates;
private final String[][] naturalOrderTableKeyColumnReaderTemplates;
/**
* If the identifier is cascade delete enabled.
* Array is ordered by the natural way ( {@see naturalOrderTableNames} )
*
* <p>
* The length of this array is <code>tableSpan</code>
* </p>
*/
private final boolean[] naturalOrderCascadeDeleteEnabled;
/**
* <code>tableNames</code>
* <code>synchronized tables in the entity hierarchy from top down to the current entity level, sub-entities are not included</code>
*
* <p>
* The length of this array is <code>tableSpan + sync table count</code>
* </p>
*/
private final String[] spaces;
/**
* This array contains all the sub-entities' name of the current entity, and
* the last element of this array is the current entity name.
*
* Sub-entities' name is ordered in the most derived subclasses first, from bottom to top, till the current one.
*
* <p>
* The length of this array is the count of all the sub entities (recursively) of the current one + 1
* </p>
*/
private final String[] subclassClosure;
/**
* This is kind of same as {@see tableNames}, but it contains all the tables' name mapped by the current entity's super entities AND
* sub entities, and joined tables mapped by the entities.
*
* Actually, due to the order operation, the first <code>coreTableSpan</code> elements are same as <code>tableNames</code>.
* (table names mapped by the current entity and its super entities, joined tables are not included)
*
* So, this property is kind of weird to me, it has:
*
* 1. "current entity" -> "parent entity" -> "root entity" -> "first sub-entity" -> "second sub-entity" .... "last sub-entity"
* 2. "root entity join table" -> ..."last entity join table"
*
*
* <p>
* Though this property is named with "subclassTable" perfix, but its length is actually:
* tableSpan + all sub-entities mapped tables' count + all sub-entities joined tables' count
* </p>
*/
private final String[] subclassTableNameClosure;
/**
* table's primary key columns, in the same order as above
*
* <p>
* The length is same as <code>subclassTableNameClosure</code>
* </p>
*/
private final String[][] subclassTableKeyColumnClosure;
/**
* If the table, in the order of <code>subclassTableNameClosure</code> is concreted.
* By "concreted", here means if the table is one of current entity or its super entity mapped table
*
* <p>
* The length is same as <code>subclassTableNameClosure</code>
* </p>
*/
private final boolean[] isClassOrSuperclassTable;
// properties of this class, including inherited properties
/**
* The element in this array is the index of the {@see naturalOrderTableNames}, which table that the column is belonged to.
*
* So, this is all about the columns ( except PK ) mapped by the properties in the current entity and its parent entity, in a top down order.
*
* <p>
* The length is the count of columns, mapped by the properties in the current entity and from its super entity, and joined columns.
* </p>
*/
private final int[] naturalOrderPropertyTableNumbers;
/**
* Same as above, but here is the index of {@see tableNames}
*
* <p>
* The length is same as above.
* </p>
*/
private final int[] propertyTableNumbers;
// the closure of all properties in the entire hierarchy including
// subclasses and superclasses of this class
/**
* the closure of all properties in the entire hierarchy including
* subclasses and superclasses of this class
*
* The element is the index of {@see subclassTableNameClosure}, which table that the property's relational value belongs to.
*
* <p>
* The length is all the properties count in the entire hierarchy.
* </p>
*
*/
private final int[] subclassPropertyTableNumberClosure;
// the closure of all columns used by the entire hierarchy including
@ -117,11 +282,16 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
private final Object discriminatorValue;
private final String discriminatorSQLString;
// Span of the tables directly mapped by this entity and super-classes, if any
private final int coreTableSpan;
// only contains values for SecondaryTables, ie. not tables part of the "coreTableSpan"
private final boolean[] isNullableTable;
private void assertOptimisticLockStyle() {
if ( optimisticLockStyle() == OptimisticLockStyle.ALL || optimisticLockStyle() == OptimisticLockStyle.DIRTY ) {
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
}
}
//INITIALIZATION:
@SuppressWarnings( {"UnusedDeclaration"})
public JoinedSubclassEntityPersister(
@ -149,14 +319,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
discriminatorSQLString = null;
}
if ( optimisticLockStyle() == OptimisticLockStyle.ALL || optimisticLockStyle() == OptimisticLockStyle.DIRTY ) {
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
}
assertOptimisticLockStyle();
//MULTITABLES
final int idColumnSpan = getIdentifierColumnSpan();
ArrayList tables = new ArrayList();
ArrayList keyColumns = new ArrayList();
ArrayList keyColumnReaders = new ArrayList();
@ -191,7 +358,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
//Span of the tables directly mapped by this entity and super-classes, if any
coreTableSpan = tables.size();
isNullableTable = new boolean[persistentClass.getJoinClosureSpan()];
int tableIndex = 0;
@ -241,7 +407,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
ArrayList isConcretes = new ArrayList();
ArrayList isDeferreds = new ArrayList();
ArrayList isLazies = new ArrayList();
keyColumns = new ArrayList();
titer = persistentClass.getSubclassTableClosureIterator();
while ( titer.hasNext() ) {
@ -262,7 +427,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}
keyColumns.add( key );
}
//Add joins
joinIter = persistentClass.getSubclassJoinClosureIterator();
while ( joinIter.hasNext() ) {
@ -293,7 +457,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
subclassTableSequentialSelect = ArrayHelper.toBooleanArray( isDeferreds );
subclassTableIsLazyClosure = ArrayHelper.toBooleanArray( isLazies );
constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length];
constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][];
int currentPosition = 0;
@ -305,9 +468,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
/**
* Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
* For the Client entity:
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
* added to the meta-data when the annotated entities are processed.
* However, in some instances, for example when generating joins, the CLIENT table needs to be
* However, in some instances, for example when generating joins, the CLIENT table needs to be
* the first table as it will the driving table.
* tableNames -> CLIENT, PERSON
*/
@ -319,12 +482,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
tableKeyColumnReaderTemplates = reverse( naturalOrderTableKeyColumnReaderTemplates, coreTableSpan );
subclassTableNameClosure = reverse( naturalOrderSubclassTableNameClosure, coreTableSpan );
subclassTableKeyColumnClosure = reverse( naturalOrderSubclassTableKeyColumnClosure, coreTableSpan );
spaces = ArrayHelper.join(
tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
);
// Custom sql
customSQLInsert = new String[tableSpan];
customSQLUpdate = new String[tableSpan];
@ -363,7 +524,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
if ( jk != -1 ) {
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
}
joinIter = persistentClass.getJoinClosureIterator();
int j = coreTableSpan;
while ( joinIter.hasNext() ) {
@ -387,6 +547,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
j++;
}
// PROPERTIES
int hydrateSpan = getPropertySpan();
naturalOrderPropertyTableNumbers = new int[hydrateSpan];
@ -412,7 +573,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
ArrayList columnTableNumbers = new ArrayList();
ArrayList formulaTableNumbers = new ArrayList();
ArrayList propTableNumbers = new ArrayList();
iter = persistentClass.getSubclassPropertyClosureIterator();
while ( iter.hasNext() ) {
Property prop = (Property) iter.next();
@ -445,8 +605,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
// SUBCLASSES
int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[subclassSpan - 1] = getEntityName();
if ( persistentClass.isPolymorphic() ) {
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
discriminatorValues = new String[subclassSpan];
@ -470,6 +629,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
notNullColumnNames = null;
}
subclassClosure = new String[subclassSpan];
subclassClosure[subclassSpan - 1] = getEntityName();
iter = persistentClass.getSubclassIterator();
int k = 0;
while ( iter.hasNext() ) {
@ -508,6 +669,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
postConstruct( mapping );
}
@SuppressWarnings( {"UnusedDeclaration"})
public JoinedSubclassEntityPersister(
final EntityBinding entityBinding,
@ -517,104 +680,358 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final Mapping mapping) throws HibernateException {
super( entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory );
// DISCRIMINATOR
if ( entityBinding.isPolymorphic() ) {
try{
discriminatorValue = entityBinding.getSubEntityBindingId();
discriminatorSQLString = discriminatorValue.toString();
} catch ( Exception e ){
throw new MappingException( "Could not format discriminator value to SQL string", e );
assertOptimisticLockStyle();
final boolean isCascadeDeleteDefault = factory.getDialect().supportsCascadeDelete();
final EntityBinding[] entityBindings = entityBinding.getEntityBindingClosure();
final TableSpecification[] tables = entityBinding.getTableClosure();
final SecondaryTable[] secondaryTables = entityBinding.getSecondaryTableClosure();
final String[] synchronizedTableNames = entityBinding.getSynchronizedTableNameClosure();
final AttributeBinding[] attributeBindings = entityBinding.getAttributeBindingClosure();
//todo the count of these two are not equal, which they should be
final EntityBinding[] preOrderSubEntityBindings = entityBinding.getPreOrderSubEntityBindingClosure();
final EntityBinding[] postOrderSubEntityBindings = entityBinding.getPostOrderSubEntityBindingClosure();
final TableSpecification[] subTables = entityBinding.getPreOrderSubTableClosure();
final SecondaryTable[] subSecondaryTables = entityBinding.getSubEntitySecondaryTables();
final AttributeBinding[] allAttributeBindings = entityBinding.getEntitiesAttributeBindingClosure();
final int idColumnSpan = getIdentifierColumnSpan();
coreTableSpan = tables.length;
final int secondaryTableSpan = secondaryTables.length;
tableSpan = coreTableSpan + secondaryTableSpan;
final int subclassSpan = postOrderSubEntityBindings.length;
final int subclassSecondaryTableSpan = subSecondaryTables.length;
final int subTableSpan = subclassSpan + subclassSecondaryTableSpan;
final int allTableSpan = tableSpan + subTableSpan;
final int hydrateSpan = getPropertySpan();
isClassOrSuperclassTable = new boolean[allTableSpan];
subclassTableSequentialSelect = new boolean[allTableSpan];
subclassTableIsLazyClosure = new boolean[allTableSpan];
naturalOrderTableNames = new String[tableSpan];
naturalOrderCascadeDeleteEnabled = new boolean[tableSpan];
naturalOrderTableKeyColumns = new String[tableSpan][];
naturalOrderTableKeyColumnReaders = new String[tableSpan][];
naturalOrderTableKeyColumnReaderTemplates = new String[tableSpan][];
//custom sql
customSQLInsert = new String[tableSpan];
customSQLUpdate = new String[tableSpan];
customSQLDelete = new String[tableSpan];
insertCallable = new boolean[tableSpan];
updateCallable = new boolean[tableSpan];
deleteCallable = new boolean[tableSpan];
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
subclassClosure = new String[subclassSpan+1];
subclassClosure[subclassSpan] = getEntityName();
isNullableTable = new boolean[secondaryTableSpan];
naturalOrderPropertyTableNumbers = new int[hydrateSpan];
propertyTableNumbers = new int[hydrateSpan];
constraintOrderedTableNames = new String[allTableSpan];
constraintOrderedKeyColumnNames = new String[allTableSpan][];
/**
* 1. core table names
* 2. direct sub entity table names
* 3. core joined table names
* 4. direct sub entity joined table names
*/
final String[] naturalOrderSubclassTableNameClosure = new String[allTableSpan];
final String[][] naturalOrderSubclassTableKeyColumnClosure = new String[allTableSpan][];
int tableIndex = 0;
int allTableIndex =0;
//first, process tables / entitybindings mapped directly by the current entitybinding and its super entitybindings
for ( int i = 0; i < coreTableSpan; i++, tableIndex++, allTableIndex++ ) {
final TableSpecification table = tables[i];
naturalOrderTableNames[tableIndex] = table.getQualifiedName( factory.getDialect() );
naturalOrderCascadeDeleteEnabled[tableIndex] = false; //todo fix me @OnDelete
naturalOrderTableKeyColumns[tableIndex] = new String[idColumnSpan];
naturalOrderTableKeyColumnReaders[tableIndex] = new String[idColumnSpan];
naturalOrderTableKeyColumnReaderTemplates[tableIndex] = new String[idColumnSpan];
PrimaryKey primaryKey = table.getPrimaryKey();
resolvePkColumnNames(
factory,
primaryKey,
naturalOrderTableKeyColumns[tableIndex],
naturalOrderTableKeyColumnReaders[tableIndex],
naturalOrderTableKeyColumnReaderTemplates[tableIndex]
);
final EntityBinding eb = entityBindings[i];
//Custom SQL
initializeCustomSql( eb.getCustomInsert(), tableIndex, customSQLInsert, insertCallable, insertResultCheckStyles );
initializeCustomSql( eb.getCustomUpdate(), tableIndex, customSQLUpdate, updateCallable, updateResultCheckStyles );
initializeCustomSql( eb.getCustomDelete(), tableIndex, customSQLDelete, deleteCallable, deleteResultCheckStyles );
isClassOrSuperclassTable[allTableIndex] = true;//EntityBindingHelper.isClassOrSuperclassTable( entityBinding, table );
subclassTableSequentialSelect[allTableIndex] = false;
subclassTableIsLazyClosure[allTableIndex] = false;
}
//#1
System.arraycopy( naturalOrderTableNames, 0, naturalOrderSubclassTableNameClosure, 0, coreTableSpan );
System.arraycopy( naturalOrderTableKeyColumns, 0, naturalOrderSubclassTableKeyColumnClosure, 0, coreTableSpan );
//--------------------------------- directly sub entities
final String[] naturalOrderSubTableNames = new String[subclassSpan];
final String[][] naturalOrderSubTableKeyColumns = new String[subclassSpan][idColumnSpan];
for ( int i = 0; i < subclassSpan; i++, allTableIndex++ ) {
final EntityBinding subEntityBinding = preOrderSubEntityBindings[i]; //todo post order??
final TableSpecification table = subEntityBinding.getPrimaryTable();
naturalOrderSubTableNames[i] = table.getQualifiedName( factory.getDialect() );
final PrimaryKey pk = table.getPrimaryKey();
for(int j=0;j<idColumnSpan;j++){
naturalOrderSubTableKeyColumns[i][j] = pk.getColumns().get( j ).getColumnName().getText( factory.getDialect() );
}
isClassOrSuperclassTable[allTableIndex] = false;//EntityBindingHelper.isClassOrSuperclassTable( entityBinding, table );
subclassTableSequentialSelect[allTableIndex] = false;
subclassTableIsLazyClosure[allTableIndex] = false;
}
//#2
System.arraycopy(
naturalOrderSubTableNames,
0,
naturalOrderSubclassTableNameClosure,
coreTableSpan,
subclassSpan
);
System.arraycopy( naturalOrderSubTableKeyColumns, 0, naturalOrderSubclassTableKeyColumnClosure, coreTableSpan,
subclassSpan );
//--------------------------------- secondary tables
for ( int i = 0; i < secondaryTableSpan; i++,tableIndex++, allTableIndex++ ) {
final SecondaryTable secondaryTable = secondaryTables[i];
final PrimaryKey pk = secondaryTable.getSecondaryTableReference().getPrimaryKey();
naturalOrderTableNames[tableIndex] = secondaryTable.getSecondaryTableReference()
.getQualifiedName( factory.getDialect() );
isNullableTable[i] = secondaryTable.isOptional();
naturalOrderCascadeDeleteEnabled[tableIndex] = secondaryTable.isCascadeDeleteEnabled();
final int secondaryTablePKColumnSpan = secondaryTable.getSecondaryTableReference()
.getPrimaryKey()
.getColumnSpan();
naturalOrderTableKeyColumns[tableIndex] = new String[secondaryTablePKColumnSpan];
naturalOrderTableKeyColumnReaders[tableIndex] = new String[secondaryTablePKColumnSpan];
naturalOrderTableKeyColumnReaderTemplates[tableIndex] = new String[secondaryTablePKColumnSpan];
resolvePkColumnNames(
factory,
pk,
naturalOrderTableKeyColumns[tableIndex],
naturalOrderTableKeyColumnReaders[tableIndex],
naturalOrderTableKeyColumnReaderTemplates[tableIndex]
);
//todo custom sql in secondary table binding
initializeCustomSql(null, tableIndex, customSQLInsert, insertCallable, insertResultCheckStyles);
initializeCustomSql(null, tableIndex, customSQLUpdate, updateCallable, updateResultCheckStyles);
initializeCustomSql(null, tableIndex, customSQLDelete, deleteCallable, deleteResultCheckStyles);
isClassOrSuperclassTable[allTableIndex] = false;//EntityBindingHelper.isClassOrSuperclassTable( entityBinding, table );
subclassTableSequentialSelect[allTableIndex] = secondaryTable.getFetchStyle() == FetchStyle.SELECT;
subclassTableIsLazyClosure[allTableIndex] = secondaryTable.isLazy();
}
//#3
System.arraycopy(
naturalOrderTableNames,
tableSpan - coreTableSpan,
naturalOrderSubclassTableNameClosure,
coreTableSpan + subclassSpan,
secondaryTableSpan
);
System.arraycopy(
naturalOrderTableKeyColumns,
tableSpan - coreTableSpan,
naturalOrderSubclassTableKeyColumnClosure,
coreTableSpan + subclassSpan,
secondaryTableSpan
);
//--------------------------------- direct sub entity secondary tables
final String[] naturalOrderSubSecondaryTableNames = new String[subclassSecondaryTableSpan];
final String[][] naturalOrderSubSecondaryTableKeyColumns = new String[subclassSecondaryTableSpan][];
for ( int i = 0; i < subclassSecondaryTableSpan; i++, allTableIndex++ ) {
final SecondaryTable secondaryTable = subSecondaryTables[i];
naturalOrderSubSecondaryTableNames[i] = secondaryTable.getSecondaryTableReference().getQualifiedName( factory.getDialect() );
final PrimaryKey pk = secondaryTable.getSecondaryTableReference().getPrimaryKey();
naturalOrderSubSecondaryTableKeyColumns[i] = new String[pk.getColumnSpan()];
for(int j =0;j<pk.getColumnSpan();j++){
naturalOrderSubSecondaryTableKeyColumns[i][j]= pk.getColumns().get( j ).getColumnName().getText( factory.getDialect() );
}
isClassOrSuperclassTable[allTableIndex] = false;//EntityBindingHelper.isClassOrSuperclassTable( entityBinding, table );
subclassTableSequentialSelect[allTableIndex] = secondaryTable.getFetchStyle() == FetchStyle.SELECT;
subclassTableIsLazyClosure[allTableIndex] = secondaryTable.isLazy();
}
//#4
System.arraycopy(
naturalOrderSubSecondaryTableNames,
0,
naturalOrderSubclassTableNameClosure,
tableSpan + subclassSpan,
subclassSecondaryTableSpan
);
//#4
System.arraycopy(
naturalOrderSubSecondaryTableKeyColumns,
0,
naturalOrderSubclassTableKeyColumnClosure,
tableSpan + subclassSpan,
subclassSecondaryTableSpan
);
//--------------------------------- core and secondary tables
tableNames = reverse( naturalOrderTableNames, coreTableSpan );
tableKeyColumns = reverse( naturalOrderTableKeyColumns, coreTableSpan );
tableKeyColumnReaders = reverse( naturalOrderTableKeyColumnReaders, coreTableSpan );
tableKeyColumnReaderTemplates = reverse( naturalOrderTableKeyColumnReaderTemplates, coreTableSpan );
spaces = ArrayHelper.join( tableNames, synchronizedTableNames );
//--------------------------------- sub entities
int currentPosition = 0;
for ( int i = allTableSpan - 1; i >= 0; i--, currentPosition++ ) {
constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i];
constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i];
}
subclassTableNameClosure = reverse( naturalOrderSubclassTableNameClosure, coreTableSpan );
subclassTableKeyColumnClosure = reverse( naturalOrderSubclassTableKeyColumnClosure, coreTableSpan );
// PROPERTIES
ArrayList<Integer> columnTableNumbers = new ArrayList<Integer>();
ArrayList<Integer> formulaTableNumbers = new ArrayList<Integer>();
ArrayList<Integer> propTableNumbers = new ArrayList<Integer>();
for(int i=0;i<allAttributeBindings.length;i++){
final AttributeBinding attributeBinding = allAttributeBindings[i];
//if this is identifier, then continue
if ( isIdentifierAttributeBinding( attributeBinding ) ) {
continue;
}
final List<RelationalValueBinding> valueBindings;
if ( SingularAttributeBinding.class.isInstance( attributeBinding ) ) {
SingularAttributeBinding singularAttributeBinding = SingularAttributeBinding.class.cast(
attributeBinding
);
valueBindings = singularAttributeBinding.getRelationalValueBindings();
}
else {
PluralAttributeBinding pluralAttributeBinding = PluralAttributeBinding.class.cast( attributeBinding );
valueBindings = pluralAttributeBinding.getPluralAttributeElementBinding().getRelationalValueBindings();
}
RelationalValueBinding valueBinding = valueBindings.get( 0 );
TableSpecification table = valueBinding.getValue().getTable();
final String tableName = table.getQualifiedName( factory.getDialect() );
if ( i < hydrateSpan ) {
propertyTableNumbers[i] = getTableId( tableName, tableNames );
naturalOrderPropertyTableNumbers[i] = getTableId( tableName, naturalOrderTableNames );
}
final int tableNumberInSubclass = getTableId( tableName, subclassTableNameClosure );
propTableNumbers.add( tableNumberInSubclass );
for ( RelationalValueBinding vb : valueBindings ) {
if ( vb.isDerived() ) {
formulaTableNumbers.add( tableNumberInSubclass );
}
else {
columnTableNumbers.add( tableNumberInSubclass );
}
}
}
subclassColumnTableNumberClosure = ArrayHelper.toIntArray( columnTableNumbers );
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propTableNumbers );
subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaTableNumbers );
// SUBCLASSES
// DISCRIMINATOR
if ( entityBinding.isPolymorphic() ) {
try {
discriminatorValue = entityBinding.getSubEntityBindingId();
discriminatorSQLString = discriminatorValue.toString();
}
catch ( Exception e ) {
throw new MappingException( "Could not format discriminator value to SQL string", e );
}
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
discriminatorValues = new String[subclassSpan+1];
discriminatorValues[subclassSpan] = discriminatorSQLString;
notNullColumnTableNumbers = new int[subclassSpan+1];
final int id = getTableId(
tableNames[0], //the current entitybinding's primary table name
subclassTableNameClosure
);
notNullColumnTableNumbers[subclassSpan] = id;
notNullColumnNames = new String[subclassSpan+1];
notNullColumnNames[subclassSpan] = subclassTableKeyColumnClosure[id][0];
}
else {
discriminatorValues = null;
notNullColumnTableNumbers = null;
notNullColumnNames = null;
discriminatorValue = null;
discriminatorSQLString = null;
}
if ( optimisticLockStyle() == OptimisticLockStyle.ALL || optimisticLockStyle() == OptimisticLockStyle.DIRTY ) {
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
}
final int idColumnSpan = getIdentifierColumnSpan();
ArrayList<String> tables = new ArrayList<String>();
ArrayList keyColumns = new ArrayList();
ArrayList keyColumnReaders = new ArrayList();
ArrayList keyColumnReaderTemplates = new ArrayList();
ArrayList cascadeDeletes = new ArrayList();
Iterator<TableSpecification> titer = entityBinding.getTableClosureIterator();
while ( titer.hasNext() ){
TableSpecification table = titer.next();
String tableName = table.getLogicalName().getText(factory.getDialect());
tables.add( tableName );
String[] keyCols = new String[idColumnSpan];
String[] keyColReaders = new String[idColumnSpan];
String[] keyColReaderTemplates = new String[idColumnSpan];
PrimaryKey primaryKey= table.getPrimaryKey();
for ( int k = 0; k < idColumnSpan; k++ ) {
org.hibernate.metamodel.spi.relational.Column column = primaryKey.getColumns().get( k );
keyCols[k] = column.getColumnName().getText(factory.getDialect());
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
for ( int k = 0; k < postOrderSubEntityBindings.length; k++ ) {
final EntityBinding eb = postOrderSubEntityBindings[k];
subclassClosure[k] = eb.getEntityName();
try {
if ( eb.isPolymorphic() ) {
// we now use subclass ids that are consistent across all
// persisters for a class hierarchy, so that the use of
// "foo.class = Bar" works in HQL
Integer subclassId = eb.getSubEntityBindingId();
subclassesByDiscriminatorValue.put( subclassId, eb.getEntityName() );
discriminatorValues[k] = subclassId.toString();
int id = getTableId(
eb.getPrimaryTable().getQualifiedName( factory.getDialect() ),
subclassTableNameClosure
);
notNullColumnTableNumbers[k] = id;
notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
if(notNullColumnNames[k] == null){
System.out.println();
}
}
}
catch ( Exception e ) {
throw new MappingException( "Error parsing discriminator value", e );
}
keyColumns.add( keyCols );
keyColumnReaders.add( keyColReaders );
keyColumnReaderTemplates.add( keyColReaderTemplates );
cascadeDeletes.add( false && factory.getDialect().supportsCascadeDelete() ); //todo add @OnDelete support
}
//Span of the tables directly mapped by this entity and super-classes, if any
coreTableSpan = tables.size();
//todo secondary table
isNullableTable = new boolean[]{true};
naturalOrderTableNames = ArrayHelper.toStringArray( tables );
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray( keyColumns );
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray( keyColumnReaders );
naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray( keyColumnReaderTemplates );
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray( cascadeDeletes );
ArrayList subtables = new ArrayList();
ArrayList isConcretes = new ArrayList();
ArrayList isDeferreds = new ArrayList();
ArrayList isLazies = new ArrayList();
keyColumns = new ArrayList();
//todo add sub class tables here
//----------------------------------------------
tableSpan = -1;
tableNames = null;
tableKeyColumns = null;
tableKeyColumnReaders = null;
tableKeyColumnReaderTemplates = null;
spaces = null;
subclassClosure = null;
subclassTableNameClosure = null;
subclassTableKeyColumnClosure = null;
isClassOrSuperclassTable = null;
naturalOrderPropertyTableNumbers = null;
propertyTableNumbers = null;
subclassPropertyTableNumberClosure = null;
subclassColumnTableNumberClosure = null;
subclassFormulaTableNumberClosure = null;
subclassTableSequentialSelect = null;
subclassTableIsLazyClosure = null;
discriminatorValues = null;
notNullColumnNames = null;
notNullColumnTableNumbers = null;
constraintOrderedTableNames = null;
constraintOrderedKeyColumnNames = null;
//-----------------------------
initLockers();
initSubclassPropertyAliasesMap( entityBinding );
postConstruct( mapping );
}
protected boolean isNullableTable(int j) {
if ( j < coreTableSpan ) {
return false;
private void resolvePkColumnNames(SessionFactoryImplementor factory, PrimaryKey primaryKey, String[] columns, String[] readers, String[] templates) {
for ( int k = 0; k < primaryKey.getColumnSpan(); k++ ) {
org.hibernate.metamodel.spi.relational.Column column = primaryKey.getColumns().get( k );
columns[k] = column.getColumnName().getText( factory.getDialect() );
readers[k] = column.getReadExpr( factory.getDialect() );
templates[k] = column.getTemplate(
factory.getDialect(),
factory.getSqlFunctionRegistry()
);
}
return isNullableTable[j - coreTableSpan];
}
protected boolean isNullableTable(int j) {
return j >= coreTableSpan && isNullableTable[j - coreTableSpan];
}
protected boolean isSubclassTableSequentialSelect(int j) {
@ -693,14 +1110,12 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
}
}*/
private static final void reverse(Object[] objects, int len) {
private static void reverse(Object[] objects, int len) {
Object[] temp = new Object[len];
for ( int i = 0; i < len; i++ ) {
temp[i] = objects[len - i - 1];
}
for ( int i = 0; i < len; i++ ) {
objects[i] = temp[i];
}
System.arraycopy( temp, 0, objects, 0, len );
}
@ -714,20 +1129,26 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
*/
private static String[] reverse(String[] objects, int n) {
int size = objects.length;
String[] temp = new String[size];
final int size = objects.length;
final String[] temp = new String[size];
for ( int i = 0; i < n; i++ ) {
temp[i] = objects[n - i - 1];
}
for ( int i = n; i < size; i++ ) {
temp[i] = objects[i];
}
System.arraycopy( objects, n, temp, n, size - n );
return temp;
}
public static void main(String[] args) {
String [] array = {"a", "b", "c", "d", "e"};
array = reverse( array, 3 );
for(String s : array){
System.out.println(s);
}
}
/**
* Reverse the first n elements of the incoming array
*
@ -743,9 +1164,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
temp[i] = objects[n - i - 1];
}
for ( int i = n; i < size; i++ ) {
temp[i] = objects[i];
}
System.arraycopy( objects, n, temp, n, size - n );
return temp;
}
@ -870,7 +1289,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
if ( index == null ) {
return null;
}
return tableNames[propertyTableNumbers[index.intValue()]];
return tableNames[propertyTableNumbers[index]];
}
public String[] getConstraintOrderedTableNameClosure() {

View File

@ -35,7 +35,6 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
@ -129,9 +128,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private final String[][] constraintOrderedKeyColumnNames;
//private final Map propertyTableNumbersByName = new HashMap();
private final Map propertyTableNumbersByNameAndSubclass = new HashMap();
private final Map<String, Integer> propertyTableNumbersByNameAndSubclass = new HashMap<String, Integer>();
private final Map sequentialSelectStringsByEntityName = new HashMap();
private final Map<String, String> sequentialSelectStringsByEntityName = new HashMap<String, String>();
private static final Object NULL_DISCRIMINATOR = new MarkerObject("<null discriminator>");
private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject("<not null discriminator>");
@ -546,7 +545,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
isNullables.add(Boolean.FALSE);
isLazies.add(Boolean.FALSE);
for ( SecondaryTable join : entityBinding.getSubclassSecondaryTableClosure() ) {
for ( SecondaryTable join : entityBinding.getEntitiesSecondaryTableClosure() ) {
final boolean isConcrete = entityBinding.isClassOrSuperclassSecondaryTable( join );
isConcretes.add( isConcrete );
boolean isDeferred = join.getFetchStyle() != FetchStyle.JOIN;
@ -672,11 +671,11 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
//TODO: code duplication with JoinedSubclassEntityPersister
ArrayList columnJoinNumbers = new ArrayList();
ArrayList formulaJoinedNumbers = new ArrayList();
ArrayList propertyJoinNumbers = new ArrayList();
ArrayList<Integer> columnJoinNumbers = new ArrayList<Integer>();
ArrayList<Integer> formulaJoinedNumbers = new ArrayList<Integer>();
ArrayList<Integer> propertyJoinNumbers = new ArrayList<Integer>();
for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding attributeBinding : entityBinding.getEntitiesAttributeBindingClosure() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
continue; // skip identifier binding
}
@ -753,18 +752,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
postConstruct( mapping );
}
private static void initializeCustomSql(
CustomSQL customSql,
int i,
String[] sqlStrings,
boolean[] callable,
ExecuteUpdateResultCheckStyle[] checkStyles) {
sqlStrings[i] = customSql != null ? customSql.getSql(): null;
callable[i] = sqlStrings[i] != null && customSql.isCallable();
checkStyles[i] = customSql != null && customSql.getCheckStyle() != null ?
customSql.getCheckStyle() :
ExecuteUpdateResultCheckStyle.determineDefault( sqlStrings[i], callable[i] );
}
protected boolean isInverseTable(int j) {
return isInverseTable[j];
@ -889,9 +876,11 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
String[] subclasses = getSubclassClosure();
for ( int i=0; i<subclasses.length; i++ ) {
final Queryable queryable = (Queryable) getFactory().getEntityPersister( subclasses[i] );
if ( !queryable.isAbstract() ) frag.addValue( queryable.getDiscriminatorSQLValue() );
for ( String subclass : subclasses ) {
final Queryable queryable = (Queryable) getFactory().getEntityPersister( subclass );
if ( !queryable.isAbstract() ) {
frag.addValue( queryable.getDiscriminatorSQLValue() );
}
}
StringBuilder buf = new StringBuilder(50)
@ -966,12 +955,12 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private int getSubclassPropertyTableNumber(String propertyName, String entityName) {
Type type = propertyMapping.toType(propertyName);
if ( type.isAssociationType() && ( (AssociationType) type ).useLHSPrimaryKey() ) return 0;
final Integer tabnum = (Integer) propertyTableNumbersByNameAndSubclass.get(entityName + '.' + propertyName);
return tabnum==null ? 0 : tabnum.intValue();
final Integer tabnum = propertyTableNumbersByNameAndSubclass.get(entityName + '.' + propertyName);
return tabnum==null ? 0 : tabnum;
}
protected String getSequentialSelect(String entityName) {
return (String) sequentialSelectStringsByEntityName.get(entityName);
return sequentialSelectStringsByEntityName.get(entityName);
}
private String generateSequentialSelect(Loadable persister) {
@ -982,7 +971,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
//figure out which tables need to be fetched
AbstractEntityPersister subclassPersister = (AbstractEntityPersister) persister;
HashSet tableNumbers = new HashSet();
HashSet<Integer> tableNumbers = new HashSet<Integer>();
String[] props = subclassPersister.getPropertyNames();
String[] classes = subclassPersister.getPropertySubclassNames();
for ( int i=0; i<props.length; i++ ) {
@ -994,7 +983,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
if ( tableNumbers.isEmpty() ) return null;
//figure out which columns are needed
ArrayList columnNumbers = new ArrayList();
ArrayList<Integer> columnNumbers = new ArrayList<Integer>();
final int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
for ( int i=0; i<getSubclassColumnClosure().length; i++ ) {
if ( tableNumbers.contains( columnTableNumbers[i] ) ) {
@ -1003,7 +992,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
//figure out which formulas are needed
ArrayList formulaNumbers = new ArrayList();
ArrayList<Integer> formulaNumbers = new ArrayList<Integer>();
final int[] formulaTableNumbers = getSubclassColumnTableNumberClosure();
for ( int i=0; i<getSubclassFormulaTemplateClosure().length; i++ ) {
if ( tableNumbers.contains( formulaTableNumbers[i] ) ) {
@ -1051,7 +1040,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
public String getPropertyTableName(String propertyName) {
Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
if (index==null) return null;
return qualifiedTableNames[ propertyTableNumbers[ index.intValue() ] ];
return qualifiedTableNames[ propertyTableNumbers[ index ] ];
}
public void postInstantiate() {

View File

@ -53,9 +53,7 @@ import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.InheritanceType;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.sql.SelectFragment;
@ -247,29 +245,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
}
private static class CustomSQLMetadata {
final boolean[] callable;
final String[] sqls;
final ExecuteUpdateResultCheckStyle[] checkStyles;
CustomSQLMetadata(String sql, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.callable = new boolean[] { callable };
this.sqls = new String[] { sql };
this.checkStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
}
}
private CustomSQLMetadata parse(CustomSQL customSql) {
final boolean callable = customSql != null && customSql.isCallable();
final String sql = customSql == null ? null: customSql.getSql();
final ExecuteUpdateResultCheckStyle checkStyle = customSql == null
? ExecuteUpdateResultCheckStyle.COUNT
: customSql.getCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: customSql.getCheckStyle();
return new CustomSQLMetadata( sql, callable, checkStyle );
}
@SuppressWarnings( {"UnusedDeclaration"})
public UnionSubclassEntityPersister(
@ -290,27 +266,20 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
//Custom SQL
{
CustomSQLMetadata customSQLMetadata;
{
customSQLMetadata = parse( entityBinding.getCustomInsert() );
customSQLInsert = customSQLMetadata.sqls;
insertCallable = customSQLMetadata.callable;
insertResultCheckStyles = customSQLMetadata.checkStyles;
}
{
customSQLMetadata = parse( entityBinding.getCustomUpdate() );
customSQLUpdate = customSQLMetadata.sqls;
updateCallable = customSQLMetadata.callable;
updateResultCheckStyles = customSQLMetadata.checkStyles;
}
{
customSQLMetadata = parse( entityBinding.getCustomDelete() );
customSQLDelete = customSQLMetadata.sqls;
deleteCallable = customSQLMetadata.callable;
deleteResultCheckStyles = customSQLMetadata.checkStyles;
}
}
// Custom sql
customSQLInsert = new String[1];
customSQLUpdate = new String[1];
customSQLDelete = new String[1];
insertCallable = new boolean[1];
updateCallable = new boolean[1];
deleteCallable = new boolean[1];
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];
initializeCustomSql( entityBinding.getCustomInsert(), 0, customSQLInsert, insertCallable, insertResultCheckStyles );
initializeCustomSql( entityBinding.getCustomUpdate(), 0, customSQLUpdate, updateCallable, updateResultCheckStyles );
initializeCustomSql( entityBinding.getCustomDelete(), 0, customSQLDelete, deleteCallable, deleteResultCheckStyles );
//discriminator
{
discriminatorValue = entityBinding.getSubEntityBindingId();
@ -329,9 +298,8 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
entityBinding.getEntityName()
);
if ( entityBinding.isPolymorphic() ) {
Iterable<EntityBinding> iter = entityBinding.getPreOrderSubEntityBindingClosure();
int k=1;
for(EntityBinding subEntityBinding : iter){
for(EntityBinding subEntityBinding : entityBinding.getPreOrderSubEntityBindingClosure()){
subclassClosure[k++] = subEntityBinding.getEntityName();
subclassByDiscriminatorValue.put( subEntityBinding.getSubEntityBindingId(), subEntityBinding.getEntityName() );
}
@ -351,8 +319,8 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
}
HashSet<String> subclassTables = new HashSet<String>();
Iterable<EntityBinding> iter = entityBinding.getPreOrderSubEntityBindingClosure();
for ( EntityBinding subEntityBinding : iter ) {
final EntityBinding[] subEntityBindings = entityBinding.getPreOrderSubEntityBindingClosure();
for ( EntityBinding subEntityBinding : entityBinding.getPreOrderSubEntityBindingClosure() ) {
subclassTables.add( subEntityBinding.getPrimaryTable().getQualifiedName( factory.getDialect() ) );
}
subclassSpaces = ArrayHelper.toStringArray( subclassTables );
@ -367,12 +335,8 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
tableNames.add( tableName );
keyColumns.add( getIdentifierColumnNames() );
}
Iterator<EntityBinding> siter = new JoinedIterator<EntityBinding>(
new SingletonIterator<EntityBinding>( entityBinding ),
iter.iterator()
);
while ( siter.hasNext() ) {
EntityBinding eb = siter.next();
EntityBinding[] ebs = ArrayHelper.join( new EntityBinding[]{entityBinding}, subEntityBindings );
for(final EntityBinding eb : ebs){
TableSpecification tab = eb.getPrimaryTable();
if ( isNotAbstractUnionTable( eb ) ) {
String tableName = tab.getQualifiedName( factory.getDialect() );

View File

@ -412,7 +412,9 @@ public class EntityMetamodel implements Serializable {
else {
identifierAttributeBindingSpan = 1;
}
propertySpan = entityBinding.getAttributeBindingClosureSpan() - identifierAttributeBindingSpan;
final AttributeBinding [] attributeBindings = entityBinding.getAttributeBindingClosure();
propertySpan = attributeBindings.length;
properties = new StandardProperty[propertySpan];
List naturalIdNumbers = new ArrayList();
@ -442,7 +444,7 @@ public class EntityMetamodel implements Serializable {
boolean foundUpdateGeneratedValue = false;
boolean foundUpdateableNaturalIdProperty = false;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
for ( AttributeBinding attributeBinding : attributeBindings ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
// skip the identifier attribute binding
continue;

View File

@ -124,8 +124,8 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertFalse( noInheritanceEntityBinding.isPolymorphic() );
assertFalse( noInheritanceEntityBinding.hasSubEntityBindings() );
assertEquals( 0, noInheritanceEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( noInheritanceEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertFalse( noInheritanceEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
assertEquals( 0, noInheritanceEntityBinding.getPostOrderSubEntityBindingClosure().length );
assertEquals( 0, noInheritanceEntityBinding.getPreOrderSubEntityBindingClosure().length );
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : noInheritanceEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
@ -140,14 +140,17 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
iterator = noInheritanceEntityBinding.getAttributeBindingClosure().iterator();
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
iterator = noInheritanceEntityBinding.getSubEntityAttributeBindingClosure().iterator();
assertTrue( iterator.hasNext() );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), iterator.next() );
assertFalse( iterator.hasNext() );
AttributeBinding[] attributeBindings = noInheritanceEntityBinding.getAttributeBindingClosure();
assertTrue( attributeBindings.length > 0 );
int index =0;
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), attributeBindings[index++] );
assertFalse( index < attributeBindings.length );
attributeBindings = noInheritanceEntityBinding.getEntitiesAttributeBindingClosure();
index = 0;
assertTrue( attributeBindings.length > 0 );
assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding(), attributeBindings[index++] );
assertFalse( index < attributeBindings.length );
}
@Test
@ -198,7 +201,7 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertEquals( 1, attributeBindingClosure.size() );
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : rootEntityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding subAttributeBinding : rootEntityBinding.getEntitiesAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 4, subAttributeBindings.size() );
@ -225,23 +228,24 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
Iterator<EntityBinding> directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator();
boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next();
assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> subEntityBindingIterator = rootEntityBinding.getPreOrderSubEntityBindingClosure().iterator();
assertTrue( subEntityBindingIterator.hasNext() );
EntityBinding[] subEntityBindingIterator = rootEntityBinding.getPreOrderSubEntityBindingClosure();
assertTrue( subEntityBindingIterator.length > 0 );
int i = 0;
if ( isSubclassEntityBindingFirst ) {
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassEntityBinding, subEntityBindingIterator[i++] );
assertTrue( i<subEntityBindingIterator.length );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator[i++] );
assertTrue( i<subEntityBindingIterator.length );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator[i++] );
}
else {
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertTrue( subEntityBindingIterator.hasNext() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator[i++] );
assertTrue( i<subEntityBindingIterator.length );
assertSame( subclassEntityBinding, subEntityBindingIterator[i++] );
assertTrue( i<subEntityBindingIterator.length );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator[i++] );
}
assertFalse( subEntityBindingIterator.hasNext() );
assertFalse( i<subEntityBindingIterator.length );
}
@Test
@ -261,19 +265,20 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
Iterator<EntityBinding> directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator();
boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next();
assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> subEntityBindingIterator = rootEntityBinding.getPostOrderSubEntityBindingClosure().iterator();
assertTrue( subEntityBindingIterator.hasNext() );
EntityBinding[] subEntityBindingIterator = rootEntityBinding.getPostOrderSubEntityBindingClosure();
int i =0;
assertTrue( subEntityBindingIterator.length > 0 );
if ( isSubclassEntityBindingFirst ) {
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator[i++] );
assertSame( subclassEntityBinding, subEntityBindingIterator[i++] );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator[i++] );
}
else {
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassEntityBinding, subEntityBindingIterator.next() );
assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator[i++] );
assertSame( otherSubclassEntityBinding, subEntityBindingIterator[i++] );
assertSame( subclassEntityBinding, subEntityBindingIterator[i++] );
}
assertFalse( subEntityBindingIterator.hasNext() );
assertFalse( i < subEntityBindingIterator.length );
}
@Test
@ -297,8 +302,8 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( otherSubclassEntityBinding.isPolymorphic() );
assertFalse( otherSubclassEntityBinding.hasSubEntityBindings() );
assertEquals( 0, otherSubclassEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( otherSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertFalse( otherSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
assertFalse( otherSubclassEntityBinding.getPostOrderSubEntityBindingClosure().length > 0 );
assertFalse( otherSubclassEntityBinding.getPreOrderSubEntityBindingClosure().length > 0 );
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
@ -314,7 +319,7 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( attributeBindingClosure.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : otherSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding subAttributeBinding : otherSubclassEntityBinding.getEntitiesAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 2, subAttributeBindings.size() );
@ -343,14 +348,16 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( subclassEntityBinding.isPolymorphic() );
assertTrue( subclassEntityBinding.hasSubEntityBindings() );
assertEquals( 1, subclassEntityBinding.getSubEntityBindingClosureSpan() );
Iterator<EntityBinding> itSubEntityBindings = subclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator();
assertTrue( itSubEntityBindings.hasNext() );
assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() );
assertFalse( itSubEntityBindings.hasNext() );
itSubEntityBindings = subclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator();
assertTrue( itSubEntityBindings.hasNext() );
assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() );
assertFalse( itSubEntityBindings.hasNext() );
EntityBinding[] itSubEntityBindings = subclassEntityBinding.getPostOrderSubEntityBindingClosure();
int i = 0;
assertTrue( i < itSubEntityBindings.length );
assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings[i++] );
assertFalse( i < itSubEntityBindings.length );
itSubEntityBindings = subclassEntityBinding.getPreOrderSubEntityBindingClosure();
i = 0;
assertTrue( i < itSubEntityBindings.length );
assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings[i++] );
assertFalse( i < itSubEntityBindings.length );
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
@ -366,7 +373,7 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) );
assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : subclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding subAttributeBinding : subclassEntityBinding.getEntitiesAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 3, subAttributeBindings.size() );
@ -396,8 +403,8 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( subclassOfSubclassEntityBinding.isPolymorphic() );
assertFalse( subclassOfSubclassEntityBinding.hasSubEntityBindings() );
assertEquals( 0, subclassOfSubclassEntityBinding.getSubEntityBindingClosureSpan() );
assertFalse( subclassOfSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() );
assertFalse( subclassOfSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() );
assertFalse( subclassOfSubclassEntityBinding.getPostOrderSubEntityBindingClosure().length > 0 );
assertFalse( subclassOfSubclassEntityBinding.getPreOrderSubEntityBindingClosure().length > 0 );
Set<AttributeBinding> directAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.attributeBindings() ) {
assertTrue( directAttributeBindings.add( attributeBinding ) );
@ -414,7 +421,7 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) );
assertTrue( attributeBindingClosure.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) );
Set<AttributeBinding> subAttributeBindings = new HashSet<AttributeBinding>();
for ( AttributeBinding subAttributeBinding : subclassOfSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) {
for ( AttributeBinding subAttributeBinding : subclassOfSubclassEntityBinding.getEntitiesAttributeBindingClosure() ) {
assertTrue( subAttributeBindings.add( subAttributeBinding ) );
}
assertEquals( 3, subAttributeBindings.size() );

View File

@ -28,13 +28,11 @@ import java.util.Date;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class IndexTest extends BaseCoreFunctionalTestCase {
@Test
public void testIndexManyToOne() throws Exception {

View File

@ -58,7 +58,7 @@ public class OrmVersion1SupportedTest extends BaseCoreFunctionalTestCase {
@FailureExpectedWithNewMetamodel // This doesn't actually work since this test class requires BMUnitRunner instead of
// CustomRunner. Thus, the if block below skips the test if the new metamodel is being used.
public void testOrm1Support() {
if ( Boolean.getBoolean( USE_NEW_METADATA_MAPPINGS ) ) {
if ( isMetadataUsed ) {
return;
}
// need to call buildSessionFactory, because this test is not using org.hibernate.testing.junit4.CustomRunner

View File

@ -27,7 +27,6 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -35,7 +34,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
* @author Emmanuel Bernard
*/
@RequiresDialectFeature(DialectChecks.SupportsIdentityColumns.class)
@FailureExpectedWithNewMetamodel
public class HbmWithIdentityTest extends BaseCoreFunctionalTestCase {
@Test
public void testManyToOneAndInterface() throws Exception {

View File

@ -26,13 +26,11 @@ package org.hibernate.test.collection.ordered.joinedInheritence;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Steve Ebersole
*/
@FailureExpectedWithNewMetamodel
public class OrderCollectionOfJoinedHierarchyTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -59,7 +59,7 @@ import static org.junit.Assert.assertTrue;
@SuppressWarnings( {"UnnecessaryUnboxing", "UnnecessaryBoxing"})
@FailureExpectedWithNewMetamodel
//@FailureExpectedWithNewMetamodel
public class SQLFunctionsTest extends LegacyTestCase {
private static final Logger log = Logger.getLogger( SQLFunctionsTest.class );
@ -217,6 +217,7 @@ public class SQLFunctionsTest extends LegacyTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testBroken() throws Exception {
Session s = openSession();
Transaction t = s.beginTransaction();

View File

@ -26,7 +26,6 @@ package org.hibernate.test.naturalid.inheritance;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertNotNull;
@ -36,7 +35,6 @@ import static org.junit.Assert.assertSame;
/**
* @author Steve Ebersole
*/
@FailureExpectedWithNewMetamodel
public class InheritedNaturalIdTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -43,7 +43,7 @@ import static org.junit.Assert.assertTrue;
*
* @author Gail Badner
*/
@FailureExpectedWithNewMetamodel
public class GetHqlQueryPlanTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {
@ -82,7 +82,7 @@ public class GetHqlQueryPlanTest extends BaseCoreFunctionalTestCase {
s.close();
}
@FailureExpectedWithNewMetamodel
@Test
@SuppressWarnings( {"UnnecessaryBoxing"})
public void testHqlQueryPlanWithEnabledFilter() {

View File

@ -5,7 +5,7 @@
<hibernate-mapping default-lazy="false">
<class name="org.hibernate.test.legacy.Blobber" dynamic-update="true">
<id name="id">
<generator class="hilo"/>
<generator class="seqhilo"/>
</id>
<property name="blob" column="blob_"/>
<property name="clob" column="clob_"/>

View File

@ -29,6 +29,7 @@ import java.util.List;
import org.jboss.logging.Logger;
import org.hibernate.EntityMode;
import org.hibernate.MappingException;
import org.hibernate.jpa.event.spi.jpa.Callback;
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
@ -62,29 +63,29 @@ public class CallbackProcessorImpl implements CallbackProcessor {
@Override
public void processCallbacksForEntity(Object entityObject, CallbackRegistryImpl callbackRegistry) {
final EntityBinding entityBinding = (EntityBinding) entityObject;
final String entityClassName = entityBinding.getEntity().getClassName();
if ( entityClassName == null ) {
if ( entityBinding.getHierarchyDetails().getEntityMode() != EntityMode.POJO ) {
return;
}
try {
final Class entityClass = classLoaderService.classForName( entityClassName );
for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) {
callbackRegistry.addEntityCallbacks(
entityClass,
annotationClass,
collectCallbacks( entityBinding, entityClass, annotationClass )
);
}
}
catch (ClassLoadingException e) {
throw new MappingException( "entity class not found: " + entityClassName, e );
final Class entityClass = entityBinding.getEntity().getClassReference();
for ( Class annotationClass : CALLBACK_ANNOTATION_CLASSES ) {
callbackRegistry.addEntityCallbacks(
entityClass,
annotationClass,
collectCallbacks( entityBinding, entityClass, annotationClass )
);
}
}
private final static Callback[] EMPTY_CALLBACK = new Callback[0];
private Callback[] collectCallbacks(EntityBinding entityBinding, Class entityClass, Class annotationClass) {
final List<Callback> callbacks = new ArrayList<Callback>();
for ( JpaCallbackSource jpaCallbackClass : entityBinding.getJpaCallbackClasses() ) {
if ( entityBinding.getJpaCallbackClasses() == null || entityBinding.getJpaCallbackClasses().isEmpty() ) {
return EMPTY_CALLBACK;
}
final int size = entityBinding.getJpaCallbackClasses().size();
final Callback[] result = new Callback[size];
for ( int i = 0; i < size; i++ ) {
final JpaCallbackSource jpaCallbackClass = entityBinding.getJpaCallbackClasses().get( i );
final Class listenerClass = classLoaderService.classForName( jpaCallbackClass.getName() );
final String methodName = jpaCallbackClass.getCallbackMethod( annotationClass );
@ -100,9 +101,9 @@ public class CallbackProcessorImpl implements CallbackProcessor {
? createListenerCallback( listenerClass, entityClass, methodName )
: createBeanCallback( listenerClass, methodName );
assert callback != null;
callbacks.add(callback);
result[i] = callback;
}
return callbacks.toArray(new Callback[callbacks.size()]);
return result;
}
private Callback createListenerCallback(
@ -141,24 +142,32 @@ public class CallbackProcessorImpl implements CallbackProcessor {
return null;
}
private Callback createBeanCallback( Class<?> callbackClass,
String methodName ) {
private Callback createBeanCallback(Class<?> callbackClass,
String methodName) {
Class<?> callbackSuperclass = callbackClass.getSuperclass();
if (callbackSuperclass != null) {
Callback callback = createBeanCallback(callbackSuperclass, methodName);
if (callback != null) return callback;
if ( callbackSuperclass != null ) {
Callback callback = createBeanCallback( callbackSuperclass, methodName );
if ( callback != null ) {
return callback;
}
}
for (Method method : callbackClass.getDeclaredMethods()) {
if (!method.getName().equals(methodName)) continue;
if (method.getParameterTypes().length != 0) continue;
if (!method.isAccessible()) method.setAccessible(true);
return new EntityCallback(method);
for ( Method method : callbackClass.getDeclaredMethods() ) {
if ( !method.getName().equals( methodName ) ) {
continue;
}
if ( method.getParameterTypes().length != 0 ) {
continue;
}
if ( !method.isAccessible() ) {
method.setAccessible( true );
}
return new EntityCallback( method );
}
return null;
}
@Override
public void release() {
//To change body of implemented methods use File | Settings | File Templates.
// N/A
}
}

View File

@ -33,6 +33,7 @@ import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import java.util.HashMap;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.event.spi.jpa.Callback;
import org.hibernate.jpa.event.spi.jpa.CallbackRegistry;
@ -59,11 +60,7 @@ public class CallbackRegistryImpl implements CallbackRegistry {
@Override
public boolean hasPostCreateCallbacks(Class entityClass) {
return notEmpty( preCreates.get( entityClass ) );
}
private boolean notEmpty(Callback[] callbacks) {
return callbacks != null && callbacks.length > 0;
return CollectionHelper.isNotEmpty( preCreates.get( entityClass ) );
}
@Override
@ -78,7 +75,7 @@ public class CallbackRegistryImpl implements CallbackRegistry {
@Override
public boolean hasPostUpdateCallbacks(Class entityClass) {
return notEmpty( postUpdates.get( entityClass ) );
return CollectionHelper.isNotEmpty( postUpdates.get( entityClass ) );
}
@Override
@ -93,7 +90,7 @@ public class CallbackRegistryImpl implements CallbackRegistry {
@Override
public boolean hasPostRemoveCallbacks(Class entityClass) {
return notEmpty( postRemoves.get( entityClass ) );
return CollectionHelper.isNotEmpty( postRemoves.get( entityClass ) );
}
@Override
@ -107,7 +104,7 @@ public class CallbackRegistryImpl implements CallbackRegistry {
}
private boolean callback(Callback[] callbacks, Object bean) {
if ( callbacks != null && callbacks.length != 0 ) {
if ( CollectionHelper.isNotEmpty( callbacks ) ) {
for ( Callback callback : callbacks ) {
callback.performCallback( bean );
}