Skip to content

Commit f091beb

Browse files
committed
Improve lambda-based EntityCallback detection.
In case an EntityCallback is declared as lambda expression, the JVM does not expose any generics information about the target entity type the callback shall be applied to. This commit changes the callback lookup and processing so that in case the generics information is not detectable on the type, we fall back to the BeanDefinition's resolvable type (fed by the factory method's return type which carries the necessary reflection information). That generics information is then kept in the newly introduce EntityCallbackAdapter and the code inspecting the actual entity type for matches then uses the resolvable type held in that. Also, the actual callback invocation is done on the adapter's delegate. Removed the ability of the discoverer to register EntityCallbacks by bean name as that was not used in the public API at all and it avoids duplicating the bean definition type detection. A couple of minor additional cleanups (records for cache key, methods static where possible and with lower visibility etc.) Fixes #2812.
1 parent ba2e0f9 commit f091beb

File tree

5 files changed

+139
-208
lines changed

5 files changed

+139
-208
lines changed

src/main/java/org/springframework/data/mapping/callback/DefaultEntityCallbacks.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import org.apache.commons.logging.Log;
2323
import org.apache.commons.logging.LogFactory;
24-
2524
import org.springframework.beans.factory.BeanFactory;
2625
import org.springframework.core.ResolvableType;
2726
import org.springframework.util.Assert;
@@ -35,6 +34,7 @@
3534
*
3635
* @author Mark Paluch
3736
* @author Christoph Strobl
37+
* @author Oliver Drotbohm
3838
* @since 2.2
3939
*/
4040
class DefaultEntityCallbacks implements EntityCallbacks {
@@ -93,7 +93,8 @@ public void addEntityCallback(EntityCallback<?> callback) {
9393
this.callbackDiscoverer.addEntityCallback(callback);
9494
}
9595

96-
static class SimpleEntityCallbackInvoker implements org.springframework.data.mapping.callback.EntityCallbackInvoker {
96+
static class SimpleEntityCallbackInvoker
97+
implements org.springframework.data.mapping.callback.EntityCallbackInvoker {
9798

9899
@Override
99100
public <T> T invokeCallback(EntityCallback<T> callback, T entity,
@@ -108,11 +109,12 @@ public <T> T invokeCallback(EntityCallback<T> callback, T entity,
108109
}
109110

110111
throw new IllegalArgumentException(
111-
String.format("Callback invocation on %s returned null value for %s", callback.getClass(), entity));
112+
"Callback invocation on %s returned null value for %s".formatted(callback.getClass(), entity));
112113

113114
} catch (IllegalArgumentException | ClassCastException ex) {
114115

115116
String msg = ex.getMessage();
117+
116118
if (msg == null || EntityCallbackInvoker.matchesClassCastMessage(msg, entity.getClass())) {
117119

118120
// Possibly a lambda-defined listener which we could not resolve the generic event type for

src/main/java/org/springframework/data/mapping/callback/DefaultReactiveEntityCallbacks.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.apache.commons.logging.Log;
2525
import org.apache.commons.logging.LogFactory;
2626
import org.reactivestreams.Publisher;
27-
2827
import org.springframework.beans.factory.BeanFactory;
2928
import org.springframework.core.ResolvableType;
3029
import org.springframework.util.Assert;
@@ -38,6 +37,7 @@
3837
* @author Mark Paluch
3938
* @author Christoph Strobl
4039
* @author Michael J. Simons
40+
* @author Oliver Drotbohm
4141
*/
4242
class DefaultReactiveEntityCallbacks implements ReactiveEntityCallbacks {
4343

@@ -63,11 +63,13 @@ class DefaultReactiveEntityCallbacks implements ReactiveEntityCallbacks {
6363
}
6464

6565
@Override
66+
@SuppressWarnings("unchecked")
6667
public <T> Mono<T> callback(Class<? extends EntityCallback> callbackType, T entity, Object... args) {
6768

6869
Assert.notNull(entity, "Entity must not be null");
6970

70-
Class<T> entityType = (Class<T>) (entity != null ? ClassUtils.getUserClass(entity.getClass())
71+
Class<T> entityType = (Class<T>) (entity != null
72+
? ClassUtils.getUserClass(entity.getClass())
7173
: callbackDiscoverer.resolveDeclaredEntityType(callbackType).getRawClass());
7274

7375
Method callbackMethod = callbackMethodCache.computeIfAbsent(callbackType, it -> {
@@ -112,7 +114,7 @@ public <T> Mono<T> invokeCallback(EntityCallback<T> callback, T entity,
112114
}
113115

114116
throw new IllegalArgumentException(
115-
String.format("Callback invocation on %s returned null value for %s", callback.getClass(), entity));
117+
"Callback invocation on %s returned null value for %s".formatted(callback.getClass(), entity));
116118
} catch (IllegalArgumentException | ClassCastException ex) {
117119

118120
String msg = ex.getMessage();

0 commit comments

Comments
 (0)