While working on #28976, it became apparent that a BeanFactory
initializer registered in BeanFactoryInitializationCode
could use a more flexible signature. Rather than injecting the DefaultListableBeanFactory
the contribution needs a ConfigurableEnvironment
and a ResourceLoader
. The former can be retrieved by the bean factory (although a bit odd). The latter is harder.
MethodReference
provides a very nice abstraction and we've almost what we need but I'd like to use the opportunity to see if we can avoid adding yet another toCodeBlock
method as the current ones are already a bit confusing IMO.
GeneratedMethod
It's often needed to get a MethodReference
from a GeneratedMethod
. It seems it would be relatively easy to pass a ClassName
to GeneratedMethods
so that the GenerateMethod
it produces can return a MethodReference
(toMethodReference
or something like that).
Also a method reference that's built from a MethodSpec
this way knows about its name, kind, and declaring class.
MethodReference getDeclaringClass
and getMethodName
Both of these seem to be unused so they should probably be removed.
CodeBlock patterns
MethodReference
provides several ways of invoking the method:
toCodeBlock()
: is producing a method reference, expecting the current context to match the signature and the method to be defined in the current class (if not static).toCodeBlock(String instanceVariable)
: is producing a method reference, expecting the current context to match the signature and the method to be defined by the class referred to theinstanceVariable
argument. (It looks like it's only used in tests or bytoCodeBlock
that's calling with anull
instance variable).toInvokeCodeBlock(CodeBlock... args)
: is producing a method invocation expected to match the arguments and the method to be defined in the current class (if not static)toInvokeCodeBlock(String instanceVariable, CodeBlock... args)
: is producing a method invocation expected to match the arguments and the method to be defined by the class referred to theinstanceVariable
argument.
I wonder if a unique toCodeBlock
that provides a context could let the MethodReference
decide for itself how the method invocation should occur. The following information would be needed:
- A resolver for arguments that could work at two potential levels:
- Provide a
CodeBlock
for a givenClass
- Expected well-known variable name to be present
- If the declaring class of the method is the current class. If not, the value of an
instanceVariable
. - Whether or not lambda references are possible (that last bit is still a bit blurry).
Comment From: snicoll
InstanceSupplierCodeGenerator
also has a method that could become irrelevant to some extent:
private CodeBlock generateReturnStatement(GeneratedMethod getInstanceMethod) {
return CodeBlock.of("$T.$L()", this.className, getInstanceMethod.getName());
}
Comment From: snicoll
toInvokeCodeBlockForInstance
also creates a new instance of the declaring class which looks a very specific decision such a generic method would take.
Comment From: snicoll
Most of the of
static factory method of MethodReference
are only used in tests.
Comment From: snicoll
I've had a brainstorming session with @wilkinsona and @bclozel today. We've discussed various options and the pros and cons and we conclude that it is overkill to try to avoid both side having some sort of shared context. Trying to do that means too much context needs to be provided by the caller and MethodReference
has to know too many things to take the right decision.
We came back with the original need of offering a more flexible signature and we'd like to explore how toInvokeCodeBlock
could be changed to take something that resolves a limited number of arguments, rather than the current CodeBlock
vararg.
Comment From: snicoll
I've made some good progress in https://github.com/snicoll/spring-framework/tree/gh-29005 - One advantage of knowing the ultimate location of the code is that we don't expand the class name for static internal calls. For instance, the following code:
beanDefinition.setInstanceSupplier(ApplicationAvailabilityAutoConfiguration__BeanDefinitions.getApplicationAvailabilityInstanceSupplier());
Is now:
beanDefinition.setInstanceSupplier(getApplicationAvailabilityInstanceSupplier());
However, knowing the ultimate target class isn't always possible so we might need to adapt some API. Perhaps methodReference
itself could offer some sort of support for this.