HHH-15074 Handle composite nested value generation for java records

This commit is contained in:
Marco Belladelli 2023-11-01 22:01:33 +01:00
parent c558fb7a5c
commit 19d9d95a9e
2 changed files with 70 additions and 15 deletions

View File

@ -17,6 +17,8 @@ import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.factory.spi.StandardGenerator;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.type.CompositeType;
/**
* For composite identifiers, defines a number of "nested" generations that
@ -87,16 +89,35 @@ public class CompositeNestedGeneratedValueGenerator
*
* @param session The current session
* @param incomingObject The entity for which we are generating id
* @param injectionContext The context into which the generated value can be injected
*/
void execute(SharedSessionContractImplementor session, Object incomingObject, Object injectionContext);
Object execute(SharedSessionContractImplementor session, Object incomingObject);
/**
* Returns the {@link Setter injector} for the generated property.
* Used when the {@link CompositeType} is {@linkplain CompositeType#isMutable() mutable}.
*
* @see #getPropertyIndex()
*/
Setter getInjector();
/**
* Returns the index of the generated property.
* Used when the {@link CompositeType} is not {@linkplain CompositeType#isMutable() mutable}.
*
* @see #getInjector()
*/
int getPropertyIndex();
}
private final GenerationContextLocator generationContextLocator;
private final CompositeType compositeType;
private final List<GenerationPlan> generationPlans = new ArrayList<>();
public CompositeNestedGeneratedValueGenerator(GenerationContextLocator generationContextLocator) {
public CompositeNestedGeneratedValueGenerator(
GenerationContextLocator generationContextLocator,
CompositeType compositeType) {
this.generationContextLocator = generationContextLocator;
this.compositeType = compositeType;
}
public void addGeneratedValuePlan(GenerationPlan plan) {
@ -107,11 +128,29 @@ public class CompositeNestedGeneratedValueGenerator
public Object generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
final Object context = generationContextLocator.locateGenerationContext( session, object );
final List<Object> generatedValues = compositeType.isMutable() ?
null :
new ArrayList<>( generationPlans.size() );
for ( GenerationPlan generationPlan : generationPlans ) {
generationPlan.execute( session, object, context );
final Object generated = generationPlan.execute( session, object );
if ( generatedValues != null ) {
generatedValues.add( generated );
}
else {
generationPlan.getInjector().set( context, generated );
}
}
return context;
if ( generatedValues != null) {
final Object[] values = compositeType.getPropertyValues( context );
for ( int i = 0; i < generatedValues.size(); i++ ) {
values[generationPlans.get( i ).getPropertyIndex()] = generatedValues.get( i );
}
return compositeType.replacePropertyValues( context, values, session );
}
else {
return context;
}
}
@Override

View File

@ -578,20 +578,25 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
final CompositeNestedGeneratedValueGenerator.GenerationContextLocator locator =
new StandardGenerationContextLocator( rootClass.getEntityName() );
final CompositeNestedGeneratedValueGenerator generator = new CompositeNestedGeneratedValueGenerator( locator );
final CompositeNestedGeneratedValueGenerator generator = new CompositeNestedGeneratedValueGenerator(
locator,
getType()
);
for ( Property property : getProperties() ) {
final List<Property> properties = getProperties();
for ( int i = 0; i < properties.size(); i++ ) {
final Property property = properties.get( i );
if ( property.getValue().isSimpleValue() ) {
final SimpleValue value = (SimpleValue) property.getValue();
if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) {
// skip any 'assigned' generators, they would have been handled by
// the StandardGenerationContextLocator
Generator subgenerator = value.createGenerator( identifierGeneratorFactory, dialect, rootClass );
generator.addGeneratedValuePlan( new ValueGenerationPlan(
subgenerator,
injector( property, attributeDeclarer ) )
);
value.createGenerator( identifierGeneratorFactory, dialect, rootClass ),
getType().isMutable() ? injector( property, attributeDeclarer ) : null,
i
) );
}
}
}
@ -639,18 +644,29 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
public static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan {
private final Generator subgenerator;
private final Setter injector;
private final int propertyIndex;
public ValueGenerationPlan(Generator subgenerator, Setter injector) {
public ValueGenerationPlan(Generator subgenerator, Setter injector, int propertyIndex) {
this.subgenerator = subgenerator;
this.injector = injector;
this.propertyIndex = propertyIndex;
}
@Override
public void execute(SharedSessionContractImplementor session, Object incomingObject, Object injectionContext) {
public Setter getInjector() {
return injector;
}
@Override
public int getPropertyIndex() {
return propertyIndex;
}
@Override
public Object execute(SharedSessionContractImplementor session, Object incomingObject) {
if ( !subgenerator.generatedOnExecution( incomingObject, session ) ) {
final Object generatedId = ( (BeforeExecutionGenerator) subgenerator)
return ( (BeforeExecutionGenerator) subgenerator)
.generate( session, incomingObject, null, INSERT );
injector.set( injectionContext, generatedId );
}
else {
throw new IdentifierGenerationException( "Identity generation isn't supported for composite ids" );