org.hibernate.id.CompositeNestedGeneratedValueGenerator Maven / Gradle / Ivy
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.id;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* For composite identifiers, defines a number of "nested" generations that
* need to happen to "fill" the identifier property(s).
*
* This generator is used implicitly for all composite identifier scenarios if an
* explicit generator is not in place. So it make sense to discuss the various
* potential scenarios:
* -
* "embedded" composite identifier - this is possible only in HBM mappings
* as {@code
} (notice the lack of both a name and class attribute
* declarations). The term {@link org.hibernate.mapping.Component#isEmbedded() "embedded"}
* here refers to the Hibernate usage which is actually the exact opposite of the JPA
* meaning of "embedded". Essentially this means that the entity class itself holds
* the named composite pk properties. This is very similar to the JPA {@code @IdClass}
* usage, though without a separate pk-class for loading.
*
* -
* pk-class as entity attribute - this is possible in both annotations ({@code @EmbeddedId})
* and HBM mappings ({@code
})
*
* -
* "embedded" composite identifier with a pk-class - this is the JPA {@code @IdClass} use case
* and is only possible in annotations
*
*
*
* Most of the grunt work is done in {@link org.hibernate.mapping.Component}.
*
* @author Steve Ebersole
*/
public class CompositeNestedGeneratedValueGenerator implements IdentifierGenerator, Serializable, IdentifierGeneratorAggregator {
/**
* Contract for declaring how to locate the context for sub-value injection.
*/
public interface GenerationContextLocator {
/**
* Given the incoming object, determine the context for injecting back its generated
* id sub-values.
*
* @param session The current session
* @param incomingObject The entity for which we are generating id
*
* @return The injection context
*/
Serializable locateGenerationContext(SharedSessionContractImplementor session, Object incomingObject);
}
/**
* Contract for performing the actual sub-value generation, usually injecting it into the
* determined {@link GenerationContextLocator#locateGenerationContext context}
*/
public interface GenerationPlan extends ExportableProducer {
/**
* Execute the value generation.
*
* @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);
}
private final GenerationContextLocator generationContextLocator;
private List generationPlans = new ArrayList<>();
public CompositeNestedGeneratedValueGenerator(GenerationContextLocator generationContextLocator) {
this.generationContextLocator = generationContextLocator;
}
public void addGeneratedValuePlan(GenerationPlan plan) {
generationPlans.add( plan );
}
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
final Serializable context = generationContextLocator.locateGenerationContext( session, object );
for ( Object generationPlan : generationPlans ) {
final GenerationPlan plan = (GenerationPlan) generationPlan;
plan.execute( session, object, context );
}
return context;
}
@Override
public void registerExportables(Database database) {
for (GenerationPlan plan : generationPlans) {
plan.registerExportables( database );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy