hibernate/hibernate-orm · error · AnnotationException

Wrong kind of binder for annotation type: '%s' does not acce

Error message

Wrong kind of binder for annotation type: '%s' does not accept an annotation of type '%s'

What it means

A custom binder must implement TypeBinder<A> or AttributeBinder<A> parameterized with exactly the annotation type it is registered on via @TypeBinderType/@AttributeBinderType. Binders.checkImplementedTypeArgument resolves the binder's implemented type argument at boot and throws this AnnotationException when it differs from the annotated annotation type. This fails fast instead of letting the binder receive a wrong-typed annotation and crash later.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/Binders.java:103

	private static <A extends Annotation> AttributeBinder<A> propertyBinder(Class<A> annotationType)
					throws Exception {
		final var binderType =
				annotationType.getAnnotation( AttributeBinderType.class )
						.binder();
		checkImplementedTypeArgument( annotationType, binderType, PropertyBinder.class );
		@SuppressWarnings("unchecked") // Safe, we just checked
		final var castBinderType = (Class<? extends AttributeBinder<A>>) binderType;
		return castBinderType.getDeclaredConstructor().newInstance();
	}

	private static void checkImplementedTypeArgument(
			Class<? extends Annotation> annotationType,
			Class<?> binderType, Class<?> implementedType) {
		final var args = typeArguments( implementedType, binderType );
		if ( args.length == 1 ) {
			final var requiredAnnotationType = args[0];
			if ( annotationType != requiredAnnotationType ) {
				throw new AnnotationException(
						"Wrong kind of binder for annotation type:"
						+ " '%s' does not accept an annotation of type '%s'"
								.formatted( binderType.getTypeName(),
										annotationType.getTypeName() )
				);
			}
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the binder's generic parameter to the annotation it processes: class MyBinder implements AttributeBinder<MyAnn>
  2. If one logic must serve several annotations, write one thin binder class per annotation and delegate to shared code
  3. Add a unit test that reflects the binder's ParameterizedType argument and asserts it equals the annotation class, so this fails at test time not boot time

Example fix

// before
@AttributeBinderType(binder = MyAnnBinder.class)
public @interface MyAnn {}

public class MyAnnBinder implements AttributeBinder<SomeOtherAnn> { ... }
// boot fails: MyAnnBinder does not accept an annotation of type MyAnn

// after
public class MyAnnBinder implements AttributeBinder<MyAnn> { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Unit-test every binder's generic argument against its annotation before boot
static void checkBinderMatchesAnnotation(Class<? extends Annotation> annotationType,
                                         Class<?> binderClass) {
    for ( Type t : binderClass.getGenericInterfaces() ) {
        if ( t instanceof ParameterizedType p
                && ( p.getRawType() == TypeBinder.class
                     || p.getRawType() == AttributeBinder.class ) ) {
            Class<?> arg = (Class<?>) p.getActualTypeArguments()[0];
            if ( arg != annotationType ) {
                throw new IllegalStateException( binderClass.getName()
                    + " binds " + arg.getName() + " but is registered on "
                    + annotationType.getName() );
            }
        }
    }
}

Prevention

When it happens

Trigger: class MyBinder implements AttributeBinder<SomeOtherAnn> is referenced from @AttributeBinderType(binder = MyBinder.class) on annotation type MyAnn. During binder lookup, typeArguments(TypeBinder/AttributeBinder, binderType) returns one argument, args[0] != annotationType, and the exception fires with both type names.

Common situations: Copy-pasting a binder from another custom annotation without updating the generic parameter; renaming the annotation class but not the binder's type argument; registering a generic/reusable binder on multiple annotation types without subclasses per annotation.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/143036a684e46cb1. Report an issue: GitHub.