I'm on a team migrating a relatively large and complex Java application to Kotlin and Spring. It's not feasible to top-down refactor the entire app to Kotlin and dependency injection all at once. To facilitate incremental migration, we capture the ApplicationContext
to a static field on startup. From there it can accessed throughout the application. Legacy code can use the ApplicationContext
as a service locator via its BeanFactory
and ListableBeanFactory
methods to access the Spring-ified parts of the application. As the refactoring to DI proceeds, the direct ApplicationContext
references are pulled up the call stack until the top-level @Configuration
is reached.
We tend to prefer disambiguating beans by type, so T BeanFactory.getBean(Class<T>)
is the most commonly used locator method. The problem is, generic types aren't supported. There's ObjectProvider<T> BeanFactory.getBeanProvider(ResolvableType requiredType)
, but its use involves a bit of boilerplate:
ParameterizedTypeReference<List<List<String>>> parameterizedTypeReference =
new ParameterizedTypeReference<>() { };
ResolvableType resolvableType =
ResolvableType.forType(parameterizedTypeReference);
ObjectProvider<List<List<String>>> objectProvider =
applicationContext.getBeanProvider(resolvableType);
List<List<String>> listOfListOfString =
objectProvider.getObject();
This can be wrapped up into a utility, but it would be nice if ParameterizedTypeReference
overloads of the getBean
methods were already available, for example:
List<List<String>> listOfListOfString =
applicationContext.getBean(new ParameterizedTypeReference<List<List<String>>>() { });
They would also streamline the Kotlin getBean
extension implementations with their reified type parameters (see #31439).
I noticed more discussion of ParameterizedTypeReference
vs. ResolvableType
in #20195. I tend to agree with the comments that the super type token approach of ParameterizedTypeReference
makes for the more convenient public API.
I realize using the application context as a service locator is not the primary design intent for the framework, but I'm hoping the migration use case warrants consideration of ParameterizedTypeReference
overloads. Presumably they could be added as interface default methods for backwards compatibility.
Comment From: snicoll
Thanks for the suggestion, but that's not the purpose of ParameterizedTypeReference
. For what you're trying to accomplish, ResolvableType
is the way to go and ObjectProvider
provides more control over the result of the lookup. I understand this leads to a bit more code in your end for straightforward use cases, but you can easily craft a couple of methods that provide what you need. Besides, getBean
has already a number of overloads so we won't be adding one more for this.
Side note: but for lookups like this, you really should use the BeanFactory
rather than having the full method signatures that ApplicationContext
brings.