You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/09/30 15:20:08 UTC
(grails-core) 04/11: Fix DomainEventListener IntelliJ warnings
This is an automated email from the ASF dual-hosted git repository.
jdaugherty pushed a commit to branch test/document-datamapping-events
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit bb46bc9561f953560b540ef755bc14be051b03b3
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Fri Aug 14 10:44:29 2026 -0500
Fix DomainEventListener IntelliJ warnings
- entityEvents field made final (never reassigned)
- Removed ZERO_PARAMS constant (zero references anywhere in the repo)
- Parameterized raw ConnectionSourcesProvider/Class usages
- supportsEventType now null-safe: Spring 7's
SmartApplicationListener.supportsEventType declares its parameter
@Nullable, and this override would NPE via Class.isAssignableFrom(null)
- invokeEvent's ea.refresh() call is now guarded by the same ea != null
check already used earlier in the method, closing a latent NPE path
- Removed the two switch branches in onPersistenceEvent (SaveOrUpdate,
Validation) that were duplicates of the default branch
- Reordered each before/after method pair so the 2-arg overload holds
the real logic and is canonical; the 3-arg overload (whose event
parameter has been unused since the dead 1-arg-hook branch was
removed) is now @Deprecated, forwards to the 2-arg overload, and is
scheduled for removal in 9.0. onPersistenceEvent now calls the 2-arg
overloads directly instead of the newly-deprecated 3-arg ones.
Added tests for the deprecated overloads' delegation and the null
eventType case. Full suite, jacoco, and codeStyle all clean.
---
.../datastore/gorm/events/DomainEventListener.java | 123 ++++++++++++---------
.../gorm/events/DomainEventListenerSpec.groovy | 36 ++++++
2 files changed, 108 insertions(+), 51 deletions(-)
diff --git a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/events/DomainEventListener.java b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/events/DomainEventListener.java
index fca82d846f..75899037c9 100644
--- a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/events/DomainEventListener.java
+++ b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/events/DomainEventListener.java
@@ -58,10 +58,8 @@ import org.grails.datastore.mapping.model.config.GormProperties;
public class DomainEventListener extends AbstractPersistenceEventListener
implements MappingContext.Listener {
- private Map<PersistentEntity, Map<String, Method>> entityEvents = new ConcurrentHashMap<>();
+ private final Map<PersistentEntity, Map<String, Method>> entityEvents = new ConcurrentHashMap<>();
- @SuppressWarnings("rawtypes")
- public static final Class[] ZERO_PARAMS = {};
public static final String EVENT_BEFORE_INSERT = "beforeInsert";
private static final String EVENT_BEFORE_UPDATE = "beforeUpdate";
private static final String EVENT_BEFORE_DELETE = "beforeDelete";
@@ -84,15 +82,15 @@ public class DomainEventListener extends AbstractPersistenceEventListener
}
datastore.getMappingContext().addMappingContextListener(this);
- if (datastore instanceof ConnectionSourcesProvider) {
- autowireEntities = ((ConnectionSourcesProvider) datastore).getConnectionSources().getDefaultConnectionSource().getSettings().isAutowire();
+ if (datastore instanceof ConnectionSourcesProvider<?, ?>) {
+ autowireEntities = ((ConnectionSourcesProvider<?, ?>) datastore).getConnectionSources().getDefaultConnectionSource().getSettings().isAutowire();
}
else {
autowireEntities = false;
}
}
- protected DomainEventListener(ConnectionSourcesProvider connectionSourcesProvider, final MappingContext mappingContext) {
+ protected DomainEventListener(ConnectionSourcesProvider<?, ?> connectionSourcesProvider, final MappingContext mappingContext) {
super(null);
for (PersistentEntity entity : mappingContext.getPersistentEntities()) {
@@ -106,54 +104,41 @@ public class DomainEventListener extends AbstractPersistenceEventListener
protected void onPersistenceEvent(final AbstractPersistenceEvent event) {
switch (event.getEventType()) {
case PreInsert:
- if (!beforeInsert(event.getEntity(), event.getEntityAccess(), (PreInsertEvent) event)) {
+ if (!beforeInsert(event.getEntity(), event.getEntityAccess())) {
event.cancel();
}
break;
case PostInsert:
- afterInsert(event.getEntity(), event.getEntityAccess(), (PostInsertEvent) event);
+ afterInsert(event.getEntity(), event.getEntityAccess());
break;
case PreUpdate:
- if (!beforeUpdate(event.getEntity(), event.getEntityAccess(), (PreUpdateEvent) event)) {
+ if (!beforeUpdate(event.getEntity(), event.getEntityAccess())) {
event.cancel();
}
break;
case PostUpdate:
- afterUpdate(event.getEntity(), event.getEntityAccess(), (PostUpdateEvent) event);
+ afterUpdate(event.getEntity(), event.getEntityAccess());
break;
case PreDelete:
- if (!beforeDelete(event.getEntity(), event.getEntityAccess(), (PreDeleteEvent) event)) {
+ if (!beforeDelete(event.getEntity(), event.getEntityAccess())) {
event.cancel();
}
break;
case PostDelete:
- afterDelete(event.getEntity(), event.getEntityAccess(), (PostDeleteEvent) event);
+ afterDelete(event.getEntity(), event.getEntityAccess());
break;
case PreLoad:
- beforeLoad(event.getEntity(), event.getEntityAccess(), (PreLoadEvent) event);
+ beforeLoad(event.getEntity(), event.getEntityAccess());
break;
case PostLoad:
- afterLoad(event.getEntity(), event.getEntityAccess(), (PostLoadEvent) event);
- break;
- case SaveOrUpdate:
- break;
- case Validation:
+ afterLoad(event.getEntity(), event.getEntityAccess());
break;
default:
break;
}
}
- /**
- * @deprecated Use {@link #beforeInsert(org.grails.datastore.mapping.model.PersistentEntity, org.grails.datastore.mapping.engine.EntityAccess, org.grails.datastore.mapping.engine.event.PreInsertEvent)} instead
- */
- @Deprecated
public boolean beforeInsert(final PersistentEntity entity, final EntityAccess ea) {
- return beforeInsert(entity, ea, null);
- }
-
- public boolean beforeInsert(final PersistentEntity entity, final EntityAccess ea, PreInsertEvent event) {
-
if (entity.isVersioned()) {
try {
setVersion(ea);
@@ -166,8 +151,16 @@ public class DomainEventListener extends AbstractPersistenceEventListener
return invokeEvent(EVENT_BEFORE_INSERT, entity, ea);
}
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #beforeInsert(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public boolean beforeInsert(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PreInsertEvent event) {
+ return beforeInsert(entity, ea);
+ }
+
protected void setVersion(final EntityAccess ea) {
- final Class versionType = ea.getPersistentEntity().getVersion().getType();
+ final Class<?> versionType = ea.getPersistentEntity().getVersion().getType();
if (Number.class.isAssignableFrom(versionType)) {
ea.setProperty(GormProperties.VERSION, 0);
}
@@ -183,43 +176,63 @@ public class DomainEventListener extends AbstractPersistenceEventListener
return invokeEvent(EVENT_BEFORE_UPDATE, entity, ea);
}
- public boolean beforeUpdate(final PersistentEntity entity, final EntityAccess ea, PreUpdateEvent event) {
- return invokeEvent(EVENT_BEFORE_UPDATE, entity, ea);
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #beforeUpdate(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public boolean beforeUpdate(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PreUpdateEvent event) {
+ return beforeUpdate(entity, ea);
}
public boolean beforeDelete(final PersistentEntity entity, final EntityAccess ea) {
return invokeEvent(EVENT_BEFORE_DELETE, entity, ea);
}
- public boolean beforeDelete(final PersistentEntity entity, final EntityAccess ea, PreDeleteEvent event) {
- return invokeEvent(EVENT_BEFORE_DELETE, entity, ea);
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #beforeDelete(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public boolean beforeDelete(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PreDeleteEvent event) {
+ return beforeDelete(entity, ea);
}
public void beforeLoad(final PersistentEntity entity, final EntityAccess ea) {
- beforeLoad(entity, ea, null);
- }
-
- public void beforeLoad(final PersistentEntity entity, final EntityAccess ea, PreLoadEvent event) {
invokeEvent(EVENT_BEFORE_LOAD, entity, ea);
}
- public void afterDelete(final PersistentEntity entity, final EntityAccess ea) {
- afterDelete(entity, ea, null);
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #beforeLoad(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public void beforeLoad(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PreLoadEvent event) {
+ beforeLoad(entity, ea);
}
- public void afterDelete(final PersistentEntity entity, final EntityAccess ea, PostDeleteEvent event) {
+ public void afterDelete(final PersistentEntity entity, final EntityAccess ea) {
invokeEvent(EVENT_AFTER_DELETE, entity, ea);
}
- public void afterInsert(final PersistentEntity entity, final EntityAccess ea) {
- afterInsert(entity, ea, null);
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #afterDelete(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public void afterDelete(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PostDeleteEvent event) {
+ afterDelete(entity, ea);
}
- public void afterInsert(final PersistentEntity entity, final EntityAccess ea, PostInsertEvent event) {
+ public void afterInsert(final PersistentEntity entity, final EntityAccess ea) {
activateDirtyChecking(ea);
invokeEvent(EVENT_AFTER_INSERT, entity, ea);
}
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #afterInsert(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public void afterInsert(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PostInsertEvent event) {
+ afterInsert(entity, ea);
+ }
+
private void activateDirtyChecking(EntityAccess ea) {
Object e = ea.getEntity();
if (e instanceof DirtyCheckable) {
@@ -228,19 +241,19 @@ public class DomainEventListener extends AbstractPersistenceEventListener
}
public void afterUpdate(final PersistentEntity entity, final EntityAccess ea) {
- afterUpdate(entity, ea, null);
- }
-
- public void afterUpdate(final PersistentEntity entity, final EntityAccess ea, PostUpdateEvent event) {
activateDirtyChecking(ea); // reset dirty checking
invokeEvent(EVENT_AFTER_UPDATE, entity, ea);
}
- public void afterLoad(final PersistentEntity entity, final EntityAccess ea) {
- afterLoad(entity, ea, null);
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #afterUpdate(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public void afterUpdate(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PostUpdateEvent event) {
+ afterUpdate(entity, ea);
}
- public void afterLoad(final PersistentEntity entity, final EntityAccess ea, PostLoadEvent event) {
+ public void afterLoad(final PersistentEntity entity, final EntityAccess ea) {
activateDirtyChecking(ea);
if (autowireEntities || (entity != null && entity.getMapping().getMappedForm().isAutowire())) {
autowireBeanProperties(ea.getEntity());
@@ -248,6 +261,14 @@ public class DomainEventListener extends AbstractPersistenceEventListener
invokeEvent(EVENT_AFTER_LOAD, entity, ea);
}
+ /**
+ * @deprecated the {@code event} parameter is unused; use {@link #afterLoad(PersistentEntity, EntityAccess)} instead. Scheduled for removal in 9.0.
+ */
+ @Deprecated
+ public void afterLoad(final PersistentEntity entity, final EntityAccess ea, @SuppressWarnings("unused") PostLoadEvent event) {
+ afterLoad(entity, ea);
+ }
+
protected void autowireBeanProperties(final Object entity) {
ConfigurableApplicationContext applicationContext = datastore.getApplicationContext();
if (applicationContext != null) {
@@ -271,7 +292,7 @@ public class DomainEventListener extends AbstractPersistenceEventListener
* java.lang.Class)
*/
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
- return AbstractPersistenceEvent.class.isAssignableFrom(eventType);
+ return eventType != null && AbstractPersistenceEvent.class.isAssignableFrom(eventType);
}
private boolean invokeEvent(String eventName, PersistentEntity entity, EntityAccess ea) {
@@ -294,7 +315,7 @@ public class DomainEventListener extends AbstractPersistenceEventListener
}
boolean booleanResult = (result instanceof Boolean) ? (Boolean) result : true;
- if (booleanResult && REFRESH_EVENTS.contains(eventName)) {
+ if (ea != null && booleanResult && REFRESH_EVENTS.contains(eventName)) {
ea.refresh();
}
return booleanResult;
diff --git a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/events/DomainEventListenerSpec.groovy b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/events/DomainEventListenerSpec.groovy
index 319f27100c..01e6f61ee8 100644
--- a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/events/DomainEventListenerSpec.groovy
+++ b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/events/DomainEventListenerSpec.groovy
@@ -123,6 +123,14 @@ class DomainEventListenerSpec extends Specification {
!listener.supportsEventType(PayloadApplicationEvent)
}
+ void "supportsEventType rejects a null event type rather than throwing, matching SmartApplicationListener's nullable contract"() {
+ given:
+ DomainEventListener listener = new DomainEventListener(plainDatastore(Stub(MappingContext) { getPersistentEntities() >> [] }))
+
+ expect:
+ !listener.supportsEventType(null)
+ }
+
void "beforeInsert sets an initial numeric version to 0 when the entity is versioned"() {
given:
PersistentEntity entity = entityFor(NoHooksDomain, true, Long)
@@ -248,6 +256,34 @@ class DomainEventListenerSpec extends Specification {
'afterLoad' | 'afterLoad'
}
+ @Unroll
+ @SuppressWarnings('deprecation')
+ void "the deprecated 3-arg #methodName(entity, ea, event) overload delegates to the 2-arg overload, ignoring the event argument"() {
+ given:
+ RecordingDomain domain = new RecordingDomain()
+ PersistentEntity entity = entityFor(RecordingDomain)
+ DomainEventListener listener = new DomainEventListener(plainDatastore(Stub(MappingContext) { getPersistentEntities() >> [] }))
+ listener.persistentEntityAdded(entity)
+ EntityAccess ea = Stub(EntityAccess) { getEntity() >> domain }
+
+ when:
+ listener."$methodName"(entity, ea, null)
+
+ then:
+ domain.invoked == [hookName]
+
+ where:
+ methodName | hookName
+ 'beforeInsert' | 'beforeInsert'
+ 'beforeUpdate' | 'beforeUpdate'
+ 'beforeDelete' | 'beforeDelete'
+ 'beforeLoad' | 'beforeLoad'
+ 'afterInsert' | 'afterInsert'
+ 'afterUpdate' | 'afterUpdate'
+ 'afterDelete' | 'afterDelete'
+ 'afterLoad' | 'afterLoad'
+ }
+
void "afterInsert activates dirty checking on entities that implement DirtyCheckable"() {
given:
DirtyCheckableDomain domain = Spy(DirtyCheckableDomain)