HHH-15782 make @ValueGenerationType work with the new "split" hierarchy of value generators
this was a lot easier than I thought it would be
This commit is contained in:
parent
82db252422
commit
f022d6ef3b
|
@ -13,8 +13,9 @@ 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.AnnotationValueGeneration;
|
import org.hibernate.tuple.AnnotationValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.GenerationTiming;
|
import org.hibernate.tuple.GenerationTiming;
|
||||||
|
import org.hibernate.tuple.InMemoryValueGenerationStrategy;
|
||||||
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;
|
||||||
|
@ -42,7 +43,8 @@ import static org.hibernate.tuple.GenerationTiming.ALWAYS;
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.2")
|
@Deprecated(since = "6.2")
|
||||||
@Internal
|
@Internal
|
||||||
public class SourceGeneration implements AnnotationValueGeneration<Source>, ValueGenerator<Object> {
|
public class SourceGeneration
|
||||||
|
implements AnnotationValueGenerationStrategy<Source>, InMemoryValueGenerationStrategy, ValueGenerator<Object> {
|
||||||
|
|
||||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||||
CoreMessageLogger.class,
|
CoreMessageLogger.class,
|
||||||
|
@ -53,6 +55,10 @@ public class SourceGeneration implements AnnotationValueGeneration<Source>, Valu
|
||||||
private ValueGenerator<?> valueGenerator;
|
private ValueGenerator<?> valueGenerator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void initialize(Source annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||||
|
initialize( annotation, propertyType );
|
||||||
|
}
|
||||||
|
|
||||||
public void initialize(Source annotation, Class<?> propertyType) {
|
public void initialize(Source annotation, Class<?> propertyType) {
|
||||||
this.propertyType = propertyType;
|
this.propertyType = propertyType;
|
||||||
switch ( annotation.value() ) {
|
switch ( annotation.value() ) {
|
||||||
|
@ -77,16 +83,6 @@ public class SourceGeneration implements AnnotationValueGeneration<Source>, Valu
|
||||||
return valueGenerator;
|
return valueGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object generateValue(Session session, Object owner) {
|
public Object generateValue(Session session, Object owner) {
|
||||||
SharedSessionContractImplementor implementor = (SharedSessionContractImplementor) session;
|
SharedSessionContractImplementor implementor = (SharedSessionContractImplementor) session;
|
||||||
|
|
|
@ -6,25 +6,25 @@
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
|
|
||||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
import org.hibernate.tuple.ValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.ValueGeneration;
|
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta-annotation used to mark another annotation as providing configuration
|
* Meta-annotation used to mark another annotation as providing configuration
|
||||||
* for a custom {@linkplain ValueGeneration value generation strategy}. This
|
* for a custom {@linkplain ValueGenerationStrategy value generation strategy}.
|
||||||
* is the best way to work with customized value generation in Hibernate.
|
* This is the best way to work with customized value generation in Hibernate.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, if we have a custom value generator:
|
* For example, if we have a custom value generator:
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* public class SKUGeneration implements AnnotationValueGeneration<SKU>, ValueGenerator<String> {
|
* public class SKUGeneration
|
||||||
|
* implements InMemoryValueGenerationStrategy,
|
||||||
|
* ValueGenerator<String> {
|
||||||
* ...
|
* ...
|
||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
|
@ -43,10 +43,18 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
* property to be generated when any SQL statement to {@code insert} or
|
* property to be generated when any SQL statement to {@code insert} or
|
||||||
* {@code update} the entity is executed.
|
* {@code update} the entity is executed.
|
||||||
* <p>
|
* <p>
|
||||||
* Each generator annotation type has an {@link AnnotationValueGeneration}
|
* Every generator annotation type has an {@link ValueGenerationStrategy}
|
||||||
* implementation which is responsible for generating values. The generator
|
* implementation which is responsible for generating values. It must be either:
|
||||||
* annotation may have members, which are used to configure the generator,
|
* <ul>
|
||||||
* when {@link AnnotationValueGeneration#initialize} is called.
|
* <li>an {@link org.hibernate.tuple.InMemoryValueGenerationStrategy}, for
|
||||||
|
* values that are generated in Java code, using a
|
||||||
|
* {@link org.hibernate.tuple.ValueGenerator}, or
|
||||||
|
* <li>an {@link org.hibernate.tuple.InDatabaseValueGenerationStrategy}, for
|
||||||
|
* values which are generated by the database.
|
||||||
|
* </ul>
|
||||||
|
* A generator annotation may have members, which are used to configure the
|
||||||
|
* generation strategy, when the strategy instance in initialized via
|
||||||
|
* {@link org.hibernate.tuple.AnnotationValueGenerationStrategy#initialize}.
|
||||||
* <p>
|
* <p>
|
||||||
* There are several excellent examples of the use of this machinery right
|
* There are several excellent examples of the use of this machinery right
|
||||||
* here in this package. {@link TenantId} and its corresponding generator
|
* here in this package. {@link TenantId} and its corresponding generator
|
||||||
|
@ -55,16 +63,22 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
* A {@code @ValueGenerationType} annotation must have retention policy
|
* A {@code @ValueGenerationType} annotation must have retention policy
|
||||||
* {@link RetentionPolicy#RUNTIME}.
|
* {@link RetentionPolicy#RUNTIME}.
|
||||||
*
|
*
|
||||||
|
* @see ValueGenerationStrategy
|
||||||
|
* @see org.hibernate.tuple.InMemoryValueGenerationStrategy
|
||||||
|
* @see org.hibernate.tuple.InDatabaseValueGenerationStrategy
|
||||||
|
* @see org.hibernate.tuple.AnnotationValueGenerationStrategy
|
||||||
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
@Target(ANNOTATION_TYPE)
|
@Target(ANNOTATION_TYPE)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface ValueGenerationType {
|
public @interface ValueGenerationType {
|
||||||
/**
|
/**
|
||||||
* The type of value generation associated with the annotated value generator annotation type. The referenced
|
* A class that implements {@link ValueGenerationStrategy}.
|
||||||
* generation type must be parameterized with the type of the given generator annotation.
|
* <p>
|
||||||
*
|
* If the generator annotation has members used to configure the
|
||||||
* @return the value generation type
|
* generation strategy instance, the strategy should implement
|
||||||
|
* {@link org.hibernate.tuple.AnnotationValueGenerationStrategy}.
|
||||||
*/
|
*/
|
||||||
Class<? extends AnnotationValueGeneration<?>> generatedBy();
|
Class<? extends ValueGenerationStrategy> generatedBy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ import org.hibernate.mapping.ToOne;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||||
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
||||||
|
import org.hibernate.tuple.AnnotationValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.ValueGenerationStrategy;
|
import org.hibernate.tuple.ValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
|
||||||
import org.hibernate.tuple.AttributeBinder;
|
import org.hibernate.tuple.AttributeBinder;
|
||||||
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
|
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.GenerationTiming;
|
import org.hibernate.tuple.GenerationTiming;
|
||||||
|
@ -402,10 +402,10 @@ public class PropertyBinder {
|
||||||
/**
|
/**
|
||||||
* Returns the value generation strategy for the given property, if any.
|
* Returns the value generation strategy for the given property, if any.
|
||||||
*/
|
*/
|
||||||
private ValueGeneration getValueGenerationFromAnnotations(XProperty property) {
|
private ValueGenerationStrategy getValueGenerationFromAnnotations(XProperty property) {
|
||||||
AnnotationValueGeneration<?> valueGeneration = null;
|
ValueGenerationStrategy valueGeneration = null;
|
||||||
for ( Annotation annotation : property.getAnnotations() ) {
|
for ( Annotation annotation : property.getAnnotations() ) {
|
||||||
AnnotationValueGeneration<?> candidate = getValueGenerationFromAnnotation( property, annotation );
|
final ValueGenerationStrategy candidate = getValueGenerationFromAnnotation( property, annotation );
|
||||||
if ( candidate != null ) {
|
if ( candidate != null ) {
|
||||||
if ( valueGeneration != null ) {
|
if ( valueGeneration != null ) {
|
||||||
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
|
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
|
||||||
|
@ -423,16 +423,16 @@ public class PropertyBinder {
|
||||||
* 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 <A extends Annotation> AnnotationValueGeneration<A> getValueGenerationFromAnnotation(
|
private ValueGenerationStrategy getValueGenerationFromAnnotation(
|
||||||
XProperty property,
|
XProperty property,
|
||||||
A annotation) {
|
Annotation annotation) {
|
||||||
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );
|
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );
|
||||||
if ( generatorAnnotation == null ) {
|
if ( generatorAnnotation == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Class<? extends AnnotationValueGeneration<?>> generationType = generatorAnnotation.generatedBy();
|
final ValueGenerationStrategy valueGeneration =
|
||||||
final AnnotationValueGeneration<A> valueGeneration = instantiateAndInitializeValueGeneration( annotation, generationType, property );
|
instantiateAndInitializeValueGeneration( annotation, generatorAnnotation.generatedBy(), property );
|
||||||
|
|
||||||
if ( annotation.annotationType() == Generated.class && property.isAnnotationPresent(Version.class) ) {
|
if ( annotation.annotationType() == Generated.class && property.isAnnotationPresent(Version.class) ) {
|
||||||
switch ( valueGeneration.getGenerationTiming() ) {
|
switch ( valueGeneration.getGenerationTiming() ) {
|
||||||
|
@ -456,23 +456,26 @@ public class PropertyBinder {
|
||||||
* 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> AnnotationValueGeneration<A> instantiateAndInitializeValueGeneration(
|
private <A extends Annotation> ValueGenerationStrategy instantiateAndInitializeValueGeneration(
|
||||||
A annotation,
|
A annotation,
|
||||||
Class<? extends AnnotationValueGeneration<?>> generationType,
|
Class<? extends ValueGenerationStrategy> generationType,
|
||||||
XProperty property) {
|
XProperty property) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// This will cause a CCE in case the generation type doesn't match the annotation type; As this would be a
|
final ValueGenerationStrategy valueGeneration = generationType.newInstance();
|
||||||
// programming error of the generation type developer and thus should show up during testing, we don't
|
if ( valueGeneration instanceof AnnotationValueGenerationStrategy ) {
|
||||||
// check this explicitly; If required, this could be done e.g. using ClassMate
|
// This will cause a CCE in case the generation type doesn't match the annotation type; As this would be
|
||||||
@SuppressWarnings( "unchecked" )
|
// a programming error of the generation type developer and thus should show up during testing, we don't
|
||||||
AnnotationValueGeneration<A> valueGeneration = (AnnotationValueGeneration<A>) generationType.newInstance();
|
// check this explicitly; If required, this could be done e.g. using ClassMate
|
||||||
valueGeneration.initialize(
|
@SuppressWarnings("unchecked")
|
||||||
annotation,
|
final AnnotationValueGenerationStrategy<A> generation = (AnnotationValueGenerationStrategy<A>) valueGeneration;
|
||||||
buildingContext.getBootstrapContext().getReflectionManager().toClass( property.getType() ),
|
generation.initialize(
|
||||||
entityBinder.getPersistentClass().getEntityName(),
|
annotation,
|
||||||
property.getName()
|
buildingContext.getBootstrapContext().getReflectionManager().toClass( property.getType() ),
|
||||||
);
|
entityBinder.getPersistentClass().getEntityName(),
|
||||||
|
property.getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return valueGeneration;
|
return valueGeneration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,27 +14,28 @@ import java.lang.annotation.Annotation;
|
||||||
*
|
*
|
||||||
* @param <A> The generator annotation type supported by an implementation
|
* @param <A> The generator annotation type supported by an implementation
|
||||||
*
|
*
|
||||||
|
* @see org.hibernate.annotations.ValueGenerationType
|
||||||
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public interface AnnotationValueGeneration<A extends Annotation> extends ValueGeneration {
|
public interface AnnotationValueGeneration<A extends Annotation>
|
||||||
|
extends ValueGeneration, AnnotationValueGenerationStrategy<A> {
|
||||||
/**
|
/**
|
||||||
* 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 propertyType the type of the property annotated with the generator annotation. Implementations may use
|
||||||
* the type to determine the right {@link ValueGenerator} to be applied.
|
* the type to determine the right {@link ValueGenerator} to be applied.
|
||||||
*
|
|
||||||
* @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);
|
void initialize(A annotation, Class<?> propertyType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 propertyType the type of the property annotated with the generator annotation. Implementations may use
|
||||||
* the type to determine the right {@link ValueGenerator} to be applied.
|
* the type to determine the right {@link ValueGenerator} to be applied.
|
||||||
|
@ -45,6 +46,6 @@ public interface AnnotationValueGeneration<A extends Annotation> extends ValueGe
|
||||||
* an implementation can't create a value for the given property type.
|
* an implementation can't create a value for the given property type.
|
||||||
*/
|
*/
|
||||||
default void initialize(A annotation, Class<?> propertyType, String entityName, String propertyName) {
|
default void initialize(A annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||||
initialize(annotation, propertyType);
|
initialize( annotation, propertyType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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 java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ValueGenerationStrategy} based on a custom Java generator annotation type.
|
||||||
|
* Every instance must implement either {@link InMemoryValueGenerationStrategy} or
|
||||||
|
* {@link InDatabaseValueGenerationStrategy}.
|
||||||
|
*
|
||||||
|
* @param <A> The generator annotation type supported by an implementation
|
||||||
|
*
|
||||||
|
* @see org.hibernate.annotations.ValueGenerationType
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
* @author Gavin King
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
public interface AnnotationValueGenerationStrategy<A extends Annotation> extends ValueGenerationStrategy {
|
||||||
|
/**
|
||||||
|
* Initializes this generation strategy for the given annotation instance.
|
||||||
|
*
|
||||||
|
* @param annotation an instance of the strategy's annotation type. Typically, implementations will retrieve the
|
||||||
|
* annotation's attribute values and store them in fields.
|
||||||
|
* @param propertyType the type of the property annotated with the generator annotation. Implementations may use
|
||||||
|
* the type to determine the right {@link ValueGenerator} to be applied.
|
||||||
|
* @param entityName the name of the entity to which the annotated property belongs
|
||||||
|
* @param propertyName the name of the annotated property
|
||||||
|
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if
|
||||||
|
* an implementation can't create a value for the given property type.
|
||||||
|
*/
|
||||||
|
void initialize(A annotation, Class<?> propertyType, String entityName, String propertyName);
|
||||||
|
}
|
|
@ -7,37 +7,35 @@
|
||||||
package org.hibernate.tuple;
|
package org.hibernate.tuple;
|
||||||
|
|
||||||
import org.hibernate.annotations.GeneratedColumn;
|
import org.hibernate.annotations.GeneratedColumn;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For {@link GeneratedColumn}
|
* For {@link GeneratedColumn}.
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class GeneratedAlwaysValueGeneration implements AnnotationValueGeneration<GeneratedColumn> {
|
public class GeneratedAlwaysValueGeneration
|
||||||
|
implements InDatabaseValueGenerationStrategy {
|
||||||
|
|
||||||
public GeneratedAlwaysValueGeneration() {}
|
public GeneratedAlwaysValueGeneration() {}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(GeneratedColumn annotation, Class<?> propertyType) {}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GenerationTiming getGenerationTiming() {
|
public GenerationTiming getGenerationTiming() {
|
||||||
return GenerationTiming.ALWAYS;
|
return GenerationTiming.ALWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueGenerator<?> getValueGenerator() {
|
public boolean writePropertyValue() {
|
||||||
// database generated values do not have a value generator
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
public boolean referenceColumnsInSql() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.tuple;
|
package org.hibernate.tuple;
|
||||||
|
|
||||||
import org.hibernate.annotations.Generated;
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
|
||||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||||
|
|
||||||
|
@ -16,11 +17,12 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class GeneratedValueGeneration implements AnnotationValueGeneration<Generated> {
|
public class GeneratedValueGeneration
|
||||||
|
implements AnnotationValueGenerationStrategy<Generated>, InDatabaseValueGenerationStrategy {
|
||||||
|
|
||||||
private GenerationTiming timing;
|
private GenerationTiming timing;
|
||||||
private boolean writable;
|
private boolean writable;
|
||||||
private String sql;
|
private String[] sql;
|
||||||
|
|
||||||
public GeneratedValueGeneration() {
|
public GeneratedValueGeneration() {
|
||||||
}
|
}
|
||||||
|
@ -30,9 +32,9 @@ public class GeneratedValueGeneration implements AnnotationValueGeneration<Gener
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(Generated annotation, Class<?> propertyType) {
|
public void initialize(Generated annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||||
timing = annotation.value().getEquivalent();
|
timing = annotation.value().getEquivalent();
|
||||||
sql = isEmpty( annotation.sql() ) ? null : annotation.sql();
|
sql = isEmpty( annotation.sql() ) ? null : new String[] { annotation.sql() };
|
||||||
writable = annotation.writable() || sql != null;
|
writable = annotation.writable() || sql != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,19 +44,18 @@ public class GeneratedValueGeneration implements AnnotationValueGeneration<Gener
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueGenerator<?> getValueGenerator() {
|
public boolean referenceColumnsInSql() {
|
||||||
// database generated values do not have a value generator
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return writable;
|
return writable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writePropertyValue() {
|
||||||
|
return writable && sql==null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ import org.hibernate.dialect.Dialect;
|
||||||
* {@code select}.
|
* {@code select}.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
public interface InDatabaseValueGenerationStrategy extends ValueGenerationStrategy {
|
public interface InDatabaseValueGenerationStrategy extends ValueGenerationStrategy {
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ package org.hibernate.tuple;
|
||||||
* or property value.
|
* or property value.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
public interface InMemoryValueGenerationStrategy extends ValueGenerationStrategy {
|
public interface InMemoryValueGenerationStrategy extends ValueGenerationStrategy {
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ import org.hibernate.type.descriptor.java.JavaType;
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class TenantIdGeneration implements AnnotationValueGeneration<TenantId>, ValueGenerator<Object> {
|
public class TenantIdGeneration
|
||||||
|
implements AnnotationValueGenerationStrategy<TenantId>, InMemoryValueGenerationStrategy, ValueGenerator<Object> {
|
||||||
|
|
||||||
private String entityName;
|
private String entityName;
|
||||||
private String propertyName;
|
private String propertyName;
|
||||||
|
@ -32,11 +33,6 @@ public class TenantIdGeneration implements AnnotationValueGeneration<TenantId>,
|
||||||
this.propertyType = propertyType;
|
this.propertyType = propertyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(TenantId annotation, Class<?> propertyType) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GenerationTiming getGenerationTiming() {
|
public GenerationTiming getGenerationTiming() {
|
||||||
return GenerationTiming.INSERT;
|
return GenerationTiming.INSERT;
|
||||||
|
@ -79,14 +75,4 @@ public class TenantIdGeneration implements AnnotationValueGeneration<TenantId>,
|
||||||
public Object generateValue(Session session, Object owner) {
|
public Object generateValue(Session session, Object owner) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,22 @@ import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the generation of values of a certain field or property of an entity. A generated
|
* Describes the generation of values of a certain field or property of an entity. A generated
|
||||||
* value might be generated in Java, or by the database.
|
* value might be generated in Java, or by the database. Every instance must implement either
|
||||||
|
* {@link InMemoryValueGenerationStrategy} or {@link InDatabaseValueGenerationStrategy}
|
||||||
|
* depending on whether values are generated in Java code, or by the database.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
|
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
|
||||||
* In this case, the generated value is written to the database just like any other field
|
* In this case, the generated value is written to the database just like any other field
|
||||||
* or property value.
|
* or property value.
|
||||||
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
|
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
|
||||||
* a {@code default} column value specified in DDL, for example, or it might be generated
|
* a {@code default} column value specified in DDL, for example, or it might be generated
|
||||||
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
|
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
|
||||||
* statement. In this case, the generated value is retrieved from the database using a SQL
|
* statement. In this case, the generated value is retrieved from the database using a SQL
|
||||||
* {@code select}.
|
* {@code select}.
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* If an implementation of {@code ValueGenerationStrategy} may be associated with an entity
|
||||||
|
* via a {@linkplain org.hibernate.annotations.ValueGenerationType custom annotation}, it
|
||||||
|
* should implement {@link AnnotationValueGenerationStrategy}.
|
||||||
*
|
*
|
||||||
* @see org.hibernate.annotations.ValueGenerationType
|
* @see org.hibernate.annotations.ValueGenerationType
|
||||||
* @see org.hibernate.annotations.Generated
|
* @see org.hibernate.annotations.Generated
|
||||||
|
@ -28,6 +33,8 @@ import java.io.Serializable;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
public interface ValueGenerationStrategy extends Serializable {
|
public interface ValueGenerationStrategy extends Serializable {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,21 +13,20 @@ import org.hibernate.annotations.GeneratorType;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link AnnotationValueGeneration} which allows to specify the {@link ValueGenerator} to be used to determine the
|
* An {@link AnnotationValueGeneration} which delegates to a {@link ValueGenerator}.
|
||||||
* value of the annotated property.
|
|
||||||
*
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class VmValueGeneration implements AnnotationValueGeneration<GeneratorType> {
|
public class VmValueGeneration
|
||||||
|
implements AnnotationValueGenerationStrategy<GeneratorType>, InMemoryValueGenerationStrategy {
|
||||||
|
|
||||||
private GenerationTiming generationTiming;
|
private GenerationTiming generationTiming;
|
||||||
private Constructor<? extends ValueGenerator<?>> constructor;
|
private Constructor<? extends ValueGenerator<?>> constructor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(GeneratorType annotation, Class<?> propertyType) {
|
public void initialize(GeneratorType annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||||
Class<? extends ValueGenerator<?>> generatorType = annotation.type();
|
constructor = ReflectHelper.getDefaultConstructor( annotation.type() );
|
||||||
constructor = ReflectHelper.getDefaultConstructor( generatorType );
|
generationTiming = annotation.when().getEquivalent();
|
||||||
this.generationTiming = annotation.when().getEquivalent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,14 +43,4 @@ public class VmValueGeneration implements AnnotationValueGeneration<GeneratorTyp
|
||||||
throw new HibernateException( "Couldn't instantiate value generator", e );
|
throw new HibernateException( "Couldn't instantiate value generator", e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,9 @@ import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.annotations.ValueGenerationType;
|
import org.hibernate.annotations.ValueGenerationType;
|
||||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
import org.hibernate.tuple.AnnotationValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.GenerationTiming;
|
import org.hibernate.tuple.GenerationTiming;
|
||||||
|
import org.hibernate.tuple.InMemoryValueGenerationStrategy;
|
||||||
import org.hibernate.tuple.ValueGenerator;
|
import org.hibernate.tuple.ValueGenerator;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
@ -86,11 +87,12 @@ 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 implements AnnotationValueGeneration<GeneratedUuidValue>, ValueGenerator<UUID> {
|
public static class UuidValueGeneration
|
||||||
|
implements AnnotationValueGenerationStrategy<GeneratedUuidValue>, InMemoryValueGenerationStrategy, ValueGenerator<UUID> {
|
||||||
private GenerationTiming timing;
|
private GenerationTiming timing;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(GeneratedUuidValue annotation, Class<?> propertyType) {
|
public void initialize(GeneratedUuidValue annotation, Class<?> propertyType, String entityName, String propertyName) {
|
||||||
timing = annotation.timing();
|
timing = annotation.timing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,16 +106,6 @@ public class GeneratedUuidTests {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean referenceColumnInSql() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID generateValue(Session session, Object owner) {
|
public UUID generateValue(Session session, Object owner) {
|
||||||
return UUID.randomUUID();
|
return UUID.randomUUID();
|
||||||
|
|
Loading…
Reference in New Issue