Fix too restrictive entity callback matching.

We now properly support generic entity callbacks defined via lambda declarations.

Fixes #2822.
This commit is contained in:
Oliver Drotbohm
2023-05-02 20:54:49 +02:00
parent cac1c211ef
commit 979e0f401b
2 changed files with 32 additions and 15 deletions

View File

@@ -33,9 +33,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -291,12 +289,9 @@ class EntityCallbackDiscoverer {
static boolean supportsEvent(EntityCallback<?> callback, ResolvableType entityType,
ResolvableType callbackType) {
ResolvableType callbackInstanceType = callback instanceof EntityCallbackAdapter<?> provider
? provider.getResolvableType()
: ResolvableType.forInstance(callback);
return supportsEvent(callbackInstanceType, entityType)
&& callbackType.isAssignableFrom(callbackInstanceType);
return callback instanceof EntityCallbackAdapter<?> provider
? provider.supports(callbackType, entityType)
: callbackType.isInstance(callback) && supportsEvent(ResolvableType.forInstance(callback), entityType);
}
/**
@@ -346,12 +341,10 @@ class EntityCallbackDiscoverer {
* @author Oliver Drotbohm
*/
private static record EntityCallbackAdapter<T>(EntityCallback<T> delegate, ResolvableType type)
implements EntityCallback<T>, ResolvableTypeProvider {
implements EntityCallback<T> {
@NonNull
@Override
public ResolvableType getResolvableType() {
return type;
boolean supports(ResolvableType callbackType, ResolvableType entityType) {
return callbackType.isInstance(delegate) && supportsEvent(type, entityType);
}
}

View File

@@ -169,8 +169,7 @@ class DefaultEntityCallbacksUnitTests {
@Test // DATACMNS-1467
void detectsMultipleCallbacksWithinOneClass() {
var ctx = new AnnotationConfigApplicationContext(
MultipleCallbacksInOneClassConfig.class);
var ctx = new AnnotationConfigApplicationContext(MultipleCallbacksInOneClassConfig.class);
var callbacks = new DefaultEntityCallbacks(ctx);
@@ -184,6 +183,17 @@ class DefaultEntityCallbacksUnitTests {
assertThat(ctx.getBean("callbacks", MultipleCallbacks.class).invocations).containsExactly("save", "convert");
}
@Test // GH-2822
void genericCallbackDiscoveredForObjectDeclaration() {
var ctx = new AnnotationConfigApplicationContext(SomeConfiguration.class);
var callbacks = new DefaultEntityCallbacks(ctx);
callbacks.callback(BeforeSaveCallback.class, new PersonDocument(null, "Walter", null));
assertThat(ctx.getBean(SomeConfiguration.class).invoked).isTrue();
}
@Configuration
static class MyConfig {
@@ -312,4 +322,18 @@ class DefaultEntityCallbacksUnitTests {
}
// GH-2822
@Configuration
static class SomeConfiguration {
boolean invoked = false;
@Bean
BeforeSaveCallback<Object> someGenericCallback() {
return it -> {
this.invoked = true;
return it;
};
}
}
}