Skip to content

Commit b350c1a

Browse files
committed
different approach to overriding SQL in annotations
introduces the @ForDialect annotation, which is really a perfectly elegant thing if you're careful not to look at its implementation this approach has the advantage that it doesn't impact the existing annotations at all: it's completely self-contained
1 parent abd63d7 commit b350c1a

File tree

5 files changed

+98
-21
lines changed

5 files changed

+98
-21
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.annotations;
8+
9+
import jakarta.persistence.DiscriminatorColumn;
10+
import org.hibernate.dialect.Dialect;
11+
12+
import java.lang.annotation.Retention;
13+
import java.lang.annotation.Target;
14+
15+
import static java.lang.annotation.ElementType.FIELD;
16+
import static java.lang.annotation.ElementType.METHOD;
17+
import static java.lang.annotation.ElementType.TYPE;
18+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
19+
20+
/**
21+
* Allows certain annotations to be overridden in a given SQL {@link Dialect}.
22+
*
23+
* @author Gavin King
24+
*/
25+
@Target({METHOD, FIELD, TYPE})
26+
@Retention(RUNTIME)
27+
public @interface ForDialect {
28+
/**
29+
* The {@link Dialect} in which this override applies.
30+
*/
31+
Class<? extends Dialect> dialect();
32+
33+
//The "?" indicates a null annotation, that is, no override for that annotation type
34+
35+
Check check() default @Check(constraints = "?");
36+
OrderBy orderBy() default @OrderBy(clause = "?");
37+
ColumnDefault columnDefault() default @ColumnDefault("?");
38+
GeneratedColumn generatedColumn() default @GeneratedColumn("?");
39+
DiscriminatorColumn discriminatorColumn() default @DiscriminatorColumn(name="?");
40+
Formula formula() default @Formula("?");
41+
JoinFormula joinFormula() default @JoinFormula("?");
42+
Where where() default @Where(clause = "?");
43+
Filters filters() default @Filters(value={@Filter(name="?")});
44+
FilterDefs filterDefs() default @FilterDefs(value=@FilterDef( name="?"));
45+
}

hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
import org.jboss.logging.Logger;
3939

40+
import static org.hibernate.cfg.AnnotationBinder.getOverridableAnnotation;
41+
4042
/**
4143
* Wrap state of an EJB3 @Column annotation
4244
* and build the Hibernate column mapping element
@@ -672,7 +674,7 @@ public static AnnotatedColumn[] buildColumnFromAnnotation(
672674
private void applyColumnDefault(PropertyData inferredData, int length) {
673675
final XProperty xProperty = inferredData.getProperty();
674676
if ( xProperty != null ) {
675-
ColumnDefault columnDefaultAnn = xProperty.getAnnotation( ColumnDefault.class );
677+
ColumnDefault columnDefaultAnn = getOverridableAnnotation( xProperty, ColumnDefault.class, context );
676678
if ( columnDefaultAnn != null ) {
677679
if (length!=1) {
678680
throw new MappingException("@ColumnDefault may only be applied to single-column mappings");
@@ -690,7 +692,7 @@ private void applyColumnDefault(PropertyData inferredData, int length) {
690692
private void applyGeneratedAs(PropertyData inferredData, int length) {
691693
final XProperty xProperty = inferredData.getProperty();
692694
if ( xProperty != null ) {
693-
GeneratedColumn generatedAnn = xProperty.getAnnotation( GeneratedColumn.class );
695+
GeneratedColumn generatedAnn = getOverridableAnnotation( xProperty, GeneratedColumn.class, context );
694696
if ( generatedAnn != null ) {
695697
if (length!=1) {
696698
throw new MappingException("@GeneratedColumn may only be applied to single-column mappings");

hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.lang.annotation.Annotation;
1010
import java.lang.reflect.InvocationTargetException;
1111
import java.lang.reflect.Member;
12+
import java.lang.reflect.Method;
1213
import java.util.ArrayList;
1314
import java.util.Arrays;
1415
import java.util.Collections;
@@ -47,6 +48,7 @@
4748
import org.hibernate.annotations.FilterDef;
4849
import org.hibernate.annotations.FilterDefs;
4950
import org.hibernate.annotations.Filters;
51+
import org.hibernate.annotations.ForDialect;
5052
import org.hibernate.annotations.ForeignKey;
5153
import org.hibernate.annotations.Formula;
5254
import org.hibernate.annotations.GenericGenerator;
@@ -104,6 +106,7 @@
104106
import org.hibernate.cfg.annotations.QueryBinder;
105107
import org.hibernate.cfg.annotations.TableBinder;
106108
import org.hibernate.cfg.internal.NullableDiscriminatorColumnSecondPass;
109+
import org.hibernate.dialect.Dialect;
107110
import org.hibernate.engine.OptimisticLockStyle;
108111
import org.hibernate.engine.spi.FilterDefinition;
109112
import org.hibernate.id.IdentifierGenerator;
@@ -632,15 +635,15 @@ else if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) {
632635

633636
entityBinder.setProxy( clazzToProcess.getAnnotation( Proxy.class ) );
634637
entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) );
635-
entityBinder.setWhere( clazzToProcess.getAnnotation( Where.class ) );
638+
entityBinder.setWhere( getOverridableAnnotation( clazzToProcess, Where.class, context ) );
636639
applyCacheSettings( entityBinder, clazzToProcess, context );
637640

638-
bindFilters( clazzToProcess, entityBinder, context );
641+
bindFiltersAndFilterDefs( clazzToProcess, entityBinder, context );
639642

640643
entityBinder.bindEntity();
641644

642645
if ( inheritanceState.hasTable() ) {
643-
Check checkAnn = clazzToProcess.getAnnotation( Check.class );
646+
Check checkAnn = getOverridableAnnotation( clazzToProcess, Check.class, context );
644647
String constraints = checkAnn == null
645648
? null
646649
: checkAnn.constraints();
@@ -842,6 +845,33 @@ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) {
842845
bindCallbacks( clazzToProcess, persistentClass, context );
843846
}
844847

848+
public static <T extends Annotation> T getOverridableAnnotation(
849+
XAnnotatedElement element,
850+
Class<T> annotationType,
851+
MetadataBuildingContext context) {
852+
Dialect dialect = context.getMetadataCollector().getDatabase().getDialect();
853+
for ( Annotation annotation: element.getAnnotations() ) {
854+
if (annotation instanceof ForDialect) {
855+
ForDialect forDialect = (ForDialect) annotation;
856+
if ( forDialect.dialect().isAssignableFrom( dialect.getClass() ) ) {
857+
for ( Method method: ForDialect.class.getDeclaredMethods() ) {
858+
if ( method.getReturnType().equals( annotationType ) ) {
859+
T result;
860+
try {
861+
result = (T) method.invoke( forDialect );
862+
if ( result.toString().indexOf('?')>0 ) break; //the "null" value
863+
return result;
864+
} catch (Exception e) {
865+
break;
866+
}
867+
}
868+
}
869+
}
870+
}
871+
}
872+
return element.getAnnotation( annotationType );
873+
}
874+
845875
private static void handleTypeDescriptorRegistrations(XAnnotatedElement annotatedElement, MetadataBuildingContext context) {
846876
final ManagedBeanRegistry managedBeanRegistry = context.getBootstrapContext()
847877
.getServiceRegistry()
@@ -958,9 +988,7 @@ private static AnnotatedDiscriminatorColumn processSingleTableDiscriminatorPrope
958988
? discAnn.discriminatorType()
959989
: DiscriminatorType.STRING;
960990

961-
DiscriminatorFormula discFormulaAnn = clazzToProcess.getAnnotation(
962-
DiscriminatorFormula.class
963-
);
991+
DiscriminatorFormula discFormulaAnn = getOverridableAnnotation( clazzToProcess, DiscriminatorFormula.class, context );
964992
if ( isRoot ) {
965993
discriminatorColumn = AnnotatedDiscriminatorColumn.buildDiscriminatorColumn(
966994
discriminatorType,
@@ -1402,18 +1430,18 @@ private static boolean isEntityClassType(XClass clazzToProcess, AnnotatedClassTy
14021430
* on the MappedSuperclass(s) in the inheritance hierarchy
14031431
*/
14041432

1405-
private static void bindFilters(
1433+
private static void bindFiltersAndFilterDefs(
14061434
XClass annotatedClass,
14071435
EntityBinder entityBinder,
14081436
MetadataBuildingContext context) {
14091437

1410-
bindFilters( annotatedClass, entityBinder );
1438+
bindFilters( annotatedClass, entityBinder, context );
14111439

14121440
XClass classToProcess = annotatedClass.getSuperclass();
14131441
while ( classToProcess != null ) {
14141442
AnnotatedClassType classType = context.getMetadataCollector().getClassType( classToProcess );
14151443
if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) {
1416-
bindFilters( classToProcess, entityBinder );
1444+
bindFilters( classToProcess, entityBinder, context );
14171445
}
14181446
else {
14191447
break;
@@ -1423,9 +1451,8 @@ private static void bindFilters(
14231451

14241452
}
14251453

1426-
private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder entityBinder) {
1427-
1428-
Filters filtersAnn = annotatedElement.getAnnotation( Filters.class );
1454+
private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder entityBinder, MetadataBuildingContext context) {
1455+
Filters filtersAnn = getOverridableAnnotation( annotatedElement, Filters.class, context );
14291456
if ( filtersAnn != null ) {
14301457
for ( Filter filter : filtersAnn.value() ) {
14311458
entityBinder.addFilter(filter);
@@ -1440,7 +1467,7 @@ private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder
14401467

14411468
private static void bindFilterDefs(XAnnotatedElement annotatedElement, MetadataBuildingContext context) {
14421469
FilterDef defAnn = annotatedElement.getAnnotation( FilterDef.class );
1443-
FilterDefs defsAnn = annotatedElement.getAnnotation( FilterDefs.class );
1470+
FilterDefs defsAnn = getOverridableAnnotation( annotatedElement, FilterDefs.class, context );
14441471
if ( defAnn != null ) {
14451472
bindFilterDef( defAnn, context );
14461473
}
@@ -2038,7 +2065,7 @@ else if ( property.isAnnotationPresent( OneToMany.class )
20382065
collectionBinder.setBatchSize( property.getAnnotation( BatchSize.class ) );
20392066

20402067
collectionBinder.setJpaOrderBy( property.getAnnotation( jakarta.persistence.OrderBy.class ) );
2041-
collectionBinder.setSqlOrderBy( property.getAnnotation( OrderBy.class ) );
2068+
collectionBinder.setSqlOrderBy( getOverridableAnnotation( property, OrderBy.class, context ) );
20422069

20432070
collectionBinder.setNaturalSort( property.getAnnotation( SortNatural.class ) );
20442071
collectionBinder.setComparatorSort( property.getAnnotation( SortComparator.class ) );
@@ -2064,7 +2091,7 @@ else if ( property.isAnnotationPresent( OneToMany.class )
20642091
Formula.class
20652092
) ) {
20662093
Column ann = property.getAnnotation( Column.class );
2067-
Formula formulaAnn = property.getAnnotation( Formula.class );
2094+
Formula formulaAnn = getOverridableAnnotation( property, Formula.class, context );
20682095
elementColumns = AnnotatedColumn.buildColumnFromAnnotation(
20692096
new Column[] { ann },
20702097
formulaAnn,

hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.hibernate.cfg.annotations.Nullability;
2929
import org.hibernate.internal.util.StringHelper;
3030

31+
import static org.hibernate.cfg.AnnotationBinder.getOverridableAnnotation;
32+
3133
/**
3234
* Do the initial discovery of columns metadata and apply defaults.
3335
* Also hosts some convenient methods related to column processing
@@ -249,7 +251,7 @@ else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) {
249251
}
250252

251253
if (property.isAnnotationPresent( JoinFormula.class)) {
252-
JoinFormula ann = property.getAnnotation( JoinFormula.class );
254+
JoinFormula ann = getOverridableAnnotation( property, JoinFormula.class, buildingContext );
253255
AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1];
254256
annotatedJoinColumns[0] = AnnotatedJoinColumn.buildJoinFormula(
255257
ann,

hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
import jakarta.persistence.OrderColumn;
132132

133133
import static jakarta.persistence.AccessType.PROPERTY;
134+
import static org.hibernate.cfg.AnnotationBinder.getOverridableAnnotation;
134135
import static org.hibernate.cfg.BinderHelper.toAliasEntityMap;
135136
import static org.hibernate.cfg.BinderHelper.toAliasTableMap;
136137

@@ -1171,7 +1172,7 @@ private void bindFilters(boolean hasAssociationTable) {
11711172
toAliasTableMap(simpleFilter.aliases()), toAliasEntityMap(simpleFilter.aliases()));
11721173
}
11731174
}
1174-
Filters filters = property.getAnnotation( Filters.class );
1175+
Filters filters = getOverridableAnnotation( property, Filters.class, buildingContext );
11751176
if ( filters != null ) {
11761177
for (Filter filter : filters.value()) {
11771178
if ( hasAssociationTable ) {
@@ -1233,12 +1234,12 @@ private void bindFilters(boolean hasAssociationTable) {
12331234
// for many-to-many e.g., @ManyToMany @Where(clause="...") public Set<Rating> getRatings();
12341235
String whereOnClassClause = null;
12351236
if ( useEntityWhereClauseForCollections && property.getElementClass() != null ) {
1236-
Where whereOnClass = property.getElementClass().getAnnotation( Where.class );
1237+
Where whereOnClass = getOverridableAnnotation( property.getElementClass(), Where.class, getBuildingContext() );
12371238
if ( whereOnClass != null ) {
12381239
whereOnClassClause = whereOnClass.clause();
12391240
}
12401241
}
1241-
Where whereOnCollection = property.getAnnotation( Where.class );
1242+
Where whereOnCollection = getOverridableAnnotation( property, Where.class, getBuildingContext() );
12421243
String whereOnCollectionClause = null;
12431244
if ( whereOnCollection != null ) {
12441245
whereOnCollectionClause = whereOnCollection.clause();

0 commit comments

Comments
 (0)