fix initialization of SingleTableEntityPersister to be eager

This commit is contained in:
Gavin King 2022-01-31 21:36:44 +01:00
parent dcd7ebbb56
commit 5a549ea5b4
4 changed files with 120 additions and 134 deletions

View File

@ -36,6 +36,7 @@ public final class ArrayHelper {
return -1; return -1;
} }
@SuppressWarnings("unchecked")
public static <T> T[] filledArray(T value, Class<T> valueJavaType, int size) { public static <T> T[] filledArray(T value, Class<T> valueJavaType, int size) {
final T[] array = (T[]) Array.newInstance( valueJavaType, size ); final T[] array = (T[]) Array.newInstance( valueJavaType, size );
Arrays.fill( array, value ); Arrays.fill( array, value );
@ -79,6 +80,10 @@ public final class ArrayHelper {
return coll.toArray( EMPTY_STRING_ARRAY ); return coll.toArray( EMPTY_STRING_ARRAY );
} }
public static Object[] toObjectArray(Collection<Object> coll) {
return coll.toArray( EMPTY_OBJECT_ARRAY );
}
public static String[][] to2DStringArray(Collection<String[]> coll) { public static String[][] to2DStringArray(Collection<String[]> coll) {
return coll.toArray( new String[0][] ); return coll.toArray( new String[0][] );
} }
@ -102,11 +107,11 @@ public final class ArrayHelper {
} }
public static boolean[] toBooleanArray(Collection<Boolean> coll) { public static boolean[] toBooleanArray(Collection<Boolean> coll) {
Iterator iter = coll.iterator(); Iterator<Boolean> iter = coll.iterator();
boolean[] arr = new boolean[coll.size()]; boolean[] arr = new boolean[coll.size()];
int i = 0; int i = 0;
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
arr[i++] = (Boolean) iter.next(); arr[i++] = iter.next();
} }
return arr; return arr;
} }
@ -116,17 +121,17 @@ public final class ArrayHelper {
} }
//Arrays.asList doesn't do primitive arrays //Arrays.asList doesn't do primitive arrays
public static List toList(Object array) { // public static List toList(Object array) {
if ( array instanceof Object[] ) { // if ( array instanceof Object[] ) {
return Arrays.asList( (Object[]) array ); //faster? // return Arrays.asList( (Object[]) array ); //faster?
} // }
int size = Array.getLength( array ); // int size = Array.getLength( array );
ArrayList list = new ArrayList( size ); // ArrayList<Object> list = new ArrayList<>( size );
for ( int i = 0; i < size; i++ ) { // for ( int i = 0; i < size; i++ ) {
list.add( Array.get( array, i ) ); // list.add( Array.get( array, i ) );
} // }
return list; // return list;
} // }
public static String[] slice(String[] strings, int begin, int length) { public static String[] slice(String[] strings, int begin, int length) {
String[] result = new String[length]; String[] result = new String[length];
@ -140,8 +145,8 @@ public final class ArrayHelper {
return result; return result;
} }
public static List toList(Iterator iter) { public static <T> List<T> toList(Iterator<T> iter) {
List list = new ArrayList(); List<T> list = new ArrayList<>();
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
list.add( iter.next() ); list.add( iter.next() );
} }

View File

@ -25,6 +25,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.DynamicFilterAliasGenerator; import org.hibernate.internal.DynamicFilterAliasGenerator;
import org.hibernate.internal.FilterAliasGenerator; import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.util.MarkerObject; import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
@ -128,6 +129,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
//private final Map propertyTableNumbersByName = new HashMap(); //private final Map propertyTableNumbersByName = new HashMap();
// private final Map<String, Integer> propertyTableNumbersByNameAndSubclass; // private final Map<String, Integer> propertyTableNumbersByNameAndSubclass;
private final String[] fullDiscriminatorSQLValues;
private final Object[] fullDiscriminatorValues;
private static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" ); private static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" );
private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" ); private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" );
@ -293,7 +297,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// DISCRIMINATOR // DISCRIMINATOR
if ( persistentClass.isPolymorphic() ) { if ( persistentClass.isPolymorphic() ) {
Value discrimValue = persistentClass.getDiscriminator(); final Value discrimValue = persistentClass.getDiscriminator();
if ( discrimValue == null ) { if ( discrimValue == null ) {
throw new MappingException( "discriminator mapping required for single table polymorphic persistence" ); throw new MappingException( "discriminator mapping required for single table polymorphic persistence" );
} }
@ -318,37 +322,10 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// discriminatorFormula = null; // discriminatorFormula = null;
discriminatorFormulaTemplate = null; discriminatorFormulaTemplate = null;
} }
discriminatorType = (BasicType<?>) persistentClass.getDiscriminator().getType(); discriminatorType = getDiscriminatorType( persistentClass );
if ( persistentClass.isDiscriminatorValueNull() ) { discriminatorValue = getDiscriminatorValue( persistentClass );
discriminatorValue = NULL_DISCRIMINATOR; discriminatorSQLValue = getDiscriminatorSQLValue( persistentClass, dialect, factory );
discriminatorSQLValue = InFragment.NULL; discriminatorInsertable = isDiscriminatorInsertable( persistentClass );
discriminatorInsertable = false;
}
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
discriminatorValue = NOT_NULL_DISCRIMINATOR;
discriminatorSQLValue = InFragment.NOT_NULL;
discriminatorInsertable = false;
}
else {
discriminatorInsertable = persistentClass.isDiscriminatorInsertable() && !discrimValue.hasFormula();
try {
discriminatorValue = discriminatorType.getJavaTypeDescriptor()
.fromString( persistentClass.getDiscriminatorValue() );
JdbcLiteralFormatter literalFormatter = discriminatorType.getJdbcType()
.getJdbcLiteralFormatter( discriminatorType.getJavaTypeDescriptor() );
discriminatorSQLValue = literalFormatter.toJdbcLiteral(
discriminatorValue,
dialect,
factory.getWrapperOptions()
);
}
catch (ClassCastException cce) {
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
}
catch (Exception e) {
throw new MappingException( "Could not format discriminator value to SQL string", e );
}
}
} }
else { else {
forceDiscriminator = false; forceDiscriminator = false;
@ -407,6 +384,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaJoinedNumbers ); // subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaJoinedNumbers );
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propertyJoinNumbers ); subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propertyJoinNumbers );
final List<Object> values = new ArrayList<>();
final List<String> sqlValues = new ArrayList<>();
int subclassSpan = persistentClass.getSubclassSpan() + 1; int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan]; subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName(); subclassClosure[0] = getEntityName();
@ -416,53 +395,106 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
discriminatorValue, discriminatorValue,
getEntityName() getEntityName()
); );
}
// SUBCLASSES if ( !getEntityMetamodel().isAbstract() ) {
if ( persistentClass.isPolymorphic() ) { values.add( discriminatorValue );
sqlValues.add( discriminatorSQLValue );
}
// SUBCLASSES
int k = 1; int k = 1;
for ( Subclass subclass : persistentClass.getSubclasses() ) { for ( Subclass subclass : persistentClass.getSubclasses() ) {
subclassClosure[k++] = subclass.getEntityName(); subclassClosure[k++] = subclass.getEntityName();
if ( subclass.isDiscriminatorValueNull() ) { Object subclassDiscriminatorValue = getDiscriminatorValue( subclass );
addSubclassByDiscriminatorValue( addSubclassByDiscriminatorValue(
subclassesByDiscriminatorValueLocal, subclassesByDiscriminatorValueLocal,
NULL_DISCRIMINATOR, subclassDiscriminatorValue,
subclass.getEntityName() subclass.getEntityName()
); );
}
else if ( subclass.isDiscriminatorValueNotNull() ) { //copy/paste from EntityMetamodel:
addSubclassByDiscriminatorValue( boolean subclassAbstract = subclass.isAbstract() == null
subclassesByDiscriminatorValueLocal, ? subclass.hasPojoRepresentation() && ReflectHelper.isAbstractClass( subclass.getMappedClass() )
NOT_NULL_DISCRIMINATOR, : subclass.isAbstract();
subclass.getEntityName()
); if ( !subclassAbstract ) {
} values.add(subclassDiscriminatorValue);
else { sqlValues.add( getDiscriminatorSQLValue( subclass, dialect, factory ) );
try {
addSubclassByDiscriminatorValue(
subclassesByDiscriminatorValueLocal,
discriminatorType.getJavaTypeDescriptor()
.fromString( subclass.getDiscriminatorValue() ),
subclass.getEntityName()
);
}
catch (ClassCastException cce) {
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
}
catch (Exception e) {
throw new MappingException( "Error parsing discriminator value", e );
}
} }
} }
} }
// Don't hold a reference to an empty HashMap: // Don't hold a reference to an empty HashMap:
subclassesByDiscriminatorValue = CollectionHelper.toSmallMap( subclassesByDiscriminatorValueLocal ); subclassesByDiscriminatorValue = CollectionHelper.toSmallMap( subclassesByDiscriminatorValueLocal );
fullDiscriminatorSQLValues = ArrayHelper.toStringArray( sqlValues );
fullDiscriminatorValues = ArrayHelper.toObjectArray( values );
initSubclassPropertyAliasesMap( persistentClass ); initSubclassPropertyAliasesMap( persistentClass );
postConstruct( creationContext.getMetadata() ); postConstruct( creationContext.getMetadata() );
}
private static BasicType<?> getDiscriminatorType(PersistentClass persistentClass) {
Type discriminatorType = persistentClass.getDiscriminator().getType();
if ( discriminatorType instanceof BasicType ) {
return (BasicType<?>) discriminatorType;
}
else {
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
}
}
private static String getDiscriminatorSQLValue(
PersistentClass persistentClass,
Dialect dialect,
SessionFactoryImplementor factory) {
if ( persistentClass.isDiscriminatorValueNull() ) {
return InFragment.NULL;
}
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
return InFragment.NOT_NULL;
}
else {
BasicType<?> discriminatorType = getDiscriminatorType( persistentClass );
Object discriminatorValue = getDiscriminatorValue( persistentClass );
try {
JdbcLiteralFormatter literalFormatter = discriminatorType.getJdbcType()
.getJdbcLiteralFormatter( discriminatorType.getJavaTypeDescriptor() );
return literalFormatter.toJdbcLiteral(
discriminatorValue,
dialect,
factory.getWrapperOptions()
);
}
catch (Exception e) {
throw new MappingException( "Could not format discriminator value to SQL string", e );
}
}
}
private static Object getDiscriminatorValue(PersistentClass persistentClass) {
if ( persistentClass.isDiscriminatorValueNull() ) {
return NULL_DISCRIMINATOR;
}
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
return NOT_NULL_DISCRIMINATOR;
}
else {
BasicType<?> discriminatorType = getDiscriminatorType( persistentClass );
try {
return discriminatorType.getJavaTypeDescriptor().fromString( persistentClass.getDiscriminatorValue() );
}
catch (Exception e) {
throw new MappingException( "Could not parse discriminator value", e );
}
}
}
private static boolean isDiscriminatorInsertable(PersistentClass persistentClass) {
return !persistentClass.isDiscriminatorValueNull()
&& !persistentClass.isDiscriminatorValueNotNull()
&& persistentClass.isDiscriminatorInsertable()
&& !persistentClass.getDiscriminator().hasFormula();
} }
private static void addSubclassByDiscriminatorValue(Map<Object, String> subclassesByDiscriminatorValue, Object discriminatorValue, String entityName) { private static void addSubclassByDiscriminatorValue(Map<Object, String> subclassesByDiscriminatorValue, Object discriminatorValue, String entityName) {
@ -632,12 +664,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
frag.setColumn( alias, getDiscriminatorColumnName() ); frag.setColumn( alias, getDiscriminatorColumnName() );
} }
if ( hasTreatAs ) { frag.addValues( hasTreatAs ? decodeTreatAsRequests( treatAsDeclarations ) : fullDiscriminatorSQLValues );
frag.addValues( decodeTreatAsRequests( treatAsDeclarations ) );
}
else {
frag.addValues( fullDiscriminatorSQLValues() );
}
return frag.toFragmentString(); return frag.toFragmentString();
} }
@ -649,7 +676,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private String[] decodeTreatAsRequests(Set<String> treatAsDeclarations) { private String[] decodeTreatAsRequests(Set<String> treatAsDeclarations) {
final List<String> values = new ArrayList<>(); final List<String> values = new ArrayList<>();
for ( String subclass : treatAsDeclarations ) { for ( String subclass : treatAsDeclarations ) {
//TODO: move getDiscriminatorSQLValue() to Loadable to get rid of Queryable
final Queryable queryable = (Queryable) getFactory() final Queryable queryable = (Queryable) getFactory()
.getRuntimeMetamodels() .getRuntimeMetamodels()
.getMappingMetamodel() .getMappingMetamodel()
@ -679,48 +705,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return ArrayHelper.toStringArray( values ); return ArrayHelper.toStringArray( values );
} }
private String[] fullDiscriminatorSQLValues;
private String[] fullDiscriminatorSQLValues() {
String[] fullDiscriminatorSQLValues = this.fullDiscriminatorSQLValues;
if ( fullDiscriminatorSQLValues == null ) {
// first access; build it
final List<String> values = new ArrayList<>();
for ( String subclass : getSubclassClosure() ) {
final Queryable queryable = (Queryable) getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( subclass );
if ( !queryable.isAbstract() ) {
values.add( queryable.getDiscriminatorSQLValue() );
}
}
this.fullDiscriminatorSQLValues = fullDiscriminatorSQLValues = ArrayHelper.toStringArray( values );
}
return fullDiscriminatorSQLValues;
}
private Object[] fullDiscriminatorValues;
private Object[] fullDiscriminatorValues() {
Object[] fullDiscriminatorValues = this.fullDiscriminatorValues;
if ( fullDiscriminatorValues == null ) {
// first access; build it
final List<Object> values = new ArrayList<>();
for ( String subclass : getSubclassClosure() ) {
final Loadable queryable = (Loadable) getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( subclass );
if ( !queryable.isAbstract() ) {
values.add( queryable.getDiscriminatorValue() );
}
}
this.fullDiscriminatorValues = fullDiscriminatorValues = values.toArray(new Object[0]);
}
return fullDiscriminatorValues;
}
@Override @Override
public String getSubclassPropertyTableName(int i) { public String getSubclassPropertyTableName(int i) {
return subclassTableNameClosure[subclassPropertyTableNumberClosure[i]]; return subclassTableNameClosure[subclassPropertyTableNumberClosure[i]];
@ -903,10 +887,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
); );
if ( hasSubclasses() ) { if ( hasSubclasses() ) {
final Object[] discriminatorValues = fullDiscriminatorValues(); final List<Expression> values = new ArrayList<>( fullDiscriminatorValues.length );
final List<Expression> values = new ArrayList<>( discriminatorValues.length );
boolean hasNull = false, hasNonNull = false; boolean hasNull = false, hasNonNull = false;
for ( Object discriminatorValue : discriminatorValues ) { for ( Object discriminatorValue : fullDiscriminatorValues) {
if ( discriminatorValue == NULL_DISCRIMINATOR ) { if ( discriminatorValue == NULL_DISCRIMINATOR ) {
hasNull = true; hasNull = true;
} }

View File

@ -48,8 +48,6 @@ public interface BasicType<T> extends Type, BasicDomainType<T>, MappingType, Bas
return getJavaTypeDescriptor(); return getJavaTypeDescriptor();
} }
@Override @Override
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) { default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
action.accept( 0, this ); action.accept( 0, this );

View File

@ -43,7 +43,7 @@ public class DuplicatedDiscriminatorValueTest {
fail( MappingException.class.getName() + " expected when two subclasses are mapped with the same discriminator value." ); fail( MappingException.class.getName() + " expected when two subclasses are mapped with the same discriminator value." );
} }
catch ( MappingException e ) { catch ( MappingException e ) {
final String errorMsg = e.getCause().getMessage(); final String errorMsg = e.getMessage();
// Check if error message contains descriptive information. // Check if error message contains descriptive information.
assertTrue( errorMsg.contains( Building1.class.getName() ) ); assertTrue( errorMsg.contains( Building1.class.getName() ) );
assertTrue( errorMsg.contains( Building2.class.getName() ) ); assertTrue( errorMsg.contains( Building2.class.getName() ) );