Skip to content

Commit 5a549ea

Browse files
committed
fix initialization of SingleTableEntityPersister to be eager
1 parent dcd7ebb commit 5a549ea

File tree

4 files changed

+120
-134
lines changed

4 files changed

+120
-134
lines changed

hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public static int indexOf(Object[] array, Object object) {
3636
return -1;
3737
}
3838

39+
@SuppressWarnings("unchecked")
3940
public static <T> T[] filledArray(T value, Class<T> valueJavaType, int size) {
4041
final T[] array = (T[]) Array.newInstance( valueJavaType, size );
4142
Arrays.fill( array, value );
@@ -79,6 +80,10 @@ public static String[] toStringArray(Collection<String> coll) {
7980
return coll.toArray( EMPTY_STRING_ARRAY );
8081
}
8182

83+
public static Object[] toObjectArray(Collection<Object> coll) {
84+
return coll.toArray( EMPTY_OBJECT_ARRAY );
85+
}
86+
8287
public static String[][] to2DStringArray(Collection<String[]> coll) {
8388
return coll.toArray( new String[0][] );
8489
}
@@ -102,11 +107,11 @@ public static int[] toIntArray(Collection<Integer> coll) {
102107
}
103108

104109
public static boolean[] toBooleanArray(Collection<Boolean> coll) {
105-
Iterator iter = coll.iterator();
110+
Iterator<Boolean> iter = coll.iterator();
106111
boolean[] arr = new boolean[coll.size()];
107112
int i = 0;
108113
while ( iter.hasNext() ) {
109-
arr[i++] = (Boolean) iter.next();
114+
arr[i++] = iter.next();
110115
}
111116
return arr;
112117
}
@@ -116,17 +121,17 @@ public static Object[] typecast(Object[] array, Object[] to) {
116121
}
117122

118123
//Arrays.asList doesn't do primitive arrays
119-
public static List toList(Object array) {
120-
if ( array instanceof Object[] ) {
121-
return Arrays.asList( (Object[]) array ); //faster?
122-
}
123-
int size = Array.getLength( array );
124-
ArrayList list = new ArrayList( size );
125-
for ( int i = 0; i < size; i++ ) {
126-
list.add( Array.get( array, i ) );
127-
}
128-
return list;
129-
}
124+
// public static List toList(Object array) {
125+
// if ( array instanceof Object[] ) {
126+
// return Arrays.asList( (Object[]) array ); //faster?
127+
// }
128+
// int size = Array.getLength( array );
129+
// ArrayList<Object> list = new ArrayList<>( size );
130+
// for ( int i = 0; i < size; i++ ) {
131+
// list.add( Array.get( array, i ) );
132+
// }
133+
// return list;
134+
// }
130135

131136
public static String[] slice(String[] strings, int begin, int length) {
132137
String[] result = new String[length];
@@ -140,8 +145,8 @@ public static Object[] slice(Object[] objects, int begin, int length) {
140145
return result;
141146
}
142147

143-
public static List toList(Iterator iter) {
144-
List list = new ArrayList();
148+
public static <T> List<T> toList(Iterator<T> iter) {
149+
List<T> list = new ArrayList<>();
145150
while ( iter.hasNext() ) {
146151
list.add( iter.next() );
147152
}

hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java

Lines changed: 99 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.hibernate.internal.DynamicFilterAliasGenerator;
2626
import org.hibernate.internal.FilterAliasGenerator;
2727
import org.hibernate.internal.util.MarkerObject;
28+
import org.hibernate.internal.util.ReflectHelper;
2829
import org.hibernate.internal.util.StringHelper;
2930
import org.hibernate.internal.util.collections.ArrayHelper;
3031
import org.hibernate.internal.util.collections.CollectionHelper;
@@ -128,6 +129,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
128129
//private final Map propertyTableNumbersByName = new HashMap();
129130
// private final Map<String, Integer> propertyTableNumbersByNameAndSubclass;
130131

132+
private final String[] fullDiscriminatorSQLValues;
133+
private final Object[] fullDiscriminatorValues;
134+
131135
private static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" );
132136
private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" );
133137

@@ -293,7 +297,7 @@ public SingleTableEntityPersister(
293297
// DISCRIMINATOR
294298

295299
if ( persistentClass.isPolymorphic() ) {
296-
Value discrimValue = persistentClass.getDiscriminator();
300+
final Value discrimValue = persistentClass.getDiscriminator();
297301
if ( discrimValue == null ) {
298302
throw new MappingException( "discriminator mapping required for single table polymorphic persistence" );
299303
}
@@ -318,37 +322,10 @@ public SingleTableEntityPersister(
318322
// discriminatorFormula = null;
319323
discriminatorFormulaTemplate = null;
320324
}
321-
discriminatorType = (BasicType<?>) persistentClass.getDiscriminator().getType();
322-
if ( persistentClass.isDiscriminatorValueNull() ) {
323-
discriminatorValue = NULL_DISCRIMINATOR;
324-
discriminatorSQLValue = InFragment.NULL;
325-
discriminatorInsertable = false;
326-
}
327-
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
328-
discriminatorValue = NOT_NULL_DISCRIMINATOR;
329-
discriminatorSQLValue = InFragment.NOT_NULL;
330-
discriminatorInsertable = false;
331-
}
332-
else {
333-
discriminatorInsertable = persistentClass.isDiscriminatorInsertable() && !discrimValue.hasFormula();
334-
try {
335-
discriminatorValue = discriminatorType.getJavaTypeDescriptor()
336-
.fromString( persistentClass.getDiscriminatorValue() );
337-
JdbcLiteralFormatter literalFormatter = discriminatorType.getJdbcType()
338-
.getJdbcLiteralFormatter( discriminatorType.getJavaTypeDescriptor() );
339-
discriminatorSQLValue = literalFormatter.toJdbcLiteral(
340-
discriminatorValue,
341-
dialect,
342-
factory.getWrapperOptions()
343-
);
344-
}
345-
catch (ClassCastException cce) {
346-
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
347-
}
348-
catch (Exception e) {
349-
throw new MappingException( "Could not format discriminator value to SQL string", e );
350-
}
351-
}
325+
discriminatorType = getDiscriminatorType( persistentClass );
326+
discriminatorValue = getDiscriminatorValue( persistentClass );
327+
discriminatorSQLValue = getDiscriminatorSQLValue( persistentClass, dialect, factory );
328+
discriminatorInsertable = isDiscriminatorInsertable( persistentClass );
352329
}
353330
else {
354331
forceDiscriminator = false;
@@ -407,6 +384,8 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) {
407384
// subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaJoinedNumbers );
408385
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propertyJoinNumbers );
409386

387+
final List<Object> values = new ArrayList<>();
388+
final List<String> sqlValues = new ArrayList<>();
410389
int subclassSpan = persistentClass.getSubclassSpan() + 1;
411390
subclassClosure = new String[subclassSpan];
412391
subclassClosure[0] = getEntityName();
@@ -416,53 +395,106 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) {
416395
discriminatorValue,
417396
getEntityName()
418397
);
419-
}
420398

421-
// SUBCLASSES
422-
if ( persistentClass.isPolymorphic() ) {
399+
if ( !getEntityMetamodel().isAbstract() ) {
400+
values.add( discriminatorValue );
401+
sqlValues.add( discriminatorSQLValue );
402+
}
403+
404+
// SUBCLASSES
423405
int k = 1;
424406
for ( Subclass subclass : persistentClass.getSubclasses() ) {
425407
subclassClosure[k++] = subclass.getEntityName();
426-
if ( subclass.isDiscriminatorValueNull() ) {
427-
addSubclassByDiscriminatorValue(
428-
subclassesByDiscriminatorValueLocal,
429-
NULL_DISCRIMINATOR,
430-
subclass.getEntityName()
431-
);
432-
}
433-
else if ( subclass.isDiscriminatorValueNotNull() ) {
434-
addSubclassByDiscriminatorValue(
435-
subclassesByDiscriminatorValueLocal,
436-
NOT_NULL_DISCRIMINATOR,
437-
subclass.getEntityName()
438-
);
439-
}
440-
else {
441-
try {
442-
addSubclassByDiscriminatorValue(
443-
subclassesByDiscriminatorValueLocal,
444-
discriminatorType.getJavaTypeDescriptor()
445-
.fromString( subclass.getDiscriminatorValue() ),
446-
subclass.getEntityName()
447-
);
448-
}
449-
catch (ClassCastException cce) {
450-
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
451-
}
452-
catch (Exception e) {
453-
throw new MappingException( "Error parsing discriminator value", e );
454-
}
408+
Object subclassDiscriminatorValue = getDiscriminatorValue( subclass );
409+
addSubclassByDiscriminatorValue(
410+
subclassesByDiscriminatorValueLocal,
411+
subclassDiscriminatorValue,
412+
subclass.getEntityName()
413+
);
414+
415+
//copy/paste from EntityMetamodel:
416+
boolean subclassAbstract = subclass.isAbstract() == null
417+
? subclass.hasPojoRepresentation() && ReflectHelper.isAbstractClass( subclass.getMappedClass() )
418+
: subclass.isAbstract();
419+
420+
if ( !subclassAbstract ) {
421+
values.add(subclassDiscriminatorValue);
422+
sqlValues.add( getDiscriminatorSQLValue( subclass, dialect, factory ) );
455423
}
456424
}
457425
}
458426

459427
// Don't hold a reference to an empty HashMap:
460428
subclassesByDiscriminatorValue = CollectionHelper.toSmallMap( subclassesByDiscriminatorValueLocal );
429+
fullDiscriminatorSQLValues = ArrayHelper.toStringArray( sqlValues );
430+
fullDiscriminatorValues = ArrayHelper.toObjectArray( values );
461431

462432
initSubclassPropertyAliasesMap( persistentClass );
463433

464434
postConstruct( creationContext.getMetadata() );
435+
}
465436

437+
private static BasicType<?> getDiscriminatorType(PersistentClass persistentClass) {
438+
Type discriminatorType = persistentClass.getDiscriminator().getType();
439+
if ( discriminatorType instanceof BasicType ) {
440+
return (BasicType<?>) discriminatorType;
441+
}
442+
else {
443+
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
444+
}
445+
}
446+
447+
private static String getDiscriminatorSQLValue(
448+
PersistentClass persistentClass,
449+
Dialect dialect,
450+
SessionFactoryImplementor factory) {
451+
if ( persistentClass.isDiscriminatorValueNull() ) {
452+
return InFragment.NULL;
453+
}
454+
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
455+
return InFragment.NOT_NULL;
456+
}
457+
else {
458+
BasicType<?> discriminatorType = getDiscriminatorType( persistentClass );
459+
Object discriminatorValue = getDiscriminatorValue( persistentClass );
460+
try {
461+
JdbcLiteralFormatter literalFormatter = discriminatorType.getJdbcType()
462+
.getJdbcLiteralFormatter( discriminatorType.getJavaTypeDescriptor() );
463+
return literalFormatter.toJdbcLiteral(
464+
discriminatorValue,
465+
dialect,
466+
factory.getWrapperOptions()
467+
);
468+
}
469+
catch (Exception e) {
470+
throw new MappingException( "Could not format discriminator value to SQL string", e );
471+
}
472+
}
473+
}
474+
475+
private static Object getDiscriminatorValue(PersistentClass persistentClass) {
476+
if ( persistentClass.isDiscriminatorValueNull() ) {
477+
return NULL_DISCRIMINATOR;
478+
}
479+
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
480+
return NOT_NULL_DISCRIMINATOR;
481+
}
482+
else {
483+
BasicType<?> discriminatorType = getDiscriminatorType( persistentClass );
484+
try {
485+
return discriminatorType.getJavaTypeDescriptor().fromString( persistentClass.getDiscriminatorValue() );
486+
}
487+
catch (Exception e) {
488+
throw new MappingException( "Could not parse discriminator value", e );
489+
}
490+
}
491+
}
492+
493+
private static boolean isDiscriminatorInsertable(PersistentClass persistentClass) {
494+
return !persistentClass.isDiscriminatorValueNull()
495+
&& !persistentClass.isDiscriminatorValueNotNull()
496+
&& persistentClass.isDiscriminatorInsertable()
497+
&& !persistentClass.getDiscriminator().hasFormula();
466498
}
467499

468500
private static void addSubclassByDiscriminatorValue(Map<Object, String> subclassesByDiscriminatorValue, Object discriminatorValue, String entityName) {
@@ -632,12 +664,7 @@ private String discriminatorFilterFragment(String alias, Set<String> treatAsDecl
632664
frag.setColumn( alias, getDiscriminatorColumnName() );
633665
}
634666

635-
if ( hasTreatAs ) {
636-
frag.addValues( decodeTreatAsRequests( treatAsDeclarations ) );
637-
}
638-
else {
639-
frag.addValues( fullDiscriminatorSQLValues() );
640-
}
667+
frag.addValues( hasTreatAs ? decodeTreatAsRequests( treatAsDeclarations ) : fullDiscriminatorSQLValues );
641668

642669
return frag.toFragmentString();
643670
}
@@ -649,7 +676,6 @@ private boolean needsDiscriminator() {
649676
private String[] decodeTreatAsRequests(Set<String> treatAsDeclarations) {
650677
final List<String> values = new ArrayList<>();
651678
for ( String subclass : treatAsDeclarations ) {
652-
//TODO: move getDiscriminatorSQLValue() to Loadable to get rid of Queryable
653679
final Queryable queryable = (Queryable) getFactory()
654680
.getRuntimeMetamodels()
655681
.getMappingMetamodel()
@@ -679,48 +705,6 @@ private String[] decodeTreatAsRequests(Set<String> treatAsDeclarations) {
679705
return ArrayHelper.toStringArray( values );
680706
}
681707

682-
private String[] fullDiscriminatorSQLValues;
683-
684-
private String[] fullDiscriminatorSQLValues() {
685-
String[] fullDiscriminatorSQLValues = this.fullDiscriminatorSQLValues;
686-
if ( fullDiscriminatorSQLValues == null ) {
687-
// first access; build it
688-
final List<String> values = new ArrayList<>();
689-
for ( String subclass : getSubclassClosure() ) {
690-
final Queryable queryable = (Queryable) getFactory().getRuntimeMetamodels()
691-
.getMappingMetamodel()
692-
.getEntityDescriptor( subclass );
693-
if ( !queryable.isAbstract() ) {
694-
values.add( queryable.getDiscriminatorSQLValue() );
695-
}
696-
}
697-
this.fullDiscriminatorSQLValues = fullDiscriminatorSQLValues = ArrayHelper.toStringArray( values );
698-
}
699-
700-
return fullDiscriminatorSQLValues;
701-
}
702-
703-
private Object[] fullDiscriminatorValues;
704-
705-
private Object[] fullDiscriminatorValues() {
706-
Object[] fullDiscriminatorValues = this.fullDiscriminatorValues;
707-
if ( fullDiscriminatorValues == null ) {
708-
// first access; build it
709-
final List<Object> values = new ArrayList<>();
710-
for ( String subclass : getSubclassClosure() ) {
711-
final Loadable queryable = (Loadable) getFactory().getRuntimeMetamodels()
712-
.getMappingMetamodel()
713-
.getEntityDescriptor( subclass );
714-
if ( !queryable.isAbstract() ) {
715-
values.add( queryable.getDiscriminatorValue() );
716-
}
717-
}
718-
this.fullDiscriminatorValues = fullDiscriminatorValues = values.toArray(new Object[0]);
719-
}
720-
721-
return fullDiscriminatorValues;
722-
}
723-
724708
@Override
725709
public String getSubclassPropertyTableName(int i) {
726710
return subclassTableNameClosure[subclassPropertyTableNumberClosure[i]];
@@ -903,10 +887,9 @@ private Predicate createDiscriminatorPredicate(
903887
);
904888

905889
if ( hasSubclasses() ) {
906-
final Object[] discriminatorValues = fullDiscriminatorValues();
907-
final List<Expression> values = new ArrayList<>( discriminatorValues.length );
890+
final List<Expression> values = new ArrayList<>( fullDiscriminatorValues.length );
908891
boolean hasNull = false, hasNonNull = false;
909-
for ( Object discriminatorValue : discriminatorValues ) {
892+
for ( Object discriminatorValue : fullDiscriminatorValues) {
910893
if ( discriminatorValue == NULL_DISCRIMINATOR ) {
911894
hasNull = true;
912895
}

hibernate-core/src/main/java/org/hibernate/type/BasicType.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ default JavaType<T> getExpressibleJavaType() {
4848
return getJavaTypeDescriptor();
4949
}
5050

51-
52-
5351
@Override
5452
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
5553
action.accept( 0, this );

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/inheritance/singletable/DuplicatedDiscriminatorValueTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void testDuplicatedDiscriminatorValueSameHierarchy() {
4343
fail( MappingException.class.getName() + " expected when two subclasses are mapped with the same discriminator value." );
4444
}
4545
catch ( MappingException e ) {
46-
final String errorMsg = e.getCause().getMessage();
46+
final String errorMsg = e.getMessage();
4747
// Check if error message contains descriptive information.
4848
assertTrue( errorMsg.contains( Building1.class.getName() ) );
4949
assertTrue( errorMsg.contains( Building2.class.getName() ) );

0 commit comments

Comments
 (0)