Skip to content

Commit f7ea1b5

Browse files
committed
clean up the type checking of TypeBinders and AttributeBinders
and produce better error messages
1 parent e558872 commit f7ea1b5

File tree

4 files changed

+124
-52
lines changed

4 files changed

+124
-52
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.model.internal;
6+
7+
import org.hibernate.AnnotationException;
8+
import org.hibernate.annotations.AttributeBinderType;
9+
import org.hibernate.annotations.TypeBinderType;
10+
import org.hibernate.binder.AttributeBinder;
11+
import org.hibernate.binder.TypeBinder;
12+
import org.hibernate.boot.spi.MetadataBuildingContext;
13+
import org.hibernate.mapping.Component;
14+
import org.hibernate.mapping.PersistentClass;
15+
import org.hibernate.mapping.Property;
16+
17+
import java.lang.annotation.Annotation;
18+
19+
import static org.hibernate.internal.util.GenericsHelper.typeArguments;
20+
21+
/**
22+
* @author Gavin King
23+
* @since 7.3
24+
*/
25+
public class Binders {
26+
static <A extends Annotation> void callTypeBinder(
27+
Annotation annotation, Class<A> annotationType,
28+
Component embeddable,
29+
MetadataBuildingContext context) {
30+
try {
31+
typeBinder( annotationType )
32+
.bind( annotationType.cast( annotation ),
33+
context, embeddable );
34+
}
35+
catch (Exception e) {
36+
throw new AnnotationException(
37+
"Error processing @TypeBinderType annotation '%s' for embeddable type '%s'"
38+
.formatted( annotation, embeddable.getComponentClassName() ), e );
39+
}
40+
}
41+
42+
static <A extends Annotation> void callTypeBinder(
43+
Annotation annotation, Class<A> annotationType,
44+
PersistentClass entity,
45+
MetadataBuildingContext context) {
46+
try {
47+
typeBinder( annotationType )
48+
.bind( annotationType.cast( annotation ),
49+
context, entity );
50+
}
51+
catch (Exception e) {
52+
throw new AnnotationException(
53+
"Error processing @TypeBinderType annotation '%s' for entity type '%s'"
54+
.formatted( annotation, entity.getClassName() ), e );
55+
}
56+
}
57+
58+
static <A extends Annotation> void callPropertyBinder(
59+
Annotation annotation, Class<A> annotationType,
60+
PersistentClass entity, Property property,
61+
MetadataBuildingContext context) {
62+
try {
63+
propertyBinder( annotationType )
64+
.bind( annotationType.cast( annotation ),
65+
context, entity, property );
66+
}
67+
catch (Exception e) {
68+
throw new AnnotationException(
69+
"error processing @AttributeBinderType annotation '%s' for attribute '%s' of entity type '%s'"
70+
.formatted( annotation, property.getName(), entity.getClassName() ), e );
71+
}
72+
}
73+
74+
private static <A extends Annotation> TypeBinder<A> typeBinder(Class<A> annotationType)
75+
throws Exception {
76+
final var binderType =
77+
annotationType.getAnnotation( TypeBinderType.class )
78+
.binder();
79+
checkImplementedTypeArgument( annotationType, binderType, TypeBinder.class );
80+
@SuppressWarnings("unchecked") // Safe, we just checked
81+
final var castBinderType = (Class<? extends TypeBinder<A>>) binderType;
82+
return castBinderType.getDeclaredConstructor().newInstance();
83+
}
84+
85+
private static <A extends Annotation> AttributeBinder<A> propertyBinder(Class<A> annotationType)
86+
throws Exception {
87+
final var binderType =
88+
annotationType.getAnnotation( AttributeBinderType.class )
89+
.binder();
90+
checkImplementedTypeArgument( annotationType, binderType, PropertyBinder.class );
91+
@SuppressWarnings("unchecked") // Safe, we just checked
92+
final var castBinderType = (Class<? extends AttributeBinder<A>>) binderType;
93+
return castBinderType.getDeclaredConstructor().newInstance();
94+
}
95+
96+
private static void checkImplementedTypeArgument(
97+
Class<? extends Annotation> annotationType,
98+
Class<?> binderType, Class<?> implementedType) {
99+
final var args = typeArguments( implementedType, binderType );
100+
if ( args.length == 1 ) {
101+
final var requiredAnnotationType = args[0];
102+
if ( annotationType != requiredAnnotationType ) {
103+
throw new AnnotationException(
104+
"Wrong kind of binder for annotation type:"
105+
+ " '%s' does not accept an annotation of type '%s'"
106+
.formatted( binderType.getTypeName(),
107+
annotationType.getTypeName() )
108+
);
109+
}
110+
}
111+
}
112+
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.hibernate.annotations.EmbeddedColumnNaming;
2626
import org.hibernate.annotations.Instantiator;
2727
import org.hibernate.annotations.TypeBinderType;
28-
import org.hibernate.binder.TypeBinder;
2928
import org.hibernate.boot.spi.AccessType;
3029
import org.hibernate.boot.spi.MetadataBuildingContext;
3130
import org.hibernate.boot.spi.PropertyData;
@@ -65,6 +64,7 @@
6564
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
6665
import static org.hibernate.boot.model.internal.BinderHelper.getRelativePath;
6766
import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation;
67+
import static org.hibernate.boot.model.internal.Binders.callTypeBinder;
6868
import static org.hibernate.boot.model.internal.ComponentPropertyHolder.applyExplicitTableName;
6969
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
7070
import static org.hibernate.boot.model.internal.GeneratorBinder.createIdGeneratorsFromGeneratorAnnotations;
@@ -316,17 +316,7 @@ private static void callTypeBinders(Component embeddable, MetadataBuildingContex
316316
.getMetaAnnotated( TypeBinderType.class,
317317
context.getBootstrapContext().getModelsContext() );
318318
for ( var metaAnnotated : metaAnnotatedAnnotations ) {
319-
final var binderType = metaAnnotated.annotationType().getAnnotation( TypeBinderType.class );
320-
try {
321-
//noinspection rawtypes
322-
final TypeBinder binder = binderType.binder().getDeclaredConstructor().newInstance();
323-
//noinspection unchecked
324-
binder.bind( metaAnnotated, context, embeddable );
325-
}
326-
catch (Exception e) {
327-
throw new AnnotationException(
328-
"error processing @TypeBinderType annotation '" + metaAnnotated + "'", e );
329-
}
319+
callTypeBinder( metaAnnotated, metaAnnotated.annotationType(), embeddable, context );
330320
}
331321
}
332322

hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
import org.hibernate.annotations.Synchronize;
6464
import org.hibernate.annotations.TypeBinderType;
6565
import org.hibernate.annotations.View;
66-
import org.hibernate.binder.TypeBinder;
6766
import org.hibernate.boot.model.NamedEntityGraphDefinition;
6867
import org.hibernate.boot.model.internal.InheritanceState.ElementsToProcess;
6968
import org.hibernate.boot.model.naming.EntityNaming;
@@ -134,6 +133,7 @@
134133
import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation;
135134
import static org.hibernate.boot.model.internal.BinderHelper.toAliasEntityMap;
136135
import static org.hibernate.boot.model.internal.BinderHelper.toAliasTableMap;
136+
import static org.hibernate.boot.model.internal.Binders.callTypeBinder;
137137
import static org.hibernate.boot.model.internal.ClassPropertyHolder.setType;
138138
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
139139
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverrideAnnotation;
@@ -383,23 +383,7 @@ private void addCheckToEntity(Check check) {
383383

384384
private void callTypeBinders(PersistentClass persistentClass) {
385385
for ( var metaAnnotated : annotatedClass.getMetaAnnotated( TypeBinderType.class, modelsContext() ) ) {
386-
applyTypeBinder( metaAnnotated, persistentClass );
387-
}
388-
}
389-
390-
private void applyTypeBinder(Annotation containingAnnotation, PersistentClass persistentClass) {
391-
final var binderClass =
392-
containingAnnotation.annotationType()
393-
.getAnnotation( TypeBinderType.class )
394-
.binder();
395-
try {
396-
//noinspection rawtypes
397-
final TypeBinder binder = binderClass.getConstructor().newInstance();
398-
//noinspection unchecked
399-
binder.bind( containingAnnotation, context, persistentClass );
400-
}
401-
catch ( Exception e ) {
402-
throw new AnnotationException( "error processing @TypeBinderType annotation '" + containingAnnotation + "'", e );
386+
callTypeBinder( metaAnnotated, metaAnnotated.annotationType(), persistentClass, context );
403387
}
404388
}
405389

hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.hibernate.annotations.NaturalId;
4242
import org.hibernate.annotations.OptimisticLock;
4343
import org.hibernate.annotations.Parent;
44-
import org.hibernate.binder.AttributeBinder;
4544
import org.hibernate.boot.spi.AccessType;
4645
import org.hibernate.boot.spi.MetadataBuildingContext;
4746
import org.hibernate.boot.spi.PropertyData;
@@ -81,6 +80,7 @@
8180
import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull;
8281
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
8382
import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation;
83+
import static org.hibernate.boot.model.internal.Binders.callPropertyBinder;
8484
import static org.hibernate.boot.model.internal.ClassPropertyHolder.handleGenericComponentProperty;
8585
import static org.hibernate.boot.model.internal.ClassPropertyHolder.prepareActualProperty;
8686
import static org.hibernate.boot.model.internal.CollectionBinder.bindCollection;
@@ -303,30 +303,16 @@ private boolean autoApplyConverters() {
303303
&& !memberDetails.hasDirectAnnotationUsage( Temporal.class );
304304
}
305305

306-
@SuppressWarnings({"rawtypes", "unchecked"})
307306
private void callAttributeBinders(Property property, Map<String, PersistentClass> persistentClasses) {
308307
final var metaAnnotatedTargets =
309308
memberDetails.getMetaAnnotated( AttributeBinderType.class, getSourceModelContext() );
310-
final var descriptorRegistry = getSourceModelContext().getAnnotationDescriptorRegistry();
311-
for ( int i = 0; i < metaAnnotatedTargets.size(); i++ ) {
312-
final Annotation metaAnnotatedTarget = metaAnnotatedTargets.get( i );
313-
final var metaAnnotatedDescriptor =
314-
descriptorRegistry.getDescriptor( metaAnnotatedTarget.annotationType() );
315-
final var binderTypeAnn =
316-
metaAnnotatedDescriptor.getDirectAnnotationUsage( AttributeBinderType.class );
317-
try {
318-
final AttributeBinder binder = binderTypeAnn.binder().getConstructor().newInstance();
319-
final var persistentClass =
320-
entityBinder != null
321-
? entityBinder.getPersistentClass()
322-
: persistentClasses.get( holder.getEntityName() );
323-
binder.bind( metaAnnotatedTarget, buildingContext, persistentClass, property );
324-
}
325-
catch ( Exception e ) {
326-
throw new AnnotationException( "error processing @AttributeBinderType annotation '"
327-
+ metaAnnotatedDescriptor.getAnnotationType().getName() + "' for property '"
328-
+ qualify( holder.getPath(), name ) + "'", e );
329-
}
309+
for ( final var metaAnnotatedTarget : metaAnnotatedTargets ) {
310+
final var annotationType = metaAnnotatedTarget.annotationType();
311+
final var persistentClass =
312+
entityBinder != null
313+
? entityBinder.getPersistentClass()
314+
: persistentClasses.get( holder.getEntityName() );
315+
callPropertyBinder( metaAnnotatedTarget, annotationType, persistentClass, property, buildingContext );
330316
}
331317
}
332318

0 commit comments

Comments
 (0)