hibernate/hibernate-orm · error · ModelsException

Mapping for entity listener specified no callback methods: %

Error message

Mapping for entity listener specified no callback methods: %s

What it means

While collecting global registrations from mapping files, Hibernate builds a LifecycleEventHandler from each declared entity-listener class and its XML callback definitions. If neither source yields any callback method - the class carries no JPA callback annotations and the XML declares none - registration fails with a ModelsException naming the listener class.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java:742

			final var lifecycleEventHandler = LifecycleEventHandler.from(
						JpaEventListenerStyle.LISTENER,
						listenerClassDetails,
						jaxbEntityListener,
						modelsContext,
						LifecycleEventHandler.hasExplicitXmlCallbackMappings( jaxbEntityListener )
			);
			final var persistenceUnitLifecycleEventHandler =
					PersistenceUnitLifecycleEventHandler.from( listenerClassDetails, jaxbEntityListener );

			if ( lifecycleEventHandler.hasCallbackMethods() ) {
				addJpaEventListener( lifecycleEventHandler );
			}
			if ( persistenceUnitLifecycleEventHandler.hasCallbackMethods() ) {
				addPersistenceUnitLifecycleEventHandler( persistenceUnitLifecycleEventHandler );
			}
			if ( !lifecycleEventHandler.hasCallbackMethods()
					&& !persistenceUnitLifecycleEventHandler.hasCallbackMethods() ) {
				throw new ModelsException( "Mapping for entity listener specified no callback methods: "
						+ listenerClassDetails.getClassName() );
			}
		} );
	}

	public void addJpaEventListener(LifecycleEventHandler listener) {
		if ( lifecycleEventHandlers == null ) {
			lifecycleEventHandlers = new ArrayList<>();
		}

		lifecycleEventHandlers.add( listener );
	}

	public void addTargetedJpaEventListener(ClassDetails listenerClassDetails) {
		final var persistenceUnitHandler = PersistenceUnitLifecycleEventHandler.from( listenerClassDetails );
		if ( persistenceUnitHandler.hasCallbackMethods() ) {
			addPersistenceUnitLifecycleEventHandler( persistenceUnitHandler );
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Add at least one JPA callback to the listener, e.g. @PrePersist void onPrePersist(Object entity) {...}, or declare the callbacks inside the <entity-listener> element in XML
  2. Verify the annotation import is jakarta.persistence (or javax.persistence on older stacks) - lookalike packages are silently ignored
  3. If the class is not meant to observe entity lifecycle, remove its registration

Example fix

// before - AuditListener registered in mapping.xml but has no callbacks
public class AuditListener { }

// after
public class AuditListener {
    @PrePersist
    void onPrePersist(Object entity) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight in tests: every registered listener must expose at least one JPA callback
static final List<Class<? extends Annotation>> CB = List.of(
        jakarta.persistence.PrePersist.class, jakarta.persistence.PostPersist.class,
        jakarta.persistence.PreUpdate.class, jakarta.persistence.PostUpdate.class,
        jakarta.persistence.PreRemove.class, jakarta.persistence.PostRemove.class,
        jakarta.persistence.PostLoad.class);
static boolean hasCallback(Class<?> listener) {
    return java.util.Arrays.stream(listener.getDeclaredMethods())
            .flatMap(m -> java.util.Arrays.stream(m.getAnnotations()))
            .anyMatch(a -> CB.contains(a.annotationType()));
}
// assertEquals over the set of listeners registered in orm.xml before bootstrap

Try / catch

catch (org.hibernate.models.ModelsException e) during bootstrap: the message names the listener class - open it and add a JPA callback annotation or declare the callback in XML inside <entity-listener>

Prevention

When it happens

Trigger: A mapping file declares <entity-listener class='com.acme.AuditListener'/> (directly or under <entity-listeners>) but AuditListener contains no @PrePersist/@PostPersist/@PreUpdate/@PostUpdate/@PreRemove/@PostRemove/@PostLoad methods and the XML element declares no <pre-persist/>-style callbacks inside it.

Common situations: Listener classes using framework annotations (e.g. Spring @EventListener) or interceptor interfaces instead of JPA callbacks; leftovers after moving callbacks out; registering a listener that exists only for persistence-unit lifecycle events.

Related errors


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