HHH-15789 unify IdentifierGenerator with value generator stuff
This commit is contained in:
parent
1bd082bd3e
commit
a67cfd039e
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
|
|
@ -13,13 +13,14 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.tuple.AnnotationGenerator;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.GeneratorCreationContext;
|
||||
import org.hibernate.tuple.InMemoryGenerator;
|
||||
import org.hibernate.tuple.TimestampGenerators;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -44,22 +45,21 @@ import static org.hibernate.tuple.GenerationTiming.ALWAYS;
|
|||
@Deprecated(since = "6.2")
|
||||
@Internal
|
||||
public class SourceGeneration
|
||||
implements AnnotationGenerator<Source>, InMemoryGenerator, ValueGenerator<Object> {
|
||||
implements InMemoryGenerator, ValueGenerator<Object> {
|
||||
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
SourceGeneration.class.getName()
|
||||
);
|
||||
|
||||
private Class<?> propertyType;
|
||||
private ValueGenerator<?> valueGenerator;
|
||||
private final Class<?> propertyType;
|
||||
private final ValueGenerator<?> valueGenerator;
|
||||
|
||||
@Override
|
||||
public void initialize(Source annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
initialize( annotation, propertyType );
|
||||
public SourceGeneration(Source annotation, Member member, GeneratorCreationContext context) {
|
||||
this( annotation, context.getProperty().getType().getReturnedClass() );
|
||||
}
|
||||
|
||||
public void initialize(Source annotation, Class<?> propertyType) {
|
||||
public SourceGeneration(Source annotation, Class<?> propertyType) {
|
||||
this.propertyType = propertyType;
|
||||
switch ( annotation.value() ) {
|
||||
case DB:
|
||||
|
|
|
@ -1001,32 +1001,14 @@ public class ModelBinder {
|
|||
context -> implicitNamingStrategy.determineBasicColumnName( versionAttributeSource )
|
||||
);
|
||||
|
||||
Property prop = new Property();
|
||||
prop.setValue( versionValue );
|
||||
Property property = new Property();
|
||||
property.setValue( versionValue );
|
||||
bindProperty(
|
||||
sourceDocument,
|
||||
versionAttributeSource,
|
||||
prop
|
||||
property
|
||||
);
|
||||
|
||||
// for version properties marked as being generated, make sure they are "always"
|
||||
// generated; aka, "insert" is invalid; this is dis-allowed by the DTD,
|
||||
// but just to make sure...
|
||||
if ( prop.getValueGenerationStrategy() != null ) {
|
||||
switch ( prop.getValueGenerationStrategy().getGenerationTiming() ) {
|
||||
case INSERT:
|
||||
throw new MappingException(
|
||||
"'generated' attribute cannot be 'insert' for version/timestamp property",
|
||||
sourceDocument.getOrigin()
|
||||
);
|
||||
case UPDATE:
|
||||
throw new MappingException(
|
||||
"'generated' attribute cannot be 'update' for version/timestamp property",
|
||||
sourceDocument.getOrigin()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( versionAttributeSource.getUnsavedValue() != null ) {
|
||||
versionValue.setNullValue( versionAttributeSource.getUnsavedValue() );
|
||||
}
|
||||
|
@ -1034,14 +1016,13 @@ public class ModelBinder {
|
|||
versionValue.setNullValue( "undefined" );
|
||||
}
|
||||
if ( versionAttributeSource.getSource().equals("db") ) {
|
||||
SourceGeneration generation = new SourceGeneration();
|
||||
generation.initialize( DB_SOURCE, prop.getType().getReturnedClass() );
|
||||
prop.setValueGenerationStrategy( generation );
|
||||
property.setValueGenerationStrategy(
|
||||
context -> new SourceGeneration( DB_SOURCE, property.getType().getReturnedClass() ) );
|
||||
}
|
||||
|
||||
rootEntityDescriptor.setVersion( prop );
|
||||
rootEntityDescriptor.setDeclaredVersion( prop );
|
||||
rootEntityDescriptor.addProperty( prop );
|
||||
rootEntityDescriptor.setVersion( property );
|
||||
rootEntityDescriptor.setDeclaredVersion( property );
|
||||
rootEntityDescriptor.addProperty( property );
|
||||
}
|
||||
|
||||
private void bindEntityDiscriminator(
|
||||
|
@ -2557,10 +2538,18 @@ public class ModelBinder {
|
|||
property.setLazy( singularAttributeSource.isBytecodeLazy() );
|
||||
|
||||
final GenerationTiming generationTiming = singularAttributeSource.getGenerationTiming();
|
||||
if ( generationTiming != null && generationTiming != GenerationTiming.NEVER ) {
|
||||
// we had generation specified...
|
||||
// HBM only supports "database generated values"
|
||||
property.setValueGenerationStrategy( new GeneratedValueGeneration( generationTiming ) );
|
||||
if ( generationTiming != null ) {
|
||||
if ( (generationTiming == GenerationTiming.INSERT || generationTiming == GenerationTiming.UPDATE)
|
||||
&& property.getValue() instanceof SimpleValue
|
||||
&& ((SimpleValue) property.getValue()).isVersion() ) {
|
||||
// this is enforced by DTD, but just make sure
|
||||
throw new MappingException(
|
||||
"'generated' attribute cannot be 'insert' or 'update' for version/timestamp property",
|
||||
mappingDocument.getOrigin()
|
||||
);
|
||||
}
|
||||
if ( generationTiming.isNotNever() ) {
|
||||
property.setValueGenerationStrategy( context -> new GeneratedValueGeneration( generationTiming ) );
|
||||
|
||||
// generated properties can *never* be insertable...
|
||||
if ( property.isInsertable() && generationTiming.includesInsert() ) {
|
||||
|
@ -2584,6 +2573,7 @@ public class ModelBinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property.setMetaAttributes( propertySource.getToolingHintContext().getMetaAttributeMap() );
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
package org.hibernate.cfg;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
|
@ -19,7 +17,6 @@ import java.util.Map;
|
|||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
|
@ -72,14 +69,12 @@ import org.hibernate.boot.spi.InFlightMetadataCollector;
|
|||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.annotations.CollectionBinder;
|
||||
import org.hibernate.cfg.annotations.EntityBinder;
|
||||
import org.hibernate.cfg.annotations.HCANNHelper;
|
||||
import org.hibernate.cfg.annotations.Nullability;
|
||||
import org.hibernate.cfg.annotations.PropertyBinder;
|
||||
import org.hibernate.cfg.annotations.QueryBinder;
|
||||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.spi.FilterDefinition;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.GenericsHelper;
|
||||
import org.hibernate.mapping.Any;
|
||||
|
@ -157,6 +152,7 @@ import static org.hibernate.cfg.InheritanceState.getInheritanceStateOfSuperEntit
|
|||
import static org.hibernate.cfg.InheritanceState.getSuperclassInheritanceState;
|
||||
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
|
||||
import static org.hibernate.cfg.annotations.HCANNHelper.findContainingAnnotation;
|
||||
import static org.hibernate.cfg.annotations.PropertyBinder.identifierGeneratorCreator;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
import static org.hibernate.mapping.Constraint.hashedName;
|
||||
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
|
||||
|
@ -1812,7 +1808,7 @@ public final class AnnotationBinder {
|
|||
final XProperty idProperty = inferredData.getProperty();
|
||||
final Annotation generatorAnnotation = findContainingAnnotation( idProperty, IdGeneratorType.class );
|
||||
if ( generatorAnnotation != null ) {
|
||||
setCustomCreator( idValue, idProperty, generatorAnnotation );
|
||||
idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, generatorAnnotation ) );
|
||||
}
|
||||
else {
|
||||
final XClass entityClass = inferredData.getClassOrElement();
|
||||
|
@ -1827,33 +1823,6 @@ public final class AnnotationBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static void setCustomCreator(SimpleValue idValue, XProperty idProperty, Annotation generatorAnnotation) {
|
||||
final Member underlyingMember = HCANNHelper.getUnderlyingMember( idProperty );
|
||||
final Class<? extends Annotation> annotationType = generatorAnnotation.annotationType();
|
||||
final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class );
|
||||
assert idGeneratorType != null;
|
||||
idValue.setCustomIdGeneratorCreator( creationContext -> {
|
||||
final Class<? extends IdentifierGenerator> generatorClass = idGeneratorType.value();
|
||||
try {
|
||||
return generatorClass
|
||||
.getConstructor( annotationType, Member.class, CustomIdGeneratorCreationContext.class )
|
||||
.newInstance( generatorAnnotation, underlyingMember, creationContext );
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new HibernateException(
|
||||
"Unable to find appropriate constructor for @IdGeneratorType handling : " + generatorClass.getName(),
|
||||
e
|
||||
);
|
||||
}
|
||||
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
throw new HibernateException(
|
||||
"Unable to invoke constructor for @IdGeneratorType handling : " + generatorClass.getName(),
|
||||
e
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private static void createIdGenerator(
|
||||
SimpleValue idValue,
|
||||
Map<String, IdentifierGeneratorDefinition> classGenerators,
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.hibernate.AnnotationException;
|
|||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.AttributeBinderType;
|
||||
import org.hibernate.annotations.Generated;
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
|
@ -29,9 +29,13 @@ import org.hibernate.cfg.AnnotatedColumn;
|
|||
import org.hibernate.cfg.InheritanceState;
|
||||
import org.hibernate.cfg.PropertyHolder;
|
||||
import org.hibernate.cfg.PropertyPreloadedData;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.GeneratorCreator;
|
||||
import org.hibernate.mapping.IdentifierGeneratorCreator;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
|
@ -43,13 +47,13 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
|||
import org.hibernate.tuple.AnnotationGenerator;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.tuple.AttributeBinder;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
import org.hibernate.tuple.GeneratorCreationContext;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.ValueGeneration;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hibernate.cfg.BinderHelper.getMappedSuperclassOrNull;
|
||||
|
@ -322,7 +326,7 @@ public class PropertyBinder {
|
|||
if ( this.property != null ) {
|
||||
if ( entityBinder != null ) {
|
||||
handleNaturalId( property );
|
||||
property.setValueGenerationStrategy( determineValueGenerationStrategy( this.property ) );
|
||||
property.setValueGenerationStrategy( getValueGenerationFromAnnotations( this.property ) );
|
||||
}
|
||||
// HHH-4635 -- needed for dialect-specific property ordering
|
||||
property.setLob( this.property.isAnnotationPresent( Lob.class ) );
|
||||
|
@ -379,143 +383,137 @@ public class PropertyBinder {
|
|||
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" );
|
||||
}
|
||||
if ( property.isAnnotationPresent(EmbeddedId.class) ) {
|
||||
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
|
||||
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
|
||||
+ "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Generator determineValueGenerationStrategy(XProperty property) {
|
||||
Generator valueGeneration = getValueGenerationFromAnnotations( property );
|
||||
if ( valueGeneration == null ) {
|
||||
return NoValueGeneration.INSTANCE;
|
||||
}
|
||||
if ( valueGeneration instanceof InDatabaseGenerator) {
|
||||
// if we have an in-db generator, mark it as not insertable nor updatable
|
||||
final boolean writable = ( (InDatabaseGenerator) valueGeneration ).writePropertyValue();
|
||||
insertable = writable;
|
||||
updatable = writable;
|
||||
}
|
||||
return valueGeneration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value generation strategy for the given property, if any.
|
||||
*/
|
||||
private Generator getValueGenerationFromAnnotations(XProperty property) {
|
||||
Generator valueGeneration = null;
|
||||
private GeneratorCreator getValueGenerationFromAnnotations(XProperty property) {
|
||||
GeneratorCreator creator = null;
|
||||
for ( Annotation annotation : property.getAnnotations() ) {
|
||||
final Generator candidate = getValueGenerationFromAnnotation( property, annotation );
|
||||
final GeneratorCreator candidate = generatorCreator( property, annotation );
|
||||
if ( candidate != null ) {
|
||||
if ( valueGeneration != null ) {
|
||||
if ( creator != null ) {
|
||||
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
|
||||
+ "' has multiple '@ValueGenerationType' annotations" );
|
||||
}
|
||||
else {
|
||||
valueGeneration = candidate;
|
||||
creator = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valueGeneration;
|
||||
return creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case the given annotation is a value generator annotation, the corresponding value generation strategy to be
|
||||
* applied to the given property is returned, {@code null} otherwise.
|
||||
*/
|
||||
private Generator getValueGenerationFromAnnotation(
|
||||
XProperty property,
|
||||
Annotation annotation) {
|
||||
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );
|
||||
if ( generatorAnnotation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Generator valueGeneration =
|
||||
instantiateAndInitializeValueGeneration( annotation, generatorAnnotation.generatedBy(), property );
|
||||
|
||||
if ( annotation.annotationType() == Generated.class && property.isAnnotationPresent(Version.class) ) {
|
||||
switch ( valueGeneration.getGenerationTiming() ) {
|
||||
case INSERT:
|
||||
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
|
||||
+ "' is annotated '@Generated(INSERT)' and '@Version' (use '@Generated(ALWAYS)' instead)"
|
||||
|
||||
);
|
||||
case UPDATE:
|
||||
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
|
||||
+ "' is annotated '@Generated(UPDATE)' and '@Version' (use '@Generated(ALWAYS)' instead)"
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return valueGeneration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the given generator annotation type, initializing it with the given instance of the corresponding
|
||||
* generator annotation and the property's type.
|
||||
*/
|
||||
private <A extends Annotation> Generator instantiateAndInitializeValueGeneration(
|
||||
A annotation,
|
||||
Class<? extends Generator> generationType,
|
||||
XProperty property) {
|
||||
private <A extends Annotation> GeneratorCreator generatorCreator(XProperty property, A annotation) {
|
||||
final Member member = HCANNHelper.getUnderlyingMember( property );
|
||||
final Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final ValueGenerationType generatorAnnotation = annotationType.getAnnotation( ValueGenerationType.class );
|
||||
if ( generatorAnnotation == null ) {
|
||||
return null;
|
||||
}
|
||||
return creationContext -> {
|
||||
final Generator generator =
|
||||
instantiateGenerator(
|
||||
annotation,
|
||||
member,
|
||||
annotationType,
|
||||
creationContext,
|
||||
GeneratorCreationContext.class,
|
||||
generatorAnnotation.generatedBy()
|
||||
);
|
||||
callInitialize( annotation, member, creationContext, generator );
|
||||
checkVersionGenerationAlways( property, generator );
|
||||
return generator;
|
||||
};
|
||||
}
|
||||
|
||||
public static IdentifierGeneratorCreator identifierGeneratorCreator(XProperty idProperty, Annotation annotation) {
|
||||
final Member member = HCANNHelper.getUnderlyingMember( idProperty );
|
||||
final Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class );
|
||||
assert idGeneratorType != null;
|
||||
return creationContext -> {
|
||||
final IdentifierGenerator generator =
|
||||
instantiateGenerator(
|
||||
annotation,
|
||||
member,
|
||||
annotationType,
|
||||
creationContext,
|
||||
CustomIdGeneratorCreationContext.class,
|
||||
idGeneratorType.value()
|
||||
);
|
||||
callInitialize( annotation, member, creationContext, generator );
|
||||
return generator;
|
||||
};
|
||||
}
|
||||
|
||||
private static <C, G extends Generator> G instantiateGenerator(
|
||||
Annotation annotation,
|
||||
Member member,
|
||||
Class<? extends Annotation> annotationType,
|
||||
C creationContext,
|
||||
Class<C> contextClass,
|
||||
Class<? extends G> generatorClass) {
|
||||
try {
|
||||
final Generator valueGeneration = generationType.newInstance();
|
||||
if ( valueGeneration instanceof AnnotationGenerator) {
|
||||
try {
|
||||
return generatorClass
|
||||
.getConstructor( annotationType, Member.class, contextClass )
|
||||
.newInstance( annotation, member, creationContext);
|
||||
}
|
||||
catch (NoSuchMethodException ignore) {
|
||||
try {
|
||||
return generatorClass
|
||||
.getConstructor( annotationType )
|
||||
.newInstance( annotation );
|
||||
}
|
||||
catch (NoSuchMethodException i) {
|
||||
return generatorClass.newInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException|InstantiationException|IllegalAccessException e) {
|
||||
throw new HibernateException(
|
||||
"Could not instantiate generator of type '" + generatorClass.getName() + "'",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static <A extends Annotation> void callInitialize(
|
||||
A annotation,
|
||||
Member member,
|
||||
GeneratorCreationContext creationContext,
|
||||
Generator generator) {
|
||||
if ( generator instanceof AnnotationGenerator) {
|
||||
// This will cause a CCE in case the generation type doesn't match the annotation type; As this would be
|
||||
// a programming error of the generation type developer and thus should show up during testing, we don't
|
||||
// check this explicitly; If required, this could be done e.g. using ClassMate
|
||||
@SuppressWarnings("unchecked")
|
||||
final AnnotationGenerator<A> generation = (AnnotationGenerator<A>) valueGeneration;
|
||||
generation.initialize(
|
||||
annotation,
|
||||
buildingContext.getBootstrapContext().getReflectionManager().toClass( property.getType() ),
|
||||
entityBinder.getPersistentClass().getEntityName(),
|
||||
property.getName()
|
||||
final AnnotationGenerator<A> generation = (AnnotationGenerator<A>) generator;
|
||||
generation.initialize( annotation, member, creationContext );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkVersionGenerationAlways(XProperty property, Generator generator) {
|
||||
if ( property.isAnnotationPresent(Version.class) ) {
|
||||
final GenerationTiming timing = generator.getGenerationTiming();
|
||||
if ( timing != GenerationTiming.ALWAYS ) {
|
||||
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
|
||||
+ "' is annotated '@Version' but has a value generator with timing " + timing.name()
|
||||
+ " (the value generation timing must be ALWAYS)"
|
||||
);
|
||||
}
|
||||
|
||||
return valueGeneration;
|
||||
}
|
||||
catch (HibernateException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AnnotationException(
|
||||
"Exception occurred during processing of generator annotation: " + qualify(
|
||||
holder.getPath(),
|
||||
name
|
||||
), e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoValueGeneration implements ValueGeneration {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NoValueGeneration INSTANCE = new NoValueGeneration();
|
||||
|
||||
@Override
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
return GenerationTiming.NEVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueGenerator<?> getValueGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnInSql() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
|||
import org.hibernate.engine.spi.CascadingActions;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.InMemoryGenerator;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -74,7 +73,7 @@ public final class Nullability {
|
|||
/*
|
||||
* Algorithm
|
||||
* Check for any level one nullability breaks
|
||||
* Look at non null components to
|
||||
* Look at non-null components to
|
||||
* recursively check next level of nullability breaks
|
||||
* Look at Collections containing components to
|
||||
* recursively check next level of nullability breaks
|
||||
|
@ -82,7 +81,7 @@ public final class Nullability {
|
|||
*
|
||||
* In the previous implementation, not-null stuffs where checked
|
||||
* filtering by level one only updatable
|
||||
* or insertable columns. So setting a sub component as update="false"
|
||||
* or insertable columns. So setting a subcomponent as update="false"
|
||||
* has no effect on not-null check if the main component had good checkability
|
||||
* In this implementation, we keep this feature.
|
||||
* However, I never see any documentation mentioning that, but it's for
|
||||
|
@ -94,14 +93,13 @@ public final class Nullability {
|
|||
? persister.getPropertyInsertability()
|
||||
: persister.getPropertyUpdateability();
|
||||
final Type[] propertyTypes = persister.getPropertyTypes();
|
||||
final InMemoryGenerator[] inMemoryValueGenerationStrategies =
|
||||
persister.getEntityMetamodel().getInMemoryValueGenerationStrategies();
|
||||
final Generator[] generators = persister.getEntityMetamodel().getGenerators();
|
||||
|
||||
for ( int i = 0; i < values.length; i++ ) {
|
||||
|
||||
if ( checkability[i] &&
|
||||
values[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
|
||||
GenerationTiming.NEVER == inMemoryValueGenerationStrategies[i].getGenerationTiming() ) {
|
||||
if ( checkability[i]
|
||||
&& values[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||
&& !generated( generators[i] ) ) {
|
||||
final Object value = values[i];
|
||||
if ( !nullability[i] && value == null ) {
|
||||
//check basic level one nullability
|
||||
|
@ -130,6 +128,10 @@ public final class Nullability {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean generated(Generator generator) {
|
||||
return generator != null && generator.getGenerationTiming().isNotNever();
|
||||
}
|
||||
|
||||
/**
|
||||
* check sub elements-nullability. Returns property path that break
|
||||
* nullability or null if none
|
||||
|
|
|
@ -55,7 +55,7 @@ public interface IdentifierGenerator extends InMemoryGenerator, ExportableProduc
|
|||
* identifier generator.
|
||||
*
|
||||
* @see org.hibernate.annotations.GenericGenerator#name()
|
||||
* @see jakarta.persistence.GeneratedValue#generator().
|
||||
* @see jakarta.persistence.GeneratedValue#generator()
|
||||
*/
|
||||
String GENERATOR_NAME = "GENERATOR_NAME";
|
||||
|
||||
|
|
|
@ -7,19 +7,12 @@
|
|||
package org.hibernate.id.factory.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.tuple.GeneratorCreationContext;
|
||||
|
||||
@Incubating
|
||||
public interface CustomIdGeneratorCreationContext {
|
||||
public interface CustomIdGeneratorCreationContext extends GeneratorCreationContext {
|
||||
IdentifierGeneratorFactory getIdentifierGeneratorFactory();
|
||||
Database getDatabase();
|
||||
ServiceRegistry getServiceRegistry();
|
||||
|
||||
String getDefaultCatalog();
|
||||
String getDefaultSchema();
|
||||
|
||||
RootClass getRootClass();
|
||||
}
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.id.uuid;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -19,6 +17,7 @@ import org.hibernate.type.descriptor.java.UUIDJavaType;
|
|||
import org.hibernate.type.descriptor.java.UUIDJavaType.ValueTransformer;
|
||||
|
||||
import static org.hibernate.annotations.UuidGenerator.Style.TIME;
|
||||
import static org.hibernate.internal.util.ReflectHelper.getPropertyType;
|
||||
|
||||
/**
|
||||
* UUID-based IdentifierGenerator
|
||||
|
@ -44,13 +43,7 @@ public class UuidGenerator implements StandardGenerator {
|
|||
generator = StandardRandomStrategy.INSTANCE;
|
||||
}
|
||||
|
||||
final Class<?> propertyType;
|
||||
if ( idMember instanceof Method ) {
|
||||
propertyType = ( (Method) idMember ).getReturnType();
|
||||
}
|
||||
else {
|
||||
propertyType = ( (Field) idMember ).getType();
|
||||
}
|
||||
final Class<?> propertyType = getPropertyType( idMember );
|
||||
|
||||
if ( UUID.class.isAssignableFrom( propertyType ) ) {
|
||||
valueTransformer = UUIDJavaType.PassThroughTransformer.INSTANCE;
|
||||
|
|
|
@ -876,4 +876,16 @@ public final class ReflectHelper {
|
|||
}
|
||||
throw new UnsupportedOperationException( "Can't get java type class from type: " + type );
|
||||
}
|
||||
|
||||
public static Class<?> getPropertyType(Member member) {
|
||||
if (member instanceof Field) {
|
||||
return ( (Field) member ).getType();
|
||||
}
|
||||
else if (member instanceof Method) {
|
||||
return ( (Method) member ).getReturnType();
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure("member should have been a method or field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.tuple.GeneratorCreationContext;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface GeneratorCreator {
|
||||
Generator createGenerator(GeneratorCreationContext context);
|
||||
}
|
|
@ -46,7 +46,17 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
|
||||
private static final Alias PK_ALIAS = new Alias( 15, "PK" );
|
||||
|
||||
/**
|
||||
* The magic value of {@link jakarta.persistence.DiscriminatorValue#value}
|
||||
* which indicates that the subclass is distinguished by a null value of the
|
||||
* discriminator column.
|
||||
*/
|
||||
public static final String NULL_DISCRIMINATOR_MAPPING = "null";
|
||||
/**
|
||||
* The magic value of {@link jakarta.persistence.DiscriminatorValue#value}
|
||||
* which indicates that the subclass is distinguished by any non-null value
|
||||
* of the discriminator column.
|
||||
*/
|
||||
public static final String NOT_NULL_DISCRIMINATOR_MAPPING = "not null";
|
||||
|
||||
private final MetadataBuildingContext metadataBuildingContext;
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
|||
import org.hibernate.property.access.spi.PropertyAccessStrategyResolver;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -45,7 +44,7 @@ public class Property implements Serializable, MetaAttributable {
|
|||
private boolean insertable = true;
|
||||
private boolean selectable = true;
|
||||
private boolean optimisticLocked = true;
|
||||
private Generator generator;
|
||||
private GeneratorCreator generator;
|
||||
private String propertyAccessorName;
|
||||
private PropertyAccessStrategy propertyAccessStrategy;
|
||||
private boolean lazy;
|
||||
|
@ -216,11 +215,11 @@ public class Property implements Serializable, MetaAttributable {
|
|||
return insertable && value.hasAnyInsertableColumns();
|
||||
}
|
||||
|
||||
public Generator getValueGenerationStrategy() {
|
||||
public GeneratorCreator getValueGenerationStrategy() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
public void setValueGenerationStrategy(Generator generator) {
|
||||
public void setValueGenerationStrategy(GeneratorCreator generator) {
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.Remove;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
@ -30,7 +31,9 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
public class RootClass extends PersistentClass implements TableOwner {
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( RootClass.class );
|
||||
|
||||
@Deprecated(since = "6.2") @Remove
|
||||
public static final String DEFAULT_IDENTIFIER_COLUMN_NAME = "id";
|
||||
@Deprecated(since = "6.2") @Remove
|
||||
public static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "class";
|
||||
|
||||
private Property identifierProperty;
|
||||
|
|
|
@ -363,11 +363,9 @@ public abstract class SimpleValue implements KeyValue {
|
|||
private IdentifierGenerator identifierGenerator;
|
||||
|
||||
/**
|
||||
* Returns the cached identifierGenerator.
|
||||
*
|
||||
* @return IdentifierGenerator null if
|
||||
* {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, String, String, RootClass)} was never
|
||||
* completed.
|
||||
* Returns the cached {@link IdentifierGenerator}, or null if
|
||||
* {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, String, String, RootClass)}
|
||||
* was never completed.
|
||||
*
|
||||
* @deprecated not used and no longer supported.
|
||||
*/
|
||||
|
@ -434,6 +432,16 @@ public abstract class SimpleValue implements KeyValue {
|
|||
public RootClass getRootClass() {
|
||||
return rootClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentClass getPersistentClass() {
|
||||
return rootClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty() {
|
||||
return rootClass.getIdentifierProperty();
|
||||
}
|
||||
};
|
||||
|
||||
identifierGenerator = customIdGeneratorCreator.createGenerator( creationContext );
|
||||
|
@ -761,14 +769,7 @@ public abstract class SimpleValue implements KeyValue {
|
|||
if ( className == null ) {
|
||||
throw new MappingException( "Attribute types for a dynamic entity must be explicitly specified: " + propertyName );
|
||||
}
|
||||
typeName = ReflectHelper.reflectedPropertyClass(
|
||||
className,
|
||||
propertyName,
|
||||
getMetadata()
|
||||
.getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.getService( ClassLoaderService.class )
|
||||
).getName();
|
||||
typeName = getClass( className, propertyName ).getName();
|
||||
// todo : to fully support isNationalized here we need to do the process hinted at above
|
||||
// essentially, much of the logic from #buildAttributeConverterTypeAdapter wrt resolving
|
||||
// a (1) JdbcType, a (2) JavaType and dynamically building a BasicType
|
||||
|
@ -780,6 +781,17 @@ public abstract class SimpleValue implements KeyValue {
|
|||
type = buildAttributeConverterTypeAdapter();
|
||||
}
|
||||
|
||||
private Class<?> getClass(String className, String propertyName) {
|
||||
return ReflectHelper.reflectedPropertyClass(
|
||||
className,
|
||||
propertyName,
|
||||
getMetadata()
|
||||
.getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.getService(ClassLoaderService.class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Hibernate Type that incorporates the JPA AttributeConverter. AttributeConverter works totally in
|
||||
* memory, meaning it converts between one Java representation (the entity attribute representation) and another
|
||||
|
|
|
@ -70,7 +70,7 @@ public interface AttributeMapping
|
|||
*
|
||||
* @apiNote Only relevant for non-id attributes
|
||||
*/
|
||||
Generator getValueGeneration();
|
||||
Generator getGenerator();
|
||||
|
||||
@Override
|
||||
default EntityMappingType findContainingEntityMapping() {
|
||||
|
|
|
@ -21,26 +21,18 @@ import org.hibernate.tuple.InMemoryGenerator;
|
|||
@Incubating
|
||||
public interface GeneratedValueResolver {
|
||||
static GeneratedValueResolver from(
|
||||
Generator valueGeneration,
|
||||
Generator generator,
|
||||
GenerationTiming requestedTiming,
|
||||
int dbSelectionPosition) {
|
||||
assert requestedTiming != GenerationTiming.NEVER;
|
||||
assert requestedTiming.isNotNever();
|
||||
|
||||
if ( valueGeneration == null || !valueGeneration.getGenerationTiming().includes( requestedTiming ) ) {
|
||||
if ( generator == null || !generator.getGenerationTiming().includes( requestedTiming ) ) {
|
||||
return NoGeneratedValueResolver.INSTANCE;
|
||||
}
|
||||
// todo (6.x) : incorporate `org.hibernate.tuple.InDatabaseValueGenerationStrategy`
|
||||
// and `org.hibernate.tuple.InMemoryValueGenerationStrategy` from `EntityMetamodel`.
|
||||
// this requires unification of the read and write (insert/update) aspects of
|
||||
// value generation which we'll circle back to as we convert write operations to
|
||||
// use the "runtime mapping" (`org.hibernate.metamodel.mapping`) model
|
||||
else if ( valueGeneration.generatedByDatabase() ) {
|
||||
// in-db generation (column-default, function, etc)
|
||||
return new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition );
|
||||
}
|
||||
else {
|
||||
InMemoryGenerator generation = (InMemoryGenerator) valueGeneration;
|
||||
return new InMemoryGeneratedValueResolver( generation, requestedTiming );
|
||||
return generator.generatedByDatabase()
|
||||
? new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition ) // in-db generation (column-default, function, etc)
|
||||
: new InMemoryGeneratedValueResolver( (InMemoryGenerator) generator, requestedTiming );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -156,7 +156,6 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
|
|||
declaringType,
|
||||
original,
|
||||
original.getPropertyAccess(),
|
||||
original.getValueGeneration(),
|
||||
selectableMapping.isInsertable(),
|
||||
selectableMapping.isUpdateable(),
|
||||
selectableMapping
|
||||
|
|
|
@ -23,7 +23,6 @@ public abstract class AbstractSingularAttributeMapping
|
|||
implements SingularAttributeMapping {
|
||||
|
||||
private final PropertyAccess propertyAccess;
|
||||
private final Generator valueGeneration;
|
||||
|
||||
public AbstractSingularAttributeMapping(
|
||||
String name,
|
||||
|
@ -31,13 +30,9 @@ public abstract class AbstractSingularAttributeMapping
|
|||
AttributeMetadataAccess attributeMetadataAccess,
|
||||
FetchOptions mappedFetchOptions,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super( name, attributeMetadataAccess, mappedFetchOptions, stateArrayPosition, declaringType );
|
||||
this.propertyAccess = propertyAccess;
|
||||
this.valueGeneration = valueGeneration != null
|
||||
? valueGeneration
|
||||
: NoValueGeneration.INSTANCE;
|
||||
}
|
||||
|
||||
public AbstractSingularAttributeMapping(
|
||||
|
@ -47,13 +42,9 @@ public abstract class AbstractSingularAttributeMapping
|
|||
FetchTiming fetchTiming,
|
||||
FetchStyle fetchStyle,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super( name, attributeMetadataAccess, fetchTiming, fetchStyle, stateArrayPosition, declaringType );
|
||||
this.propertyAccess = propertyAccess;
|
||||
this.valueGeneration = valueGeneration != null
|
||||
? valueGeneration
|
||||
: NoValueGeneration.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +53,7 @@ public abstract class AbstractSingularAttributeMapping
|
|||
}
|
||||
|
||||
@Override
|
||||
public Generator getValueGeneration() {
|
||||
return valueGeneration;
|
||||
public Generator getGenerator() {
|
||||
return findContainingEntityMapping().getEntityPersister().getEntityMetamodel().getGenerators()[getStateArrayPosition()];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.function.BiConsumer;
|
|||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.mapping.GeneratorCreator;
|
||||
import org.hibernate.mapping.IndexedConsumer;
|
||||
import org.hibernate.metamodel.mapping.AttributeMetadataAccess;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
|
@ -36,7 +37,6 @@ import org.hibernate.sql.results.graph.Fetch;
|
|||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
|
@ -86,8 +86,7 @@ public class BasicAttributeMapping
|
|||
boolean updateable,
|
||||
JdbcMapping jdbcMapping,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super(
|
||||
attributeName,
|
||||
stateArrayPosition,
|
||||
|
@ -95,8 +94,7 @@ public class BasicAttributeMapping
|
|||
mappedFetchTiming,
|
||||
mappedFetchStyle,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
this.navigableRole = navigableRole;
|
||||
this.tableExpression = tableExpression;
|
||||
|
@ -126,7 +124,6 @@ public class BasicAttributeMapping
|
|||
ManagedMappingType declaringType,
|
||||
BasicValuedModelPart original,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration,
|
||||
boolean insertable,
|
||||
boolean updateable,
|
||||
SelectableMapping selectableMapping) {
|
||||
|
@ -168,8 +165,7 @@ public class BasicAttributeMapping
|
|||
updateable,
|
||||
original.getJdbcMapping(),
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,8 +85,7 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
fetchTiming,
|
||||
FetchStyle.SELECT,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
null
|
||||
propertyAccess
|
||||
);
|
||||
this.navigableRole = attributeRole;
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ import org.hibernate.sql.results.graph.Fetchable;
|
|||
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
|
||||
import org.hibernate.tuple.Generator;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -79,8 +78,7 @@ public class EmbeddedAttributeMapping
|
|||
FetchStyle mappedFetchStyle,
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
this(
|
||||
name,
|
||||
navigableRole,
|
||||
|
@ -92,8 +90,7 @@ public class EmbeddedAttributeMapping
|
|||
mappedFetchStyle,
|
||||
embeddableMappingType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -108,8 +105,7 @@ public class EmbeddedAttributeMapping
|
|||
FetchStyle mappedFetchStyle,
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super(
|
||||
name,
|
||||
stateArrayPosition,
|
||||
|
@ -117,8 +113,7 @@ public class EmbeddedAttributeMapping
|
|||
mappedFetchTiming,
|
||||
mappedFetchStyle,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
this.navigableRole = navigableRole;
|
||||
|
||||
|
@ -145,7 +140,6 @@ public class EmbeddedAttributeMapping
|
|||
keyDeclaringType,
|
||||
inverseModelPart instanceof PropertyBasedMapping ?
|
||||
( (PropertyBasedMapping) inverseModelPart ).getPropertyAccess() :
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
|||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
import org.hibernate.tuple.Generator;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -59,43 +59,9 @@ public class GeneratedValuesProcessor {
|
|||
// NOTE: we only care about db-generated values here. in-memory generation
|
||||
// is applied before the insert/update happens.
|
||||
|
||||
final List<AttributeMapping> generatedValuesToSelect = new ArrayList<>();
|
||||
// todo (6.0): for now, we rely on the entity metamodel as composite attributes report GenerationTiming.NEVER
|
||||
// even if they have attributes that would need generation
|
||||
final InDatabaseGenerator[] inDatabaseValueGenerationStrategies = entityDescriptor.getEntityPersister()
|
||||
.getEntityMetamodel()
|
||||
.getInDatabaseValueGenerationStrategies();
|
||||
entityDescriptor.visitAttributeMappings( mapping -> {
|
||||
final InDatabaseGenerator inDatabaseValueGenerationStrategy =
|
||||
inDatabaseValueGenerationStrategies[ mapping.getStateArrayPosition() ];
|
||||
if ( inDatabaseValueGenerationStrategy.getGenerationTiming() == GenerationTiming.NEVER ) {
|
||||
return;
|
||||
}
|
||||
final GeneratedValueResolver generatedValueResolver = new InDatabaseGeneratedValueResolver(
|
||||
timing,
|
||||
generatedValuesToSelect.size()
|
||||
);
|
||||
// if ( attr.getValueGeneration().getGenerationTiming() == GenerationTiming.NEVER ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final GeneratedValueResolver generatedValueResolver = GeneratedValueResolver.from(
|
||||
// attr.getValueGeneration(),
|
||||
// timing,
|
||||
// generatedValuesToSelect.size()
|
||||
// );
|
||||
//
|
||||
// //noinspection RedundantClassCall
|
||||
// if ( ! InDatabaseGeneratedValueResolver.class.isInstance( generatedValueResolver ) ) {
|
||||
// // again, we only care about in in-db generations here
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this attribute is generated for the timing we are processing...
|
||||
valueDescriptors.add( new GeneratedValueDescriptor( generatedValueResolver, mapping ) );
|
||||
generatedValuesToSelect.add( mapping );
|
||||
});
|
||||
|
||||
// todo (6.0): for now, we rely on the entity metamodel as composite attributes report
|
||||
// GenerationTiming.NEVER even if they have attributes that would need generation
|
||||
final List<AttributeMapping> generatedValuesToSelect = getGeneratedValues( entityDescriptor, timing );
|
||||
if ( generatedValuesToSelect.isEmpty() ) {
|
||||
selectStatement = null;
|
||||
}
|
||||
|
@ -114,6 +80,25 @@ public class GeneratedValuesProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private List<AttributeMapping> getGeneratedValues(EntityMappingType entityDescriptor, GenerationTiming timing) {
|
||||
final Generator[] generators = entityDescriptor.getEntityPersister().getEntityMetamodel().getGenerators();
|
||||
final List<AttributeMapping> generatedValuesToSelect = new ArrayList<>();
|
||||
entityDescriptor.visitAttributeMappings( mapping -> {
|
||||
final Generator generator = generators[ mapping.getStateArrayPosition() ];
|
||||
if ( generator != null
|
||||
&& generator.generatedByDatabase()
|
||||
&& generator.getGenerationTiming().isNotNever() ) {
|
||||
// this attribute is generated for the timing we are processing...
|
||||
valueDescriptors.add( new GeneratedValueDescriptor(
|
||||
new InDatabaseGeneratedValueResolver( timing, generatedValuesToSelect.size() ),
|
||||
mapping
|
||||
) );
|
||||
generatedValuesToSelect.add( mapping );
|
||||
}
|
||||
} );
|
||||
return generatedValuesToSelect;
|
||||
}
|
||||
|
||||
public void processGeneratedValues(Object entity, Object id, Object[] state, SharedSessionContractImplementor session) {
|
||||
if ( selectStatement == null ) {
|
||||
return;
|
||||
|
|
|
@ -114,8 +114,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
|
|||
FetchStyle.JOIN,
|
||||
this,
|
||||
identifiedEntityMapping,
|
||||
propertyAccess,
|
||||
null
|
||||
propertyAccess
|
||||
);
|
||||
|
||||
final CompositeType idClassType = (CompositeType) idClassSource.getType();
|
||||
|
|
|
@ -287,8 +287,7 @@ public class MappingModelCreationHelper {
|
|||
updateable,
|
||||
attrType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
bootProperty.getValueGenerationStrategy()
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -333,8 +332,7 @@ public class MappingModelCreationHelper {
|
|||
FetchStyle.JOIN,
|
||||
attributeMappingType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
bootProperty.getValueGenerationStrategy()
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -349,8 +347,7 @@ public class MappingModelCreationHelper {
|
|||
FetchStyle.JOIN,
|
||||
attributeMappingType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
bootProperty.getValueGenerationStrategy()
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.ValueGeneration;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NoValueGeneration implements ValueGeneration {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NoValueGeneration INSTANCE = new NoValueGeneration();
|
||||
|
||||
@Override
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
return GenerationTiming.NEVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueGenerator<?> getValueGenerator() {
|
||||
return (session, owner) -> null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnInSql() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -68,7 +68,7 @@ import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResul
|
|||
import org.hibernate.sql.results.graph.collection.internal.DelayedCollectionFetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
||||
import org.hibernate.tuple.ValueGeneration;
|
||||
import org.hibernate.tuple.Generator;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -325,9 +325,9 @@ public class PluralAttributeMappingImpl
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValueGeneration getValueGeneration() {
|
||||
public Generator getGenerator() {
|
||||
// can never be a generated value
|
||||
return NoValueGeneration.INSTANCE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -80,7 +80,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
keyDeclaringType,
|
||||
keyModelPart,
|
||||
keyPropertyAccess,
|
||||
NoValueGeneration.INSTANCE,
|
||||
insertable,
|
||||
updateable,
|
||||
keySelectableMapping
|
||||
|
@ -146,7 +145,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
keyDeclaringType,
|
||||
targetModelPart,
|
||||
valueAccess,
|
||||
NoValueGeneration.INSTANCE,
|
||||
keySelectableMapping.isInsertable(),
|
||||
keySelectableMapping.isUpdateable(),
|
||||
keySelectableMapping
|
||||
|
|
|
@ -201,9 +201,7 @@ public class ToOneAttributeMapping
|
|||
adjustFetchTiming( mappedFetchTiming, bootValue ),
|
||||
mappedFetchStyle,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
// can never be a generated value
|
||||
NoValueGeneration.INSTANCE
|
||||
propertyAccess
|
||||
);
|
||||
this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromAttributeName( name );
|
||||
this.isNullable = bootValue.isNullable();
|
||||
|
@ -551,8 +549,7 @@ public class ToOneAttributeMapping
|
|||
original.getAttributeMetadataAccess(),
|
||||
original,
|
||||
declaringType,
|
||||
original.getPropertyAccess(),
|
||||
original.getValueGeneration()
|
||||
original.getPropertyAccess()
|
||||
);
|
||||
this.navigableRole = original.navigableRole;
|
||||
this.sqlAliasStem = original.sqlAliasStem;
|
||||
|
@ -1404,7 +1401,7 @@ public class ToOneAttributeMapping
|
|||
return bidirectionalAttributeName != null && (
|
||||
!( entityMappingType.getIdentifierMapping() instanceof SingleAttributeIdentifierMapping )
|
||||
|| !targetKeyPropertyNames.contains(
|
||||
( (SingleAttributeIdentifierMapping) entityMappingType.getIdentifierMapping() ).getAttributeName()
|
||||
entityMappingType.getIdentifierMapping().getAttributeName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.hibernate.metamodel.mapping.VirtualModelPart;
|
|||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.tuple.Generator;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
|
@ -35,8 +34,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
|
|||
FetchStyle mappedFetchStyle,
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super(
|
||||
name,
|
||||
navigableRole,
|
||||
|
@ -48,8 +46,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
|
|||
mappedFetchStyle,
|
||||
embeddableMappingType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -64,8 +61,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
|
|||
FetchStyle mappedFetchStyle,
|
||||
EmbeddableMappingType embeddableMappingType,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess,
|
||||
Generator valueGeneration) {
|
||||
PropertyAccess propertyAccess) {
|
||||
super(
|
||||
name,
|
||||
navigableRole,
|
||||
|
@ -77,8 +73,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
|
|||
mappedFetchStyle,
|
||||
embeddableMappingType,
|
||||
declaringType,
|
||||
propertyAccess,
|
||||
valueGeneration
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2766,16 +2766,17 @@ public abstract class AbstractEntityPersister
|
|||
hasColumns = true;
|
||||
}
|
||||
else {
|
||||
final Generator valueGeneration = attributeMapping.getValueGeneration();
|
||||
if ( valueGeneration.getGenerationTiming().includesUpdate()
|
||||
&& valueGeneration.generatedByDatabase() ) {
|
||||
final InDatabaseGenerator generation = (InDatabaseGenerator) valueGeneration;
|
||||
if ( generation.referenceColumnsInSql() ) {
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( generator!=null
|
||||
&& generator.getGenerationTiming().includesUpdate()
|
||||
&& generator.generatedByDatabase() ) {
|
||||
final InDatabaseGenerator databaseGenerator = (InDatabaseGenerator) generator;
|
||||
if ( databaseGenerator.referenceColumnsInSql() ) {
|
||||
final Dialect dialect = getFactory().getJdbcServices().getDialect();
|
||||
update.addColumns(
|
||||
getPropertyColumnNames(index),
|
||||
SINGLE_TRUE,
|
||||
generation.getReferencedColumnValues(dialect)
|
||||
databaseGenerator.getReferencedColumnValues(dialect)
|
||||
);
|
||||
hasColumns = true;
|
||||
}
|
||||
|
|
|
@ -92,10 +92,10 @@ public abstract class AbstractMutationCoordinator {
|
|||
void handleValueGeneration(
|
||||
AttributeMapping attributeMapping,
|
||||
MutationGroupBuilder mutationGroupBuilder,
|
||||
InDatabaseGenerator valueGeneration) {
|
||||
InDatabaseGenerator generator) {
|
||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||
final boolean writePropertyValue = valueGeneration.writePropertyValue();
|
||||
final String[] columnValues = writePropertyValue ? null : valueGeneration.getReferencedColumnValues( dialect );
|
||||
final boolean writePropertyValue = generator.writePropertyValue();
|
||||
final String[] columnValues = writePropertyValue ? null : generator.getReferencedColumnValues( dialect );
|
||||
attributeMapping.forEachSelectable( (j, mapping) -> {
|
||||
final String tableName = entityPersister.physicalTableNameForMutation( mapping );
|
||||
final ColumnValuesTableMutationBuilder tableUpdateBuilder = mutationGroupBuilder.findTableDetailsBuilder( tableName );
|
||||
|
|
|
@ -100,10 +100,13 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
protected void preInsertInMemoryValueGeneration(Object[] values, Object entity, SharedSessionContractImplementor session) {
|
||||
final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel();
|
||||
if ( entityMetamodel.hasPreInsertGeneratedValues() ) {
|
||||
final InMemoryGenerator[] strategies = entityMetamodel.getInMemoryValueGenerationStrategies();
|
||||
for ( int i = 0; i < strategies.length; i++ ) {
|
||||
if ( strategies[i] != null && strategies[i].getGenerationTiming().includesInsert() ) {
|
||||
values[i] = strategies[i].generate( session, entity, values[i] );
|
||||
final Generator[] generators = entityMetamodel.getGenerators();
|
||||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedByDatabase()
|
||||
&& generator.getGenerationTiming().includesInsert() ) {
|
||||
values[i] = ( (InMemoryGenerator) generator).generate( session, entity, values[i] );
|
||||
entityPersister().setPropertyValue( entity, i, values[i] );
|
||||
}
|
||||
}
|
||||
|
@ -389,13 +392,9 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
|
||||
|
||||
if ( !attributeInclusions[ attributeIndex ] ) {
|
||||
final Generator valueGeneration = attributeMapping.getValueGeneration();
|
||||
if ( isValueGenerationInSql( valueGeneration ) ) {
|
||||
handleValueGeneration(
|
||||
attributeMapping,
|
||||
insertGroupBuilder,
|
||||
(InDatabaseGenerator) valueGeneration
|
||||
);
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerationInSql( generator ) ) {
|
||||
handleValueGeneration( attributeMapping, insertGroupBuilder, (InDatabaseGenerator) generator );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -436,9 +435,10 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
} );
|
||||
}
|
||||
|
||||
private static boolean isValueGenerationInSql(Generator valueGeneration) {
|
||||
return valueGeneration.getGenerationTiming().includesInsert()
|
||||
&& valueGeneration.generatedByDatabase()
|
||||
&& ( (InDatabaseGenerator) valueGeneration ).referenceColumnsInSql();
|
||||
private static boolean isValueGenerationInSql(Generator generator) {
|
||||
return generator != null
|
||||
&& generator.getGenerationTiming().includesInsert()
|
||||
&& generator.generatedByDatabase()
|
||||
&& ( (InDatabaseGenerator) generator ).referenceColumnsInSql();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,13 +223,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
}
|
||||
}
|
||||
|
||||
final InclusionChecker updateabilityChecker = (position, attribute) -> {
|
||||
if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return attributeUpdateability[ position ];
|
||||
};
|
||||
final InclusionChecker updateabilityChecker =
|
||||
(position, attribute) -> isValueGenerationInSql( attribute.getGenerator() ) || attributeUpdateability[ position ];
|
||||
|
||||
final InclusionChecker dirtinessChecker = (position, attribute) -> {
|
||||
if ( !attributeUpdateability[ position ] ) {
|
||||
|
@ -320,10 +315,19 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isValueGenerationInSql(Generator valueGeneration) {
|
||||
return valueGeneration.getGenerationTiming().includesUpdate()
|
||||
&& valueGeneration.generatedByDatabase()
|
||||
&& ( (InDatabaseGenerator) valueGeneration ).referenceColumnsInSql();
|
||||
private boolean isValueGenerationInSql(Generator generator) {
|
||||
return generator != null
|
||||
&& generator.getGenerationTiming().includesUpdate()
|
||||
&& generator.generatedByDatabase()
|
||||
&& ((InDatabaseGenerator) generator).referenceColumnsInSql();
|
||||
}
|
||||
|
||||
private boolean isValueGenerationInSqlNoWrite(Generator generator) {
|
||||
return generator != null
|
||||
&& generator.getGenerationTiming().includesUpdate()
|
||||
&& generator.generatedByDatabase()
|
||||
&& ((InDatabaseGenerator) generator).referenceColumnsInSql()
|
||||
&& !((InDatabaseGenerator) generator).writePropertyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,18 +419,20 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
Object[] newValues,
|
||||
SharedSessionContractImplementor session) {
|
||||
final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel();
|
||||
if ( ! entityMetamodel.hasPreUpdateGeneratedValues() ) {
|
||||
if ( !entityMetamodel.hasPreUpdateGeneratedValues() ) {
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
|
||||
final InMemoryGenerator[] valueGenerationStrategies = entityMetamodel.getInMemoryValueGenerationStrategies();
|
||||
if ( valueGenerationStrategies.length != 0 ) {
|
||||
final int[] fieldsPreUpdateNeeded = new int[valueGenerationStrategies.length];
|
||||
final Generator[] generators = entityMetamodel.getGenerators();
|
||||
if ( generators.length != 0 ) {
|
||||
final int[] fieldsPreUpdateNeeded = new int[generators.length];
|
||||
int count = 0;
|
||||
for ( int i = 0; i < valueGenerationStrategies.length; i++ ) {
|
||||
if ( valueGenerationStrategies[i] != null
|
||||
&& valueGenerationStrategies[i].getGenerationTiming().includesUpdate() ) {
|
||||
newValues[i] = valueGenerationStrategies[i].generate( session, object, newValues[i] );
|
||||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedByDatabase()
|
||||
&& generator.getGenerationTiming().includesUpdate() ) {
|
||||
newValues[i] = ( (InMemoryGenerator) generator ).generate( session, object, newValues[i] );
|
||||
entityPersister().setPropertyValue( object, i, newValues[i] );
|
||||
fieldsPreUpdateNeeded[count++] = i;
|
||||
}
|
||||
|
@ -673,9 +679,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
// apply the new values
|
||||
final boolean includeInSet;
|
||||
|
||||
final Generator valueGeneration = attributeMapping.getValueGeneration();
|
||||
if ( isValueGenerationInSql( valueGeneration )
|
||||
&& !( (InDatabaseGenerator) valueGeneration ).writePropertyValue() ) {
|
||||
if ( isValueGenerationInSqlNoWrite( attributeMapping.getGenerator() ) ) {
|
||||
// we applied `#getDatabaseGeneratedReferencedColumnValue` earlier
|
||||
includeInSet = false;
|
||||
}
|
||||
|
@ -908,13 +912,9 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
if ( attributeAnalysis.includeInSet() ) {
|
||||
assert updateValuesAnalysis.tablesNeedingUpdate.contains( tableMapping );
|
||||
|
||||
final Generator valueGeneration = attributeMapping.getValueGeneration();
|
||||
if ( isValueGenerationInSql( valueGeneration ) ) {
|
||||
handleValueGeneration(
|
||||
attributeMapping,
|
||||
updateGroupBuilder,
|
||||
(InDatabaseGenerator) valueGeneration
|
||||
);
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerationInSql( generator ) ) {
|
||||
handleValueGeneration( attributeMapping, updateGroupBuilder, (InDatabaseGenerator) generator );
|
||||
}
|
||||
else if ( versionMapping != null
|
||||
&& versionMapping.getVersionAttribute() == attributeMapping ) {
|
||||
|
@ -1343,13 +1343,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
(index,attribute) -> {
|
||||
if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return entityPersister().getPropertyUpdateability()[index];
|
||||
},
|
||||
(index,attribute) -> isValueGenerationInSql( attribute.getGenerator() )
|
||||
|| entityPersister().getPropertyUpdateability()[index],
|
||||
(index,attribute) -> {
|
||||
final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle();
|
||||
if ( optimisticLockStyle.isAll() ) {
|
||||
|
|
|
@ -68,11 +68,6 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
|
|||
return attributeInformation.isUpdateable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Generator getValueGenerationStrategy() {
|
||||
return attributeInformation.getValueGenerationStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
return attributeInformation.isNullable();
|
||||
|
|
|
@ -7,12 +7,16 @@
|
|||
package org.hibernate.tuple;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link Generator} based on a custom Java generator annotation type.
|
||||
* Every instance must implement either {@link InMemoryGenerator} or
|
||||
* {@link InDatabaseGenerator}.
|
||||
* {@link InDatabaseGenerator}. Implementing this interface is just a
|
||||
* slightly more typesafe alternative to providing a constructor with
|
||||
* the same signature as the method
|
||||
* {@link #initialize(Annotation, Member, GeneratorCreationContext)}.
|
||||
*
|
||||
* @param <A> The generator annotation type supported by an implementation
|
||||
*
|
||||
|
@ -29,12 +33,10 @@ public interface AnnotationGenerator<A extends Annotation> extends Generator {
|
|||
*
|
||||
* @param annotation an instance of the strategy's annotation type. Typically, implementations will retrieve the
|
||||
* annotation's attribute values and store them in fields.
|
||||
* @param propertyType the type of the property annotated with the generator annotation. Implementations may use
|
||||
* the type to determine the right {@link ValueGenerator} to be applied.
|
||||
* @param entityName the name of the entity to which the annotated property belongs
|
||||
* @param propertyName the name of the annotated property
|
||||
* @param member the Java member annotated with the generator annotation.
|
||||
* @param context a {@link GeneratorCreationContext}
|
||||
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if
|
||||
* an implementation can't create a value for the given property type.
|
||||
*/
|
||||
void initialize(A annotation, Class<?> propertyType, String entityName, String propertyName);
|
||||
void initialize(A annotation, Member member, GeneratorCreationContext context);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.tuple;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,20 +37,19 @@ public interface AnnotationValueGeneration<A extends Annotation>
|
|||
*/
|
||||
void initialize(A annotation, Class<?> propertyType);
|
||||
|
||||
/**
|
||||
* Initializes this generation strategy for the given annotation instance.
|
||||
*
|
||||
* @param annotation an instance of the strategy's annotation type. Typically, implementations will retrieve the
|
||||
* annotation's attribute values and store them in fields.
|
||||
* @param propertyType the type of the property annotated with the generator annotation. Implementations may use
|
||||
* the type to determine the right {@link ValueGenerator} to be applied.
|
||||
* @param entityName the name of the entity to which the annotated property belongs
|
||||
* @param propertyName the name of the annotated property
|
||||
*
|
||||
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if
|
||||
* an implementation can't create a value for the given property type.
|
||||
*/
|
||||
default void initialize(A annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
initialize( annotation, propertyType );
|
||||
default void initialize(A annotation, Member member, GeneratorCreationContext context) {
|
||||
initialize( annotation, getPropertyType( member ) );
|
||||
}
|
||||
|
||||
private static Class<?> getPropertyType(Member member) {
|
||||
if (member instanceof Field) {
|
||||
return ((Field) member).getType();
|
||||
}
|
||||
else if (member instanceof Method) {
|
||||
return ((Method) member).getReturnType();
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure("member should have been a method or field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,16 @@ public class BaselineAttributeInformation {
|
|||
private final boolean lazy;
|
||||
private final boolean insertable;
|
||||
private final boolean updateable;
|
||||
private final Generator generator;
|
||||
private final boolean nullable;
|
||||
private final boolean dirtyCheckable;
|
||||
private final boolean versionable;
|
||||
private final CascadeStyle cascadeStyle;
|
||||
private final FetchMode fetchMode;
|
||||
private boolean checkable;
|
||||
|
||||
public BaselineAttributeInformation(
|
||||
boolean lazy,
|
||||
boolean insertable,
|
||||
boolean updateable,
|
||||
Generator generator,
|
||||
boolean nullable,
|
||||
boolean dirtyCheckable,
|
||||
boolean versionable,
|
||||
|
@ -37,7 +34,6 @@ public class BaselineAttributeInformation {
|
|||
this.lazy = lazy;
|
||||
this.insertable = insertable;
|
||||
this.updateable = updateable;
|
||||
this.generator = generator;
|
||||
this.nullable = nullable;
|
||||
this.dirtyCheckable = dirtyCheckable;
|
||||
this.versionable = versionable;
|
||||
|
@ -57,10 +53,6 @@ public class BaselineAttributeInformation {
|
|||
return updateable;
|
||||
}
|
||||
|
||||
public Generator getValueGenerationStrategy() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
@ -81,15 +73,10 @@ public class BaselineAttributeInformation {
|
|||
return fetchMode;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return checkable;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private boolean lazy;
|
||||
private boolean insertable;
|
||||
private boolean updateable;
|
||||
private Generator generator;
|
||||
private boolean nullable;
|
||||
private boolean dirtyCheckable;
|
||||
private boolean versionable;
|
||||
|
@ -111,11 +98,6 @@ public class BaselineAttributeInformation {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setValueGenerationStrategy(Generator generator) {
|
||||
this.generator = generator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
|
@ -146,7 +128,6 @@ public class BaselineAttributeInformation {
|
|||
lazy,
|
||||
insertable,
|
||||
updateable,
|
||||
generator,
|
||||
nullable,
|
||||
dirtyCheckable,
|
||||
versionable,
|
||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.tuple;
|
|||
import org.hibernate.annotations.Generated;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
|
@ -17,8 +19,7 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
|
|||
* @author Steve Ebersole
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public class GeneratedValueGeneration
|
||||
implements AnnotationGenerator<Generated>, InDatabaseGenerator {
|
||||
public class GeneratedValueGeneration implements InDatabaseGenerator {
|
||||
|
||||
private GenerationTiming timing;
|
||||
private boolean writable;
|
||||
|
@ -31,8 +32,7 @@ public class GeneratedValueGeneration
|
|||
this.timing = timing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Generated annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
public GeneratedValueGeneration(Generated annotation) {
|
||||
timing = annotation.value().getEquivalent();
|
||||
sql = isEmpty( annotation.sql() ) ? null : new String[] { annotation.sql() };
|
||||
writable = annotation.writable() || sql != null;
|
||||
|
|
|
@ -88,7 +88,7 @@ public enum GenerationTiming {
|
|||
|
||||
@Override
|
||||
public boolean includes(GenerationTiming timing) {
|
||||
return timing != NEVER;
|
||||
return timing.isNotNever();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -101,6 +101,10 @@ public enum GenerationTiming {
|
|||
*/
|
||||
public abstract boolean includesUpdate();
|
||||
|
||||
public boolean isNotNever() {
|
||||
return this != NEVER;
|
||||
}
|
||||
|
||||
public abstract boolean includes(GenerationTiming timing);
|
||||
|
||||
public static GenerationTiming parseFromName(String name) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.tuple;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
@Incubating
|
||||
public interface GeneratorCreationContext {
|
||||
Database getDatabase();
|
||||
ServiceRegistry getServiceRegistry();
|
||||
|
||||
String getDefaultCatalog();
|
||||
String getDefaultSchema();
|
||||
|
||||
PersistentClass getPersistentClass();
|
||||
|
||||
Property getProperty();
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.tuple;
|
||||
|
||||
import org.hibernate.engine.spi.IdentifierValue;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.type.Type;
|
||||
|
|
|
@ -19,8 +19,6 @@ public interface NonIdentifierAttribute extends Attribute {
|
|||
|
||||
boolean isUpdateable();
|
||||
|
||||
Generator getValueGenerationStrategy();
|
||||
|
||||
boolean isNullable();
|
||||
|
||||
/**
|
||||
|
|
|
@ -95,7 +95,6 @@ public final class PropertyFactory {
|
|||
.setLazy( lazy )
|
||||
.setInsertable( property.isInsertable() )
|
||||
.setUpdateable( property.isUpdateable() )
|
||||
.setValueGenerationStrategy( property.getValueGenerationStrategy() )
|
||||
.setNullable( property.isOptional() )
|
||||
.setDirtyCheckable( property.isUpdateable() && !lazy )
|
||||
.setVersionable( property.isOptimisticLocked() )
|
||||
|
@ -166,7 +165,6 @@ public final class PropertyFactory {
|
|||
.setLazy( lazy )
|
||||
.setInsertable( property.isInsertable() )
|
||||
.setUpdateable( property.isUpdateable() )
|
||||
.setValueGenerationStrategy( property.getValueGenerationStrategy() )
|
||||
.setNullable( property.isOptional() )
|
||||
.setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
|
||||
.setVersionable( property.isOptimisticLocked() )
|
||||
|
@ -186,7 +184,6 @@ public final class PropertyFactory {
|
|||
.setLazy( lazy )
|
||||
.setInsertable( property.isInsertable() )
|
||||
.setUpdateable( property.isUpdateable() )
|
||||
.setValueGenerationStrategy( property.getValueGenerationStrategy() )
|
||||
.setNullable( property.isOptional() )
|
||||
.setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
|
||||
.setVersionable( property.isOptimisticLocked() )
|
||||
|
@ -208,7 +205,6 @@ public final class PropertyFactory {
|
|||
.setLazy( lazy )
|
||||
.setInsertable( property.isInsertable() )
|
||||
.setUpdateable( property.isUpdateable() )
|
||||
.setValueGenerationStrategy( property.getValueGenerationStrategy() )
|
||||
.setNullable( property.isOptional() )
|
||||
.setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
|
||||
.setVersionable( property.isOptimisticLocked() )
|
||||
|
@ -269,7 +265,6 @@ public final class PropertyFactory {
|
|||
false,
|
||||
property.isInsertable(),
|
||||
property.isUpdateable(),
|
||||
property.getValueGenerationStrategy(),
|
||||
property.isOptional(),
|
||||
alwaysDirtyCheck || property.isUpdateable(),
|
||||
property.isOptimisticLocked(),
|
||||
|
|
|
@ -29,10 +29,7 @@ public class StandardProperty extends AbstractNonIdentifierAttribute implements
|
|||
* @param lazy Should this property be handled lazily?
|
||||
* @param insertable Is this property an insertable value?
|
||||
* @param updateable Is this property an updateable value?
|
||||
* @param generator How (if) values for this attribute are generated
|
||||
* @param nullable Is this property a nullable value?
|
||||
* @param checkable Is this property a checkable value?
|
||||
* @param versionable Is this property a versionable value?
|
||||
* @param cascadeStyle The cascade style for this property's value.
|
||||
* @param fetchMode Any fetch mode defined for this property
|
||||
*/
|
||||
|
@ -42,7 +39,6 @@ public class StandardProperty extends AbstractNonIdentifierAttribute implements
|
|||
boolean lazy,
|
||||
boolean insertable,
|
||||
boolean updateable,
|
||||
Generator generator,
|
||||
boolean nullable,
|
||||
boolean checkable,
|
||||
boolean versionable,
|
||||
|
@ -58,7 +54,6 @@ public class StandardProperty extends AbstractNonIdentifierAttribute implements
|
|||
.setLazy( lazy )
|
||||
.setInsertable( insertable )
|
||||
.setUpdateable( updateable )
|
||||
.setValueGenerationStrategy(generator)
|
||||
.setNullable( nullable )
|
||||
.setDirtyCheckable( checkable )
|
||||
.setVersionable( versionable )
|
||||
|
|
|
@ -14,23 +14,25 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.getPropertyType;
|
||||
|
||||
/**
|
||||
* Value generation implementation for {@link TenantId}.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class TenantIdGeneration
|
||||
implements AnnotationGenerator<TenantId>, InMemoryGenerator {
|
||||
public class TenantIdGeneration implements InMemoryGenerator {
|
||||
|
||||
private String entityName;
|
||||
private String propertyName;
|
||||
private Class<?> propertyType;
|
||||
private final String entityName;
|
||||
private final String propertyName;
|
||||
private final Class<?> propertyType;
|
||||
|
||||
@Override
|
||||
public void initialize(TenantId annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
this.entityName = entityName;
|
||||
this.propertyName = propertyName;
|
||||
this.propertyType = propertyType;
|
||||
public TenantIdGeneration(TenantId annotation, Member member, GeneratorCreationContext context) {
|
||||
entityName = context.getPersistentClass().getEntityName();
|
||||
propertyName = context.getProperty().getName();
|
||||
propertyType = getPropertyType( member );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,7 +12,8 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.GeneratorType;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor;
|
||||
|
||||
/**
|
||||
* An {@link AnnotationValueGeneration} which delegates to a {@link ValueGenerator}.
|
||||
|
@ -20,14 +21,13 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
* @author Gunnar Morling
|
||||
*/
|
||||
public class VmValueGeneration
|
||||
implements AnnotationGenerator<GeneratorType>, InMemoryGenerator {
|
||||
implements InMemoryGenerator {
|
||||
|
||||
private GenerationTiming generationTiming;
|
||||
ValueGenerator<?> generator;
|
||||
private final GenerationTiming generationTiming;
|
||||
private final ValueGenerator<?> generator;
|
||||
|
||||
@Override
|
||||
public void initialize(GeneratorType annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
Constructor<? extends ValueGenerator<?>> constructor = ReflectHelper.getDefaultConstructor(annotation.type());
|
||||
public VmValueGeneration(GeneratorType annotation) {
|
||||
Constructor<? extends ValueGenerator<?>> constructor = getDefaultConstructor( annotation.type() );
|
||||
try {
|
||||
generator = constructor.newInstance();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Set;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
|
||||
|
@ -29,19 +30,21 @@ import org.hibernate.engine.spi.CascadeStyle;
|
|||
import org.hibernate.engine.spi.CascadeStyles;
|
||||
import org.hibernate.engine.spi.CascadingActions;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.GeneratorCreator;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.tuple.GeneratorCreationContext;
|
||||
import org.hibernate.tuple.InDatabaseGenerator;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.IdentifierProperty;
|
||||
|
@ -100,8 +103,7 @@ public class EntityMetamodel implements Serializable {
|
|||
private final boolean hasInsertGeneratedValues;
|
||||
private final boolean hasUpdateGeneratedValues;
|
||||
|
||||
private final InMemoryGenerator[] inMemoryValueGenerationStrategies;
|
||||
private final InDatabaseGenerator[] inDatabaseValueGenerationStrategies;
|
||||
private final Generator[] generators;
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private final Map<String, Integer> propertyIndexes = new HashMap<>();
|
||||
|
@ -211,8 +213,7 @@ public class EntityMetamodel implements Serializable {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// generated value strategies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
this.inMemoryValueGenerationStrategies = new InMemoryGenerator[propertySpan];
|
||||
this.inDatabaseValueGenerationStrategies = new InDatabaseGenerator[propertySpan];
|
||||
this.generators = new Generator[propertySpan];
|
||||
|
||||
boolean foundPreInsertGeneratedValues = false;
|
||||
boolean foundPreUpdateGeneratedValues = false;
|
||||
|
@ -300,42 +301,44 @@ public class EntityMetamodel implements Serializable {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// generated value strategies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
GenerationStrategyPair pair = buildGenerationStrategyPair( sessionFactory, prop );
|
||||
inMemoryValueGenerationStrategies[i] = pair.getInMemoryStrategy();
|
||||
inDatabaseValueGenerationStrategies[i] = pair.getInDatabaseStrategy();
|
||||
|
||||
if ( pair.getInMemoryStrategy() != null
|
||||
&& !pair.getInMemoryStrategy().generatedByDatabase() ) {
|
||||
final GenerationTiming timing = pair.getInMemoryStrategy().getGenerationTiming();
|
||||
final Generator generator = buildGenerator( persistentClass, prop, creationContext );
|
||||
generators[i] = generator;
|
||||
if ( generator != null ) {
|
||||
if ( generatedWithNoParameter( generator ) ) {
|
||||
propertyInsertability[i] = false;
|
||||
propertyUpdateability[i] = false;
|
||||
}
|
||||
// we have some level of generation indicated
|
||||
switch ( timing ) {
|
||||
switch ( generator.getGenerationTiming() ) {
|
||||
case INSERT:
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostInsertGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreInsertGeneratedValues = true;
|
||||
}
|
||||
break;
|
||||
case UPDATE:
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreUpdateGeneratedValues = true;
|
||||
}
|
||||
break;
|
||||
case ALWAYS:
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostInsertGeneratedValues = true;
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreInsertGeneratedValues = true;
|
||||
foundPreUpdateGeneratedValues = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( pair.getInDatabaseStrategy() != null
|
||||
&& pair.getInDatabaseStrategy().generatedByDatabase() ) {
|
||||
switch ( pair.getInDatabaseStrategy().getGenerationTiming() ) {
|
||||
case INSERT:
|
||||
foundPostInsertGeneratedValues = true;
|
||||
break;
|
||||
case UPDATE:
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
break;
|
||||
case ALWAYS:
|
||||
foundPostInsertGeneratedValues = true;
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if ( attribute.isLazy() ) {
|
||||
|
@ -452,89 +455,79 @@ public class EntityMetamodel implements Serializable {
|
|||
entityNameByInheritanceClassMap = CollectionHelper.toSmallMap( entityNameByInheritanceClassMapLocal );
|
||||
}
|
||||
|
||||
private static GenerationStrategyPair buildGenerationStrategyPair(
|
||||
final SessionFactoryImplementor sessionFactory,
|
||||
final Property mappingProperty) {
|
||||
final Generator valueGeneration = mappingProperty.getValueGenerationStrategy();
|
||||
if ( valueGeneration != null && valueGeneration.getGenerationTiming() != GenerationTiming.NEVER ) {
|
||||
// the property is generated in full. build the generation strategy pair.
|
||||
if ( !valueGeneration.generatedByDatabase() ) {
|
||||
// in-memory generation
|
||||
return new GenerationStrategyPair( (InMemoryGenerator) valueGeneration );
|
||||
}
|
||||
else {
|
||||
// in-db generation
|
||||
return new GenerationStrategyPair( (InDatabaseGenerator) valueGeneration );
|
||||
}
|
||||
}
|
||||
else if ( mappingProperty.getValue() instanceof Component ) {
|
||||
final CompositeGenerationStrategyPairBuilder builder = new CompositeGenerationStrategyPairBuilder(
|
||||
mappingProperty,
|
||||
sessionFactory.getJdbcServices().getDialect()
|
||||
);
|
||||
interpretPartialCompositeValueGeneration( sessionFactory, (Component) mappingProperty.getValue(), builder );
|
||||
return builder.buildPair();
|
||||
private static boolean generatedWithNoParameter(Generator generator) {
|
||||
return generator.generatedByDatabase()
|
||||
&& !((InDatabaseGenerator) generator).writePropertyValue();
|
||||
}
|
||||
|
||||
return NO_GEN_PAIR;
|
||||
}
|
||||
|
||||
private static final GenerationStrategyPair NO_GEN_PAIR = new GenerationStrategyPair();
|
||||
|
||||
private static void interpretPartialCompositeValueGeneration(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
Component composite,
|
||||
CompositeGenerationStrategyPairBuilder builder) {
|
||||
for ( Property property : composite.getProperties() ) {
|
||||
builder.addPair( buildGenerationStrategyPair( sessionFactory, property ) );
|
||||
private static Generator buildGenerator(
|
||||
final PersistentClass persistentClass,
|
||||
final Property mappingProperty,
|
||||
final RuntimeModelCreationContext context) {
|
||||
final GeneratorCreator generatorCreator = mappingProperty.getValueGenerationStrategy();
|
||||
if ( generatorCreator != null ) {
|
||||
final Generator generator = createGenerator( persistentClass, mappingProperty, context, generatorCreator );
|
||||
if ( generator.getGenerationTiming().isNotNever() ) {
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenerationStrategyPair {
|
||||
private final InMemoryGenerator inMemoryStrategy;
|
||||
private final InDatabaseGenerator inDatabaseStrategy;
|
||||
|
||||
public GenerationStrategyPair() {
|
||||
this( NoInMemoryGenerator.INSTANCE, NoInDatabaseGenerator.INSTANCE );
|
||||
if ( mappingProperty.getValue() instanceof Component ) {
|
||||
Dialect dialect = context.getSessionFactory().getJdbcServices().getDialect();
|
||||
final CompositeGeneratorBuilder builder = new CompositeGeneratorBuilder( mappingProperty, dialect );
|
||||
final Component component = (Component) mappingProperty.getValue();
|
||||
for ( Property property : component.getProperties() ) {
|
||||
builder.addPair( createGenerator( null, property, context, property.getValueGenerationStrategy() ) );
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GenerationStrategyPair(InMemoryGenerator inMemoryStrategy) {
|
||||
this( inMemoryStrategy, NoInDatabaseGenerator.INSTANCE );
|
||||
private static Generator createGenerator(
|
||||
PersistentClass persistentClass,
|
||||
Property mappingProperty,
|
||||
RuntimeModelCreationContext context,
|
||||
GeneratorCreator generatorCreator) {
|
||||
if ( generatorCreator == null ) {
|
||||
return null;
|
||||
}
|
||||
return generatorCreator.createGenerator(
|
||||
new GeneratorCreationContext() {
|
||||
@Override
|
||||
public Database getDatabase() {
|
||||
return context.getMetadata().getDatabase();
|
||||
}
|
||||
|
||||
public GenerationStrategyPair(InDatabaseGenerator inDatabaseStrategy) {
|
||||
this( NoInMemoryGenerator.INSTANCE, inDatabaseStrategy );
|
||||
@Override
|
||||
public ServiceRegistry getServiceRegistry() {
|
||||
return context.getBootstrapContext().getServiceRegistry();
|
||||
}
|
||||
|
||||
public GenerationStrategyPair(
|
||||
InMemoryGenerator inMemoryStrategy,
|
||||
InDatabaseGenerator inDatabaseStrategy) {
|
||||
// perform some normalization. Also check that only one (if any) strategy is specified
|
||||
if ( inMemoryStrategy == null ) {
|
||||
inMemoryStrategy = NoInMemoryGenerator.INSTANCE;
|
||||
}
|
||||
if ( inDatabaseStrategy == null ) {
|
||||
inDatabaseStrategy = NoInDatabaseGenerator.INSTANCE;
|
||||
@Override
|
||||
public String getDefaultCatalog() {
|
||||
return context.getSessionFactory().getSessionFactoryOptions().getDefaultCatalog();
|
||||
}
|
||||
|
||||
if ( inMemoryStrategy.getGenerationTiming() != GenerationTiming.NEVER
|
||||
&& inDatabaseStrategy.getGenerationTiming() != GenerationTiming.NEVER ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"in-memory and in-database value generation are mutually exclusive"
|
||||
@Override
|
||||
public String getDefaultSchema() {
|
||||
return context.getSessionFactory().getSessionFactoryOptions().getDefaultSchema();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentClass getPersistentClass() {
|
||||
return persistentClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty() {
|
||||
return mappingProperty;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.inMemoryStrategy = inMemoryStrategy;
|
||||
this.inDatabaseStrategy = inDatabaseStrategy;
|
||||
}
|
||||
|
||||
public InMemoryGenerator getInMemoryStrategy() {
|
||||
return inMemoryStrategy;
|
||||
}
|
||||
|
||||
public InDatabaseGenerator getInDatabaseStrategy() {
|
||||
return inDatabaseStrategy;
|
||||
}
|
||||
public Generator[] getGenerators() {
|
||||
return generators;
|
||||
}
|
||||
|
||||
public static class ValueGenerationStrategyException extends HibernateException {
|
||||
|
@ -543,7 +536,7 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private static class CompositeGenerationStrategyPairBuilder {
|
||||
private static class CompositeGeneratorBuilder {
|
||||
private final Property mappingProperty;
|
||||
private final Dialect dialect;
|
||||
|
||||
|
@ -552,18 +545,28 @@ public class EntityMetamodel implements Serializable {
|
|||
|
||||
private List<InDatabaseGenerator> inDatabaseStrategies;
|
||||
|
||||
public CompositeGenerationStrategyPairBuilder(Property mappingProperty, Dialect dialect) {
|
||||
public CompositeGeneratorBuilder(Property mappingProperty, Dialect dialect) {
|
||||
this.mappingProperty = mappingProperty;
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
public void addPair(GenerationStrategyPair generationStrategyPair) {
|
||||
add( generationStrategyPair.getInMemoryStrategy() );
|
||||
add( generationStrategyPair.getInDatabaseStrategy() );
|
||||
public void addPair(Generator generator) {
|
||||
if ( generator != null ) {
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
if ( generator instanceof InDatabaseGenerator ) {
|
||||
add( (InDatabaseGenerator) generator );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( generator instanceof InMemoryGenerator ) {
|
||||
add( (InMemoryGenerator) generator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(InMemoryGenerator inMemoryStrategy) {
|
||||
if ( inMemoryStrategy.getGenerationTiming() != GenerationTiming.NEVER ) {
|
||||
if ( inMemoryStrategy.getGenerationTiming().isNotNever() ) {
|
||||
hadInMemoryGeneration = true;
|
||||
}
|
||||
}
|
||||
|
@ -574,12 +577,12 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
inDatabaseStrategies.add( inDatabaseStrategy );
|
||||
|
||||
if ( inDatabaseStrategy.getGenerationTiming() != GenerationTiming.NEVER ) {
|
||||
if ( inDatabaseStrategy.getGenerationTiming().isNotNever() ) {
|
||||
hadInDatabaseGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
public GenerationStrategyPair buildPair() {
|
||||
public Generator build() {
|
||||
if ( hadInMemoryGeneration && hadInDatabaseGeneration ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"Composite attribute [" + mappingProperty.getName() + "] contained both in-memory"
|
||||
|
@ -593,7 +596,7 @@ public class EntityMetamodel implements Serializable {
|
|||
else if ( hadInDatabaseGeneration ) {
|
||||
final Component composite = (Component) mappingProperty.getValue();
|
||||
|
||||
// we need the numbers to match up so we can properly handle 'referenced sql column values'
|
||||
// we need the numbers to match up so that we can properly handle 'referenced sql column values'
|
||||
if ( inDatabaseStrategies.size() != composite.getPropertySpan() ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"Internal error : mismatch between number of collected in-db generation strategies" +
|
||||
|
@ -658,57 +661,20 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
|
||||
// then use the aggregated values to build the InDatabaseValueGenerationStrategy
|
||||
return new GenerationStrategyPair(
|
||||
new InDatabaseGeneratorImpl( timing, referenceColumns, columnValues )
|
||||
);
|
||||
return new InDatabaseGeneratorImpl( timing, referenceColumns, columnValues );
|
||||
}
|
||||
else {
|
||||
return NO_GEN_PAIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoInMemoryGenerator implements InMemoryGenerator {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NoInMemoryGenerator INSTANCE = new NoInMemoryGenerator();
|
||||
|
||||
return new Generator() {
|
||||
@Override
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
return GenerationTiming.NEVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
return null;
|
||||
public boolean generatedByDatabase() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class NoInDatabaseGenerator implements InDatabaseGenerator {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NoInDatabaseGenerator INSTANCE = new NoInDatabaseGenerator();
|
||||
|
||||
@Override
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
return GenerationTiming.NEVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnsInSql() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePropertyValue() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -769,18 +735,18 @@ public class EntityMetamodel implements Serializable {
|
|||
// Assumptions:
|
||||
// * That code checks that there is a natural identifier before making this call, so we assume the same here
|
||||
// * That code assumes a non-composite natural-id, so we assume the same here
|
||||
final InDatabaseGenerator strategy = inDatabaseValueGenerationStrategies[ naturalIdPropertyNumbers[0] ];
|
||||
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
|
||||
final Generator strategy = generators[ naturalIdPropertyNumbers[0] ];
|
||||
return strategy != null && strategy.getGenerationTiming().isNotNever();
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedByDatabase() {
|
||||
final InDatabaseGenerator strategy = inDatabaseValueGenerationStrategies[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
|
||||
final Generator strategy = generators[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.getGenerationTiming().isNotNever() && strategy.generatedByDatabase();
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedInMemory() {
|
||||
final InMemoryGenerator strategy = inMemoryValueGenerationStrategies[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
|
||||
final Generator strategy = generators[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.getGenerationTiming().isNotNever() && !strategy.generatedByDatabase();
|
||||
}
|
||||
|
||||
public int[] getNaturalIdentifierProperties() {
|
||||
|
@ -1054,16 +1020,8 @@ public class EntityMetamodel implements Serializable {
|
|||
return hasUpdateGeneratedValues;
|
||||
}
|
||||
|
||||
public InMemoryGenerator[] getInMemoryValueGenerationStrategies() {
|
||||
return inMemoryValueGenerationStrategies;
|
||||
}
|
||||
|
||||
public InDatabaseGenerator[] getInDatabaseValueGenerationStrategies() {
|
||||
return inDatabaseValueGenerationStrategies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this class can be lazy (ie intercepted)
|
||||
* Whether this class can be lazy (ie intercepted)
|
||||
*/
|
||||
public boolean isInstrumented() {
|
||||
return bytecodeEnhancementMetadata.isEnhancedForLazyLoading();
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.Remove;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
|
@ -38,7 +39,6 @@ import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
|||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.tuple.PropertyFactory;
|
||||
import org.hibernate.tuple.StandardProperty;
|
||||
import org.hibernate.tuple.ValueGeneration;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.spi.CompositeTypeImplementor;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
@ -53,7 +53,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
|
||||
private final String[] propertyNames;
|
||||
private final Type[] propertyTypes;
|
||||
private final Generator[] propertyValueGenerationStrategies;
|
||||
private final boolean[] propertyNullability;
|
||||
private final int[] originalPropertyOrder;
|
||||
protected final int propertySpan;
|
||||
|
@ -76,7 +75,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
this.originalPropertyOrder = originalPropertyOrder;
|
||||
this.propertyNames = new String[propertySpan];
|
||||
this.propertyTypes = new Type[propertySpan];
|
||||
this.propertyValueGenerationStrategies = new ValueGeneration[propertySpan];
|
||||
this.propertyNullability = new boolean[propertySpan];
|
||||
this.cascade = new CascadeStyle[propertySpan];
|
||||
this.joinedFetch = new FetchMode[propertySpan];
|
||||
|
@ -93,7 +91,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
if ( !prop.isNullable() ) {
|
||||
hasNotNullProperty = true;
|
||||
}
|
||||
this.propertyValueGenerationStrategies[i] = prop.getValueGenerationStrategy();
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -438,8 +435,9 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
return propertyTypes;
|
||||
}
|
||||
|
||||
@Deprecated(since = "6.2") @Remove
|
||||
public Generator[] getPropertyValueGenerationStrategies() {
|
||||
return propertyValueGenerationStrategies;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -84,12 +84,10 @@ public class GeneratedUuidTests {
|
|||
//end::mapping-generated-custom-ex2[]
|
||||
|
||||
//tag::mapping-generated-custom-ex3[]
|
||||
public static class UuidValueGeneration
|
||||
implements AnnotationGenerator<GeneratedUuidValue>, InMemoryGenerator {
|
||||
private GenerationTiming timing;
|
||||
public static class UuidValueGeneration implements InMemoryGenerator {
|
||||
private final GenerationTiming timing;
|
||||
|
||||
@Override
|
||||
public void initialize(GeneratedUuidValue annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||
public UuidValueGeneration(GeneratedUuidValue annotation) {
|
||||
timing = annotation.timing();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,10 @@ import org.hibernate.envers.internal.entities.mapper.CompositeMapperBuilder;
|
|||
import org.hibernate.envers.internal.entities.mapper.ExtendedPropertyMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.SubclassPropertyMapper;
|
||||
import org.hibernate.mapping.GeneratorCreator;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.SyntheticProperty;
|
||||
import org.hibernate.tuple.Generator;
|
||||
import org.hibernate.tuple.GeneratedValueGeneration;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -119,7 +119,8 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
|
|||
|
||||
private boolean isPropertyInsertable(Property property) {
|
||||
if ( !property.isInsertable() ) {
|
||||
final Generator generation = property.getValueGenerationStrategy();
|
||||
// TODO: this is now broken by changes to generators
|
||||
final GeneratorCreator generation = property.getValueGenerationStrategy();
|
||||
if ( generation instanceof GeneratedValueGeneration ) {
|
||||
final GeneratedValueGeneration valueGeneration = (GeneratedValueGeneration) generation;
|
||||
if ( valueGeneration.getGenerationTiming().includesInsert() ) {
|
||||
|
@ -142,7 +143,6 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
|
|||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createJoins(PersistentClass persistentClass, JoinAwarePersistentEntity entity, ClassAuditingData auditingData) {
|
||||
final Iterator<org.hibernate.mapping.Join> joins = persistentClass.getJoinIterator();
|
||||
final Map<org.hibernate.mapping.Join, Join> joinElements = new HashMap<>();
|
||||
|
|
Loading…
Reference in New Issue