Skip to content

Commit fbbaa38

Browse files
dreab8DavideD
authored andcommitted
[#2154] Composite key with generated value not working properly
1 parent a0524fe commit fbbaa38

File tree

3 files changed

+225
-15
lines changed

3 files changed

+225
-15
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.hibernate.reactive.id;
77

88
import org.hibernate.Incubating;
9+
import org.hibernate.generator.EventType;
910
import org.hibernate.generator.Generator;
1011
import org.hibernate.id.IdentifierGenerator;
1112
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
@@ -33,4 +34,8 @@ public interface ReactiveIdentifierGenerator<Id> extends Generator {
3334
* @param session the reactive session
3435
*/
3536
CompletionStage<Id> generate(ReactiveConnectionSupplier session, Object entity);
37+
38+
default CompletionStage<Id> generate(ReactiveConnectionSupplier session, Object owner, Object currentValue, EventType eventType) {
39+
return generate( session, owner );
40+
}
3641
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.id.impl;
7+
8+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
9+
import org.hibernate.generator.BeforeExecutionGenerator;
10+
import org.hibernate.generator.Generator;
11+
import org.hibernate.generator.GeneratorCreationContext;
12+
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
13+
import org.hibernate.id.IdentifierGenerationException;
14+
import org.hibernate.mapping.Component;
15+
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
16+
import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
17+
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
18+
import org.hibernate.reactive.tuple.entity.ReactiveEntityMetamodel;
19+
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.concurrent.CompletionStage;
23+
24+
import static org.hibernate.generator.EventType.INSERT;
25+
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
26+
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
27+
28+
public class ReactiveCompositeNestedGeneratedValueGenerator extends CompositeNestedGeneratedValueGenerator implements
29+
ReactiveIdentifierGenerator<Object> {
30+
31+
public ReactiveCompositeNestedGeneratedValueGenerator(
32+
CompositeNestedGeneratedValueGenerator generator,
33+
GeneratorCreationContext creationContext,
34+
RuntimeModelCreationContext runtimeModelCreationContext) {
35+
super(
36+
generator.getGenerationContextLocator(),
37+
generator.getCompositeType(),
38+
reactivePlans( generator, creationContext, runtimeModelCreationContext )
39+
);
40+
}
41+
42+
private static List<GenerationPlan> reactivePlans(
43+
CompositeNestedGeneratedValueGenerator generator,
44+
GeneratorCreationContext creationContext,
45+
RuntimeModelCreationContext runtimeModelCreationContext) {
46+
final List<GenerationPlan> plans = new ArrayList<>();
47+
for ( GenerationPlan plan : generator.getGenerationPlans() ) {
48+
final GenerationPlan reactivePlane = new Component.ValueGenerationPlan(
49+
(BeforeExecutionGenerator) ReactiveEntityMetamodel.augmentWithReactiveGenerator(
50+
plan.getGenerator(),
51+
creationContext,
52+
runtimeModelCreationContext
53+
),
54+
plan.getInjector(),
55+
plan.getPropertyIndex()
56+
);
57+
plans.add( reactivePlane );
58+
}
59+
return plans;
60+
}
61+
62+
@Override
63+
public CompletionStage<Object> generate(ReactiveConnectionSupplier reactiveConnectionSupplier, Object object) {
64+
SharedSessionContractImplementor session = (SharedSessionContractImplementor) reactiveConnectionSupplier;
65+
final Object context = getGenerationContextLocator().locateGenerationContext( session, object );
66+
67+
final List<Object> generatedValues = getCompositeType().isMutable()
68+
? null
69+
: new ArrayList<>( getGenerationPlans().size() );
70+
return loop( getGenerationPlans(), generationPlan -> generateIdentifier(
71+
reactiveConnectionSupplier,
72+
object,
73+
generationPlan,
74+
session,
75+
generatedValues,
76+
context
77+
) )
78+
.thenCompose( v -> handleGeneratedValues( generatedValues, context, session ) );
79+
}
80+
81+
private CompletionStage<?> generateIdentifier(
82+
ReactiveConnectionSupplier reactiveConnectionSupplier,
83+
Object object,
84+
GenerationPlan generationPlan,
85+
SharedSessionContractImplementor session,
86+
List<Object> generatedValues,
87+
Object context) {
88+
final Generator generator = generationPlan.getGenerator();
89+
if ( generator.generatedBeforeExecution( object, session ) ) {
90+
if ( generator instanceof ReactiveIdentifierGenerator<?> reactiveIdentifierGenerator ) {
91+
return reactiveIdentifierGenerator
92+
.generate( reactiveConnectionSupplier, object )
93+
.thenAccept( generated -> {
94+
if ( generatedValues != null ) {
95+
generatedValues.add( generated );
96+
}
97+
else {
98+
generationPlan.getInjector().set( context, generated );
99+
}
100+
} );
101+
}
102+
else {
103+
final Object currentValue = generator.allowAssignedIdentifiers()
104+
? getCompositeType().getPropertyValue( context, generationPlan.getPropertyIndex(), session )
105+
: null;
106+
return completedFuture( ( (BeforeExecutionGenerator) generator )
107+
.generate( session, object, currentValue, INSERT ) );
108+
}
109+
}
110+
else {
111+
throw new IdentifierGenerationException( "Identity generation isn't supported for composite ids" );
112+
}
113+
}
114+
115+
private CompletionStage<Object> handleGeneratedValues(
116+
List<Object> generatedValues,
117+
Object context,
118+
SharedSessionContractImplementor session) {
119+
if ( generatedValues != null ) {
120+
final Object[] values = getCompositeType().getPropertyValues( context );
121+
for ( int i = 0; i < generatedValues.size(); i++ ) {
122+
values[getGenerationPlans().get( i ).getPropertyIndex()] = generatedValues.get( i );
123+
}
124+
return completedFuture( getCompositeType().replacePropertyValues( context, values, session ) );
125+
}
126+
else {
127+
return completedFuture( context );
128+
}
129+
}
130+
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/tuple/entity/ReactiveEntityMetamodel.java

Lines changed: 90 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
import java.util.function.Function;
99

1010

11+
import org.hibernate.boot.model.relational.Database;
12+
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
1113
import org.hibernate.generator.Generator;
1214
import org.hibernate.generator.GeneratorCreationContext;
15+
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
1316
import org.hibernate.id.Configurable;
1417
import org.hibernate.id.IdentifierGenerator;
1518
import org.hibernate.id.SelectGenerator;
@@ -18,18 +21,23 @@
1821
import org.hibernate.id.enhanced.SequenceStyleGenerator;
1922
import org.hibernate.id.enhanced.TableGenerator;
2023
import org.hibernate.id.enhanced.TableStructure;
21-
import org.hibernate.mapping.GeneratorCreator;
24+
import org.hibernate.mapping.GeneratorSettings;
2225
import org.hibernate.mapping.PersistentClass;
26+
import org.hibernate.mapping.Property;
27+
import org.hibernate.mapping.RootClass;
2328
import org.hibernate.mapping.SimpleValue;
2429
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
2530
import org.hibernate.persister.entity.EntityPersister;
2631
import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
2732
import org.hibernate.reactive.id.impl.EmulatedSequenceReactiveIdentifierGenerator;
33+
import org.hibernate.reactive.id.impl.ReactiveCompositeNestedGeneratedValueGenerator;
2834
import org.hibernate.reactive.id.impl.ReactiveGeneratorWrapper;
2935
import org.hibernate.reactive.id.impl.ReactiveSequenceIdentifierGenerator;
3036
import org.hibernate.reactive.id.impl.TableReactiveIdentifierGenerator;
3137
import org.hibernate.reactive.logging.impl.Log;
38+
import org.hibernate.service.ServiceRegistry;
3239
import org.hibernate.tuple.entity.EntityMetamodel;
40+
import org.hibernate.type.Type;
3341

3442
import static java.lang.invoke.MethodHandles.lookup;
3543
import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
@@ -67,20 +75,22 @@ private static Generator buildIdGenerator(
6775
return existing;
6876
}
6977
else {
70-
SimpleValue identifier = (SimpleValue) persistentClass.getIdentifier();
71-
GeneratorCreator customIdGeneratorCreator = identifier.getCustomIdGeneratorCreator();
72-
identifier.setCustomIdGeneratorCreator( context -> {
73-
Generator generator = customIdGeneratorCreator.createGenerator( context );
74-
return augmentWithReactiveGenerator( generator, context, creationContext );
75-
} );
76-
final Generator idgenerator = identifier
77-
// returns the cached Generator if it was already created
78-
.createGenerator(
78+
final SimpleValue identifier = (SimpleValue) persistentClass.getIdentifier();
79+
final Generator idgenerator = augmentWithReactiveGenerator(
80+
identifier.createGenerator(
7981
creationContext.getDialect(),
8082
persistentClass.getRootClass(),
8183
persistentClass.getIdentifierProperty(),
8284
creationContext.getGeneratorSettings()
83-
);
85+
),
86+
new IdGeneratorCreationContext(
87+
persistentClass.getRootClass(),
88+
persistentClass.getIdentifierProperty(),
89+
creationContext.getGeneratorSettings(),
90+
identifier,
91+
creationContext
92+
),
93+
creationContext );
8494
creationContext.getGenerators().put( rootName, idgenerator );
8595
return idgenerator;
8696
}
@@ -90,8 +100,8 @@ public static Generator augmentWithReactiveGenerator(
90100
Generator generator,
91101
GeneratorCreationContext creationContext,
92102
RuntimeModelCreationContext runtimeModelCreationContext) {
93-
if ( generator instanceof SequenceStyleGenerator ) {
94-
final DatabaseStructure structure = ( (SequenceStyleGenerator) generator ).getDatabaseStructure();
103+
if ( generator instanceof SequenceStyleGenerator sequenceStyleGenerator) {
104+
final DatabaseStructure structure = sequenceStyleGenerator.getDatabaseStructure();
95105
if ( structure instanceof TableStructure ) {
96106
return initialize( (IdentifierGenerator) generator, new EmulatedSequenceReactiveIdentifierGenerator( (TableStructure) structure, runtimeModelCreationContext ), creationContext );
97107
}
@@ -100,16 +110,28 @@ public static Generator augmentWithReactiveGenerator(
100110
}
101111
throw LOG.unknownStructureType();
102112
}
103-
if ( generator instanceof TableGenerator ) {
113+
if ( generator instanceof TableGenerator tableGenerator ) {
104114
return initialize(
105115
(IdentifierGenerator) generator,
106-
new TableReactiveIdentifierGenerator( (TableGenerator) generator, runtimeModelCreationContext ),
116+
new TableReactiveIdentifierGenerator( tableGenerator, runtimeModelCreationContext ),
107117
creationContext
108118
);
109119
}
110120
if ( generator instanceof SelectGenerator ) {
111121
throw LOG.selectGeneratorIsNotSupportedInHibernateReactive();
112122
}
123+
if ( generator instanceof CompositeNestedGeneratedValueGenerator compositeNestedGeneratedValueGenerator ) {
124+
final ReactiveCompositeNestedGeneratedValueGenerator reactiveCompositeNestedGeneratedValueGenerator = new ReactiveCompositeNestedGeneratedValueGenerator(
125+
compositeNestedGeneratedValueGenerator,
126+
creationContext,
127+
runtimeModelCreationContext
128+
);
129+
return initialize(
130+
(IdentifierGenerator) generator,
131+
reactiveCompositeNestedGeneratedValueGenerator,
132+
creationContext
133+
);
134+
}
113135
//nothing to do
114136
return generator;
115137
}
@@ -121,4 +143,57 @@ private static Generator initialize(
121143
( (Configurable) reactiveIdGenerator ).initialize( creationContext.getSqlStringGenerationContext() );
122144
return new ReactiveGeneratorWrapper( reactiveIdGenerator, idGenerator );
123145
}
146+
147+
private record IdGeneratorCreationContext(
148+
RootClass rootClass,
149+
Property property,
150+
GeneratorSettings defaults,
151+
SimpleValue identifier,
152+
RuntimeModelCreationContext buildingContext) implements GeneratorCreationContext {
153+
154+
@Override
155+
public Database getDatabase() {
156+
return buildingContext.getBootModel().getDatabase();
157+
}
158+
159+
@Override
160+
public ServiceRegistry getServiceRegistry() {
161+
return buildingContext.getBootstrapContext().getServiceRegistry();
162+
}
163+
164+
@Override
165+
public SqlStringGenerationContext getSqlStringGenerationContext() {
166+
return defaults.getSqlStringGenerationContext();
167+
}
168+
169+
@Override
170+
public String getDefaultCatalog() {
171+
return defaults.getDefaultCatalog();
172+
}
173+
174+
@Override
175+
public String getDefaultSchema() {
176+
return defaults.getDefaultSchema();
177+
}
178+
179+
@Override
180+
public RootClass getRootClass() {
181+
return rootClass;
182+
}
183+
184+
@Override
185+
public PersistentClass getPersistentClass() {
186+
return rootClass;
187+
}
188+
189+
@Override
190+
public Property getProperty() {
191+
return property;
192+
}
193+
194+
@Override
195+
public Type getType() {
196+
return identifier.getType();
197+
}
198+
}
124199
}

0 commit comments

Comments
 (0)