From fd57a751b4a34675d80609f0924319fc312fff85 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Wed, 6 Nov 2013 10:10:15 +0100 Subject: [PATCH] HHH-2907 Retrofitting @Generated, making it a generator annotation type --- .../org/hibernate/annotations/Generated.java | 4 + .../java/org/hibernate/cfg/HbmBinder.java | 35 +------- .../cfg/annotations/PropertyBinder.java | 89 ++++--------------- .../tuple/GeneratedValueGeneration.java | 71 +++++++++++++++ 4 files changed, 96 insertions(+), 103 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/tuple/GeneratedValueGeneration.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Generated.java b/hibernate-core/src/main/java/org/hibernate/annotations/Generated.java index 3885c78ef5..c65995c7da 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Generated.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Generated.java @@ -28,14 +28,18 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.hibernate.tuple.GeneratedValueGeneration; + /** * The annotated property is generated by the database. * * @author Emmanuel Bernard */ +@ValueGenerationType( generatedBy = GeneratedValueGeneration.class ) @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Generated { + /** * The enum value representing when the value is generated. */ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java index 70b762dfc8..15f4ad1fea 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java @@ -34,7 +34,6 @@ import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.jboss.logging.Logger; - import org.hibernate.CacheMode; import org.hibernate.EntityMode; import org.hibernate.FetchMode; @@ -96,6 +95,7 @@ import org.hibernate.mapping.TypeDef; import org.hibernate.mapping.UnionSubclass; import org.hibernate.mapping.UniqueKey; import org.hibernate.mapping.Value; +import org.hibernate.tuple.GeneratedValueGeneration; import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerator; @@ -1307,7 +1307,7 @@ public final class HbmBinder { if ( generationTiming == GenerationTiming.ALWAYS || generationTiming == GenerationTiming.INSERT ) { // we had generation specified... // HBM only supports "database generated values" - property.setValueGenerationStrategy( new HbmDefinedValueGeneration( generationTiming ) ); + property.setValueGenerationStrategy( new GeneratedValueGeneration( generationTiming ) ); // generated properties can *never* be insertable... if ( property.isInsertable() ) { @@ -1370,37 +1370,6 @@ public final class HbmBinder { } - private static class HbmDefinedValueGeneration implements ValueGeneration { - private final GenerationTiming timing; - - private HbmDefinedValueGeneration(GenerationTiming timing) { - this.timing = timing; - } - - @Override - public GenerationTiming getGenerationTiming() { - return timing; - } - - @Override - public ValueGenerator getValueGenerator() { - // database generated values do not have a value generator - return null; - } - - @Override - public boolean referenceColumnInSql() { - // historically these columns are not referenced in the SQL - return false; - } - - @Override - public String getDatabaseGeneratedReferencedColumnValue() { - // the column is not referenced in the sql. - return null; - } - } - private static String columns(Value val) { StringBuilder columns = new StringBuilder(); Iterator iter = val.getColumnIterator(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java index f1734d340c..9b54da4a19 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java @@ -33,7 +33,6 @@ import javax.persistence.Lob; import org.hibernate.AnnotationException; import org.hibernate.HibernateException; import org.hibernate.annotations.Generated; -import org.hibernate.annotations.GenerationTime; import org.hibernate.annotations.Immutable; import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.OptimisticLock; @@ -333,50 +332,22 @@ public class PropertyBinder { } private ValueGeneration determineValueGenerationStrategy(XProperty property) { - ValueGeneration annotationValueGeneration = getValueGenerationFromAnnotations( property ); - ValueGeneration legacyValueGeneration = getLegacyValueGeneration( property ); + ValueGeneration valueGeneration = getValueGenerationFromAnnotations( property ); - if ( annotationValueGeneration == null && legacyValueGeneration == null ) { + if ( valueGeneration == null ) { return NoValueGeneration.INSTANCE; } - else if ( annotationValueGeneration != null && legacyValueGeneration != null ) { - throw new AnnotationException( - "@Generated and a generator annotation must not be specified at the same time:" + StringHelper.qualify( - holder.getPath(), - name - ) - ); - } - final GenerationTiming when = annotationValueGeneration != null ? - annotationValueGeneration.getGenerationTiming() : - legacyValueGeneration.getGenerationTiming(); + final GenerationTiming when = valueGeneration.getGenerationTiming(); - if ( property.isAnnotationPresent( javax.persistence.Version.class ) && when == GenerationTiming.INSERT ) { - throw new AnnotationException( - "@Generated(INSERT) on a @Version property not allowed, use ALWAYS (or NEVER): " - + StringHelper.qualify( holder.getPath(), name ) - ); - } - - if ( legacyValueGeneration != null ) { + if ( valueGeneration.getValueGenerator() == null ) { insertable = false; if ( when == GenerationTiming.ALWAYS ) { updatable = false; } } - return annotationValueGeneration != null ? annotationValueGeneration : legacyValueGeneration; - } - - private ValueGeneration getLegacyValueGeneration(XProperty property) { - Generated generatedAnnotation = property.getAnnotation( Generated.class ); - - if ( generatedAnnotation != null && generatedAnnotation.value() != null && generatedAnnotation.value() != GenerationTime.NEVER ) { - return new LegacyValueGeneration( generatedAnnotation.value().getEquivalent() ); - } - - return null; + return valueGeneration; } /** @@ -421,9 +392,21 @@ public class PropertyBinder { } Class> generationType = generatorAnnotation.generatedBy(); - return instantiateAndInitializeValueGeneration( + AnnotationValueGeneration valueGeneration = instantiateAndInitializeValueGeneration( annotation, generationType, property ); + + if ( annotation.annotationType() == Generated.class && + property.isAnnotationPresent( javax.persistence.Version.class ) && + valueGeneration.getGenerationTiming() == GenerationTiming.INSERT ) { + + throw new AnnotationException( + "@Generated(INSERT) on a @Version property not allowed, use ALWAYS (or NEVER): " + + StringHelper.qualify( holder.getPath(), name ) + ); + } + + return valueGeneration; } /** @@ -470,7 +453,7 @@ public class PropertyBinder { } @Override - public ValueGenerator getValueGenerator() { + public ValueGenerator getValueGenerator() { return null; } @@ -485,40 +468,6 @@ public class PropertyBinder { } } - private static class LegacyValueGeneration implements ValueGeneration { - private final GenerationTiming timing; - - private LegacyValueGeneration(GenerationTiming timing) { - this.timing = timing; - } - - @Override - public GenerationTiming getGenerationTiming() { - return timing; - } - - @Override - public ValueGenerator getValueGenerator() { - // database generated values do not have a value generator - return null; - } - - @Override - public boolean referenceColumnInSql() { - // historically these columns are not referenced in the SQL - return false; - } - - @Override - public String getDatabaseGeneratedReferencedColumnValue() { - return null; - } - } - - private boolean isCollection(Value value) { - return Collection.class.isInstance( value ); - } - private boolean isToOneValue(Value value) { return ToOne.class.isInstance( value ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/GeneratedValueGeneration.java b/hibernate-core/src/main/java/org/hibernate/tuple/GeneratedValueGeneration.java new file mode 100644 index 0000000000..de428c2df3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tuple/GeneratedValueGeneration.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.tuple; + +import org.hibernate.annotations.Generated; + +/** + * A {@link AnnotationValueGeneration} which marks a property as generated in the database. + * + * @author Steve Ebersole + * @author Gunnar Morling + */ +public class GeneratedValueGeneration implements AnnotationValueGeneration { + + private GenerationTiming timing; + + public GeneratedValueGeneration() { + } + + public GeneratedValueGeneration(GenerationTiming timing) { + this.timing = timing; + } + + @Override + public void initialize(Generated annotation, Class propertyType) { + this.timing = annotation.value().getEquivalent(); + } + + @Override + public GenerationTiming getGenerationTiming() { + return timing; + } + + @Override + public ValueGenerator getValueGenerator() { + // database generated values do not have a value generator + return null; + } + + @Override + public boolean referenceColumnInSql() { + // historically these columns are not referenced in the SQL + return false; + } + + @Override + public String getDatabaseGeneratedReferencedColumnValue() { + return null; + } +}