-
Notifications
You must be signed in to change notification settings - Fork 38.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@MockBean does not work with request-scoped Supplier<T> without explicit name #30043
Comments
Thanks for the reproducer. When the bean's type is |
|
More minimal test that shows the difference in Framework's behavior: package com.example;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
class RequestScopedBeansOfTypeTests {
@Test
void requestScopedGenericSupplier() {
ResolvableType type = ResolvableType.forClassWithGenerics(Supplier.class, String.class);
assertBeansAreFound(GenericSupplierConfiguration.class, type);
}
@Test
void requestScopedCustomSupplier() {
ResolvableType type = ResolvableType.forClass(CustomSupplier.class);
assertBeansAreFound(CustomSupplierConfiguration.class, type);
}
void assertBeansAreFound(Class<?> config, ResolvableType type) {
try (AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext()) {
context.register(config);
context.refresh();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
String[] names = beanFactory.getBeanNamesForType(type, true, false);
assertThat(names).containsExactlyInAnyOrder("scopedTarget.requestScopedBean", "requestScopedBean", "bean");
}
}
@Configuration(proxyBeanMethods = false)
static class GenericSupplierConfiguration {
@Bean
@RequestScope
Supplier<String> requestScopedBean() {
return () -> "value";
}
@Bean
Supplier<String> bean() {
return () -> "value";
}
}
@Configuration(proxyBeanMethods = false)
static class CustomSupplierConfiguration {
@Bean
@RequestScope
CustomSupplier requestScopedBean() {
return () -> "value";
}
@Bean
CustomSupplier bean() {
return () -> "value";
}
}
static interface CustomSupplier extends Supplier<String> {
}
} |
There's indeed a problematic shortcut with this case as the factory bean creates a proxy for the scope that does not carry the full generic information that is required for the algorithm to match. Looking at the underlying bean definition that's created, I can see that the the Even if we did that, we still need to modify the algorithm, perhaps checking higher in the stack if the type to match has a generic. Thoughts @jhoeller? |
@MockBean
does not work with request-scoped Supplier<T>
without explicit name
@MockBean
does not work with request-scoped Supplier<T>
without explicit name
Hello, I'd like to work on this issue. I've reproduced the problem with request-scoped I'm planning to work on a solution that improves type matching for scoped proxy beans with generic types. I'll explore both:
I'll submit a PR once I have a working solution with appropriate test coverage. Please let me know if you have any specific guidance or if someone else is already working on this. |
Trying to define mock for request-scoped supplier does not work unless I explicitly name the mock.
The problem with hardcoding bean name is that name can be dependent on configuration (for example via use conditions).
If there is no
RequestScope
or I use custom interface there is no such problem.Spring Boot 2.7.8 + JDK17
Simplified program:
The text was updated successfully, but these errors were encountered: