Our team has been working on adopting the sling model paradigm which has given
me a chance to get involved with creating a number of injectors to meet our
needs.
I wanted to share some of my observations.
To clarify the existing flow, when we are looking at performing an injection it
is really a three step process.
* Obtain the base Object from the supplied adaptable
* Retrieve a value from the base Object
* Manipulate the value to meet the type expectations of the annotated field
During any one of these steps, the result of the step could equal null and the
process would then move on to the next injector.
While working on these injectors I came across a series of commonalities within
their implementations. You could actually define a shorthand for the majority
of the injectors, and extrapolating from that you could define an injector
completely in annotations.
Example annotations derived from existing
For defining the base object
@adaptable(Class<?>) The expected object to be used as the source of this
injector
@via(String) use a JavaBean property of the adaptable as the source of the
injection
@viaArgument(Object*) if present, use this as the argument for the @via access
@adaptTo(Class<?>) if present attempts to adapt the current base Object
For retrieving the value
@method(String) name of the method to use.
@named(String) name of the argument for the above @method, defaults to the
property name
@default(Object*) replaces the returned value if null.
Which, if you put the logic for these annotations in the framework, would allow
you to do things like this mockup of a RequestAttribute injector:
public class RequestAttributeInjector {
@adaptable(ServletRequest.class) @method("getAttribute")
Object getValue(Object adaptable, String name, Type declaredType,
AnnotatedElement element, DisposalCallbackRegistry callbackRegistry){
return adaptable;
}
}
where a SlingBindings injector would look like this
public class SlingBindingsInjector {
@adaptable(ServletRequest.class) @via("attribute")
@viaArgument(SlingBindings.class.name()) @method("get")
Object getValue(Object adaptable, String name, Type declaredType,
AnnotatedElement element, DisposalCallbackRegistry callbackRegistry){
return adaptable;
}
}
You'll notice I didn't touch step 3. Because once you extract these concepts
into separate steps, type conversion is the same for all objects and therefore
something that should be supplied by the framework. This sort of separation
would provide consistency of type conversion across different injectors.
My TL;DR comes down to
I believe that by adding additional meta information to the sling injector
definition, either through annotations or properties, that you could streamline
the functionality and make it easier to develop new injectors. An example being
the declaration of what type of adaptable is expected and verifying that prior
to calling the injector.
The addition of the meta information could be added expanded to the point that
most injectors could be defined as a series of properties.
Additionally, unifying the type conversion outside of the injector would be
beneficial, as it provides a consistent type conversion process and enables
improvements of that process to be shared by all injectors.
WDYT?
-Jason