Support fallback parameter resolution extension
Overview
Spring Framework would like to be able to resolve parameters from its ApplicationContext so that users can easily create tests that inject beans. We'd also like to allow any existing ParameterResolver instances to take precedence so that Spring only attempts to resolve parameters that have not been otherwise claimed.
For example, given something like this:
@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
class MyTest {
MyTest(@Mock Customer customer, CustomerService service) {
}
}
We'd like to allow the MockitoExtension to support customer and the SpringExtension to support service.
One option to allow this might be to have a FallbackParameterResolver interface which would be used only if no regular ParameterResolver supports the parameter.
Related Issues
- #1604
Tentatively slated for 5.6 M1 for team discussion
@philwebb, thanks for raising the issue.
One option to allow this might be to have a
FallbackParameterResolverinterface which would be used only if no regularParameterResolversupports the parameter.
Are you envisioning that as a marker interface?
are you envisioning that as a marker interface?
I didn't give it too much thought to be honest, but I assumed it would have a slightly different signature to ParameterResolver since it I wasn't sure if supportsParameter made sense. I figured it would have to support all parameter types at that point and throw an exception if it couldn't actually resolve them.
To be more precise, something like:
public interface ParameterResolver extends Extension {
Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException;
}
With the resolveParameter method returning an object or null to inject and throwing ParameterResolutionException on failure.
The default implementation would always throw a ParameterResolutionException, like the one generated at the moment.
- Having a singleton
ParameterResolverinstance installed as fall-back for an entire test run? - Chain multiple such instances and the first one win (and resolve) and the last is the throwing resolver?
🤔
Ordering becomes important if you have a chain so I was originally thinking of just one and throw an exception if someone tired to add multiple @ExtendsWith. I figured that might also match the existing logic where if more than one ParameterResolver claims to support a parameter an exception is thrown.
With the
resolveParametermethod returning an object ornullto inject and throwingParameterResolutionExceptionon failure.
@philwebb, the example you provided is identical to the existing ParameterResolver.
Was that perhaps a copy-n-paste error?
* Having a singleton `ParameterResolver` instance installed as fall-back for an entire test run?
I see no reason to introduce limitations like that. A fallback parameter resolver should not need to be a singleton.
* Chain multiple such instances and the first one win (and resolve) and the last is the throwing resolver?
I'm not sure that chaining fallback resolvers helps us all that much. Normal resolvers are already chained, so to speak. And if we have a chain, we then must have a way to "query" fallback resolvers to ask them if they support a given parameter. Otherwise, we cannot differentiate between null and non-null return values as an indication that the parameter was actually resolved.
Perhaps we just need to create a spike.
I see no reason to introduce limitations like that. A fallback parameter resolver should not need to be a singleton.
Ah, translation issue: wanted to say "single ParameterResolver class that handles all unresolved parameters".
Ordering becomes important if you have a chain so I was originally thinking of just one...
Totally with you and Sam here. One should suffice.
the example you provided is identical to the existing ParameterResolver. Was that perhaps a copy-n-paste error?
It's not quite identical since is doesn't have the supportsParameter method.
Well, from our perspective it is identical, since it fails the Kitchen Sink Test. 😉
In all seriousness, we want a single extension to be able to implement all Extension APIs without ambiguity.
So, for me, the proposal is effectively a marker interface. FallbackParameterResolver could actually extend ParameterResolver without defining any new contract, and I think that might work out nicely.
Team decision: We intend to support this but have yet to decide what the API should look like.
Option 1: Add FallbackParameterResolver as a marker interface that extends ParameterResolver.
Option 2: Add a new default method getResolutionMode(ParameterContext, ExtensionContext) (name subject to change) to ParameterResolver that returns the "mode" of this resolver for a particular parameter. The default implementation would return something like "DIRECT"/"EXPLICIT" with things such as "EAGER" as alternative options to designate fallback support.
This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. Thank you for your contribution.
This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. Thank you for your contribution.