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