Skip to content

Commit d90807f

Browse files
committed
HHH-17117 allow @TenantID to form part of composite key
Signed-off-by: Gavin King <[email protected]>
1 parent 77a34e6 commit d90807f

File tree

14 files changed

+251
-86
lines changed

14 files changed

+251
-86
lines changed

hibernate-core/src/main/java/org/hibernate/annotations/TenantId.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* @author Gavin King
2727
*/
2828
@ValueGenerationType(generatedBy = TenantIdGeneration.class)
29+
@IdGeneratorType(TenantIdGeneration.class)
2930
@AttributeBinderType(binder = TenantIdBinder.class)
3031
@Target({METHOD, FIELD})
3132
@Retention(RUNTIME)

hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,24 +1358,6 @@ else if ( clazz.hasDirectAnnotationUsage( Imported.class ) ) {
13581358
}
13591359
}
13601360

1361-
private static AnnotatedClassType getAnnotatedClassType2(ClassDetails classDetails) {
1362-
if ( classDetails.hasDirectAnnotationUsage( Entity.class ) ) {
1363-
return AnnotatedClassType.ENTITY;
1364-
}
1365-
else if ( classDetails.hasDirectAnnotationUsage( Embeddable.class ) ) {
1366-
return AnnotatedClassType.EMBEDDABLE;
1367-
}
1368-
else if ( classDetails.hasDirectAnnotationUsage( jakarta.persistence.MappedSuperclass.class ) ) {
1369-
return AnnotatedClassType.MAPPED_SUPERCLASS;
1370-
}
1371-
else if ( classDetails.hasDirectAnnotationUsage( Imported.class ) ) {
1372-
return AnnotatedClassType.IMPORTED;
1373-
}
1374-
else {
1375-
return AnnotatedClassType.NONE;
1376-
}
1377-
}
1378-
13791361
@Override
13801362
public void addMappedSuperclass(Class<?> type, MappedSuperclass mappedSuperclass) {
13811363
if ( mappedSuperClasses == null ) {
@@ -2022,10 +2004,10 @@ private void processEndOfQueue(List<FkSecondPass> endOfQueueFkSecondPasses) {
20222004
}
20232005
}
20242006
}
2025-
stopProcess = failingSecondPasses.size() == 0 || failingSecondPasses.size() == endOfQueueFkSecondPasses.size();
2007+
stopProcess = failingSecondPasses.isEmpty() || failingSecondPasses.size() == endOfQueueFkSecondPasses.size();
20262008
endOfQueueFkSecondPasses = failingSecondPasses;
20272009
}
2028-
if ( endOfQueueFkSecondPasses.size() > 0 ) {
2010+
if ( !endOfQueueFkSecondPasses.isEmpty() ) {
20292011
throw originalException;
20302012
}
20312013
}
@@ -2212,7 +2194,8 @@ private void processExportableProducers() {
22122194
handleIdentifierValueBinding(
22132195
entityBinding.getIdentifier(),
22142196
dialect,
2215-
(RootClass) entityBinding
2197+
(RootClass) entityBinding,
2198+
entityBinding.getIdentifierProperty()
22162199
);
22172200

22182201
}
@@ -2225,22 +2208,20 @@ private void processExportableProducers() {
22252208
handleIdentifierValueBinding(
22262209
( (IdentifierCollection) collection ).getIdentifier(),
22272210
dialect,
2211+
null,
22282212
null
22292213
);
22302214
}
22312215
}
22322216

22332217
private void handleIdentifierValueBinding(
2234-
KeyValue identifierValueBinding,
2235-
Dialect dialect,
2236-
RootClass entityBinding) {
2218+
KeyValue identifierValueBinding, Dialect dialect, RootClass entityBinding, Property identifierProperty) {
22372219
// todo : store this result (back into the entity or into the KeyValue, maybe?)
22382220
// This process of instantiating the id-generator is called multiple times.
22392221
// It was done this way in the old code too, so no "regression" here; but
22402222
// it could be done better
22412223
try {
2242-
final Generator generator = identifierValueBinding.createGenerator( dialect, entityBinding );
2243-
2224+
final Generator generator = identifierValueBinding.createGenerator( dialect, entityBinding, identifierProperty );
22442225
if ( generator instanceof ExportableProducer ) {
22452226
( (ExportableProducer) generator ).registerExportables( getDatabase() );
22462227
}

hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.hibernate.engine.spi.SessionImplementor;
2626
import org.hibernate.engine.spi.Status;
2727
import org.hibernate.event.spi.EventSource;
28-
import org.hibernate.id.Assigned;
2928
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
3029
import org.hibernate.id.IdentifierGenerationException;
3130
import org.hibernate.internal.CoreLogging;

hibernate-core/src/main/java/org/hibernate/generator/internal/TenantIdGeneration.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,26 @@ public EnumSet<EventType> getEventTypes() {
5151
@Override
5252
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
5353
final SessionFactoryImplementor sessionFactory = session.getSessionFactory();
54-
final JavaType<Object> tenantIdentifierJavaType = sessionFactory.getTenantIdentifierJavaType();
55-
5654
final Object tenantId = session.getTenantIdentifierValue();
5755
if ( currentValue != null ) {
58-
final CurrentTenantIdentifierResolver<Object> resolver = sessionFactory.getCurrentTenantIdentifierResolver();
56+
final CurrentTenantIdentifierResolver<Object> resolver =
57+
sessionFactory.getCurrentTenantIdentifierResolver();
5958
if ( resolver != null && resolver.isRoot( tenantId ) ) {
6059
// the "root" tenant is allowed to set the tenant id explicitly
6160
return currentValue;
6261
}
63-
if ( !tenantIdentifierJavaType.areEqual( currentValue, tenantId ) ) {
64-
throw new PropertyValueException(
65-
"assigned tenant id differs from current tenant id: " +
66-
tenantIdentifierJavaType.toString( currentValue ) +
67-
"!=" +
68-
tenantIdentifierJavaType.toString( tenantId ),
69-
entityName,
70-
propertyName
71-
);
62+
else {
63+
final JavaType<Object> tenantIdJavaType = sessionFactory.getTenantIdentifierJavaType();
64+
if ( !tenantIdJavaType.areEqual( currentValue, tenantId ) ) {
65+
throw new PropertyValueException(
66+
"assigned tenant id differs from current tenant id ["
67+
+ tenantIdJavaType.toString( currentValue )
68+
+ " != "
69+
+ tenantIdJavaType.toString( tenantId ) + "]",
70+
entityName,
71+
propertyName
72+
);
73+
}
7274
}
7375
}
7476
return tenantId;

hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,16 @@ public Map<String,?> getParameters() {
103103
* of the passed value did not match the configured type.
104104
*/
105105
public Filter setParameter(String name, Object value) throws IllegalArgumentException {
106-
Object argument = definition.processArgument(value);
106+
final Object argument = definition.processArgument( value );
107107

108108
// Make sure this is a defined parameter and check the incoming value type
109-
JdbcMapping type = definition.getParameterJdbcMapping( name );
109+
final JdbcMapping type = definition.getParameterJdbcMapping( name );
110110
if ( type == null ) {
111-
throw new IllegalArgumentException( "Undefined filter parameter [" + name + "]" );
111+
throw new IllegalArgumentException( "Undefined filter parameter '" + name + "'" );
112112
}
113113
if ( argument != null && !type.getJavaTypeDescriptor().isInstance( argument ) ) {
114-
throw new IllegalArgumentException( "Incorrect type for parameter [" + name + "]" );
114+
throw new IllegalArgumentException( "Argument assigned to filter parameter '" + name
115+
+ "' is not of type '" + type.getJavaTypeDescriptor().getTypeName() + "'" );
115116
}
116117
if ( parameters == null ) {
117118
parameters = new TreeMap<>();
@@ -133,14 +134,15 @@ public Filter setParameterList(String name, Collection<?> values) throws Hiberna
133134
if ( values == null ) {
134135
throw new IllegalArgumentException( "Collection must be not null" );
135136
}
136-
JdbcMapping type = definition.getParameterJdbcMapping( name );
137+
final JdbcMapping type = definition.getParameterJdbcMapping( name );
137138
if ( type == null ) {
138-
throw new HibernateException( "Undefined filter parameter [" + name + "]" );
139+
throw new HibernateException( "Undefined filter parameter '" + name + "'" );
139140
}
140141
if ( !values.isEmpty() ) {
141142
final Object element = values.iterator().next();
142143
if ( !type.getJavaTypeDescriptor().isInstance( element ) ) {
143-
throw new HibernateException( "Incorrect type for parameter [" + name + "]" );
144+
throw new IllegalArgumentException( "Argument assigned to filter parameter '" + name
145+
+ "' is not of type '" + type.getJavaTypeDescriptor().getTypeName() + "'" );
144146
}
145147
}
146148
if ( parameters == null ) {

hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ private static Map<String, Generator> createGenerators(
457457
for ( PersistentClass model : bootMetamodel.getEntityBindings() ) {
458458
if ( !model.isInherited() ) {
459459
final KeyValue id = model.getIdentifier();
460-
final Generator generator = id.createGenerator( dialect, (RootClass) model );
460+
final Generator generator = id.createGenerator( dialect, (RootClass) model, model.getIdentifierProperty() );
461461
if ( generator instanceof Configurable ) {
462462
final Configurable identifierGenerator = (Configurable) generator;
463463
identifierGenerator.initialize( sqlStringGenerationContext );

hibernate-core/src/main/java/org/hibernate/mapping/Component.java

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import java.util.Comparator;
1212
import java.util.HashMap;
1313
import java.util.HashSet;
14-
import java.util.Iterator;
1514
import java.util.List;
1615
import java.util.Map;
1716
import java.util.Objects;
@@ -546,10 +545,6 @@ public void setKey(boolean isKey) {
546545
this.isKey = isKey;
547546
}
548547

549-
public boolean hasPojoRepresentation() {
550-
return componentClassName!=null;
551-
}
552-
553548
/**
554549
* Returns the {@link Property} at the specified position in this {@link Component}.
555550
*
@@ -661,37 +656,33 @@ public String toString() {
661656
}
662657

663658
@Override
664-
public Generator createGenerator(Dialect dialect, RootClass rootClass) throws MappingException {
659+
public Generator createGenerator(Dialect dialect, RootClass rootClass, Property property) {
665660
if ( builtIdentifierGenerator == null ) {
666-
builtIdentifierGenerator = buildIdentifierGenerator( dialect, rootClass );
661+
builtIdentifierGenerator =
662+
getCustomIdGeneratorCreator().isAssigned()
663+
? buildIdentifierGenerator( dialect, rootClass )
664+
: super.createGenerator( dialect, rootClass, property );
667665
}
668666
return builtIdentifierGenerator;
669667
}
670668

671-
private Generator buildIdentifierGenerator( Dialect dialect, RootClass rootClass) throws MappingException {
672-
if ( !getCustomIdGeneratorCreator().isAssigned() ) {
673-
return super.createGenerator( dialect, rootClass );
674-
}
675-
676-
final Class<?> entityClass = rootClass.getMappedClass();
677-
final Class<?> attributeDeclarer = getAttributeDeclarer( rootClass, entityClass );
678-
679-
final CompositeNestedGeneratedValueGenerator.GenerationContextLocator locator =
680-
new StandardGenerationContextLocator( rootClass.getEntityName() );
669+
private Generator buildIdentifierGenerator(Dialect dialect, RootClass rootClass) {
681670
final CompositeNestedGeneratedValueGenerator generator =
682-
new CompositeNestedGeneratedValueGenerator( locator, getType() );
683-
671+
new CompositeNestedGeneratedValueGenerator(
672+
new StandardGenerationContextLocator( rootClass.getEntityName() ),
673+
getType()
674+
);
684675
final List<Property> properties = getProperties();
685676
for ( int i = 0; i < properties.size(); i++ ) {
686677
final Property property = properties.get( i );
687678
if ( property.getValue().isSimpleValue() ) {
688679
final SimpleValue value = (SimpleValue) property.getValue();
689680
if ( !value.getCustomIdGeneratorCreator().isAssigned() ) {
690-
// skip any 'assigned' generators, they would have been handled by
691-
// the StandardGenerationContextLocator
681+
// skip any 'assigned' generators, they would have been
682+
// handled by the StandardGenerationContextLocator
692683
generator.addGeneratedValuePlan( new ValueGenerationPlan(
693-
value.createGenerator( dialect, rootClass ),
694-
getType().isMutable() ? injector( property, attributeDeclarer ) : null,
684+
value.createGenerator( dialect, rootClass, property ),
685+
getType().isMutable() ? injector( property, getAttributeDeclarer( rootClass ) ) : null,
695686
i
696687
) );
697688
}
@@ -700,23 +691,27 @@ private Generator buildIdentifierGenerator( Dialect dialect, RootClass rootClass
700691
return generator;
701692
}
702693

703-
private Class<?> getAttributeDeclarer(RootClass rootClass, Class<?> entityClass) {
704-
final Class<?> attributeDeclarer; // what class is the declarer of the composite pk attributes
705-
// IMPL NOTE : See the javadoc discussion on CompositeNestedGeneratedValueGenerator wrt the
706-
// various scenarios for which we need to account here
694+
/**
695+
* Return the class that declares the composite pk attributes,
696+
* which might be an {@code @IdClass}, an {@code @EmbeddedId},
697+
* of the entity class itself.
698+
*/
699+
private Class<?> getAttributeDeclarer(RootClass rootClass) {
700+
// See the javadoc discussion on CompositeNestedGeneratedValueGenerator
701+
// for the various scenarios we need to account for here
707702
if ( rootClass.getIdentifierMapper() != null ) {
708703
// we have the @IdClass / <composite-id mapped="true"/> case
709-
attributeDeclarer = resolveComponentClass();
704+
return resolveComponentClass();
710705
}
711706
else if ( rootClass.getIdentifierProperty() != null ) {
712707
// we have the "@EmbeddedId" / <composite-id name="idName"/> case
713-
attributeDeclarer = resolveComponentClass();
708+
return resolveComponentClass();
714709
}
715710
else {
716-
// we have the "straight up" embedded (again the Hibernate term) component identifier
717-
attributeDeclarer = entityClass;
711+
// we have the "straight up" embedded (again the Hibernate term)
712+
// component identifier: the entity class itself is the id class
713+
return rootClass.getMappedClass();
718714
}
719-
return attributeDeclarer;
720715
}
721716

722717
private Setter injector(Property property, Class<?> attributeDeclarer) {

hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public interface KeyValue extends Value {
2727

2828
boolean isUpdateable();
2929

30-
Generator createGenerator(Dialect dialect, RootClass rootClass);
30+
@Deprecated(since = "7.0")
31+
default Generator createGenerator(Dialect dialect, RootClass rootClass) {
32+
return createGenerator( dialect, rootClass, null );
33+
}
34+
35+
Generator createGenerator(Dialect dialect, RootClass rootClass, Property property);
3136

3237
}

hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,10 +375,10 @@ public GeneratorCreator getCustomIdGeneratorCreator() {
375375
}
376376

377377
@Override
378-
public Generator createGenerator(Dialect dialect, RootClass rootClass) {
378+
public Generator createGenerator(Dialect dialect, RootClass rootClass, Property property) {
379379
if ( generator == null ) {
380380
if ( customIdGeneratorCreator != null ) {
381-
generator = customIdGeneratorCreator.createGenerator( new IdGeneratorCreationContext( rootClass ) );
381+
generator = customIdGeneratorCreator.createGenerator( new IdGeneratorCreationContext( rootClass, property ) );
382382
}
383383
}
384384
return generator;
@@ -1011,9 +1011,11 @@ public Long[] getColumnLengths() {
10111011

10121012
private class IdGeneratorCreationContext implements GeneratorCreationContext {
10131013
private final RootClass rootClass;
1014+
private final Property property;
10141015

1015-
public IdGeneratorCreationContext(RootClass rootClass) {
1016+
public IdGeneratorCreationContext(RootClass rootClass, Property property) {
10161017
this.rootClass = rootClass;
1018+
this.property = property;
10171019
}
10181020

10191021
@Override
@@ -1048,7 +1050,7 @@ public PersistentClass getPersistentClass() {
10481050

10491051
@Override
10501052
public Property getProperty() {
1051-
return rootClass.getIdentifierProperty();
1053+
return property;
10521054
}
10531055

10541056
@Override

hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ else if ( indexedCollection instanceof org.hibernate.mapping.Map
598598
}
599599

600600
private BeforeExecutionGenerator createGenerator(RuntimeModelCreationContext context, IdentifierCollection collection) {
601-
final Generator generator = collection.getIdentifier().createGenerator( context.getDialect(), null );
601+
final Generator generator = collection.getIdentifier().createGenerator( context.getDialect(), null, null );
602602
if ( generator.generatedOnExecution() ) {
603603
throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
604604
}

0 commit comments

Comments
 (0)