I think I see where you are coming from with the "magic" comment. I tend to be 
slow sometimes writing these things out and they end up going through several 
iterations in my head.

I had gotten to the point where I saw the "getValue" as the equivalent of a 
post retrieval callback. With the idea that the return value had been obtained 
and that certain implementations would require that you do something above and 
beyond before being submitted to the type conversion.

So taking a step back, You can define any of the existing non-class based 
injectors as a series of very discrete steps that are separated into two 
groups. the first being the definition of the object to retrieve a value from 
and then the second are the definitions needed to retrieve the value.


So working on the assumption of a builder pattern which I assume your looking 
at to isolate this from what you are doing at the factory level. I could 
incorporate the callbacks like so;

return 
builder.withName("request-attributes").requiresAdabtable(ServletRequest.class).withMethod("getAttribute").setCallbacks(new
 InjectorBuilder.Callback(){
        public Object postObject(Object adaptable) {
             //do something funky
        }

        public Object postValue(Object adaptable, String name, Type 
declaredType, AnnotatedElement element, DisposalCallbackRegistry 
callbackRegistry) {
             //do something funky
        }
                     
}).build();

So is this more preferable?

-Jason

________________________________________
From: [email protected] <[email protected]> on behalf of Justin 
Edelson <[email protected]>
Sent: Friday, August 29, 2014 11:44 AM
To: [email protected]
Subject: Re: Some thoughts on Sling Models and injectors

Hi Jason,
I'm all for anything that could make injector development simpler. But
personally, that looks like a weird usage for annotations. Have you
considered using the Builder pattern?

Maybe an interface like this:

public interface InjectorFactory {
     Injector build(InjectorBuilder builder);
}

And then you would have:

@Component @Service
public class RequestAttributeInjectorFactory {
    public Injector build(InjectorBuilder builder) {
        return 
builder.withName("request-attributes").withAdaptable(ServletRequest.class).withMethod("getAttribute").build();
    }
}

This, IMHO, accomplishes the same goal, but somehow looks less
"magical" :) WDYT?

As I wrote yesterday in a separate thread, I do think there's been a
bit of sloppiness on my part about type checking/conversion. Unless
specifically required (i.e. the case of the ValueMapInjector), all
type checking and conversion should happen in the ModelAdapterFactory.
And really all conversion should happen via adaptTo().

Justin

On Thu, Aug 28, 2014 at 2:49 PM, Jason Bailey <[email protected]> wrote:
> 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

Reply via email to