ignore

Adding Dependency Injectors

A feature of Strecks is the ability to add dependency injectors. A fairly large range of dependency injectors is provided, but adding your own is quite straightforward. As with converters, validators and bind handlers, new dependency injector annotations can be added in a three step process, again, without changing any existing code or configuration file.

  1. The key interface with dependency injection is the InjectionHandler interface. InjectionHandler defines a contract for extracting a dependency from the HttpServletRequest, HttpServletResponse, or one of the other objects accessible via Streck's ActionContext. The InjectionHandler interface has the following form:

    public interface InjectionHandler
    {
        public Object getValue(ActionContext injectionContext);
    }
    

    The purpose of an InjectionHandler implementation is to extract a value from the ActionContext, let's take a look at this interface:

    public interface ActionContext
    {
        public ServletContext getContext();
    
        public ActionForm getForm();
    
        public ActionMapping getMapping();
    
        public HttpServletRequest getRequest();
    
        public HttpServletResponse getResponse();
    }
    

    Actual injection handler implementations tend to be quite straightforward. Consider the implementation of RequestAttributeInjectionHandler, whose job is to extract a request attribute from the HttpServletRequest.

    public class RequestAttributeInjectionHandler implements InjectionHandler
    {
        private String attributeName;
        private Class autoCreateClass;
    
        public RequestAttributeInjectionHandler(String attributeName, 
                     Class autoCreateClass)
        {
            super();
            Assert.notNull(attributeName);
            this.attributeName = attributeName;
            this.autoCreateClass = autoCreateClass;
        }
    
        public String getAttributeName()
        {
            return attributeName;
        }
    
        public Object getValue(ActionContext injectionContext)
        {
            HttpServletRequest request = injectionContext.getRequest();
    
            Object attribute = request.getAttribute(attributeName);
            if (attribute == null && autoCreateClass != null)
            {
                attribute = AnnotationFactoryUtils.maybeAutoCreate(autoCreateClass);
                request.setAttribute(attributeName, attribute);
            }
            return attribute;
        }
    }
    

    Notice how in getValue(), the HttpServletRequest is extracted from the ActionContext, which in turn is used to get the named attribute. If the attribute is null, it may be auto-created. Finally, the result is returned.

  2. Next, we need to provide an annotation which can configure the injection handler. The annotation used for the RequestAttributeInjectionHandler is shown below:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @InjectionFactoryClass(RequestAttributeFactory.class)
    public @interface InjectRequestAttribute
    {
        String name() default "";
        boolean autoCreate() default false;
    }
    

    The annotation provides three pieces of information: the identity of the factory class which has the intelligence to read the annotation and create an injection handler instance, the name of the attribute, and whether it should be auto-created if null.

  3. Finally, we need an implementation of the factory class to link together the InjectionHandler and the annotation. Our implementation of RequestAttributeFactory is shown below:

    public class RequestAttributeFactory implements InjectionHandlerFactory
    {
        public InjectionHandler createInjectionHandler(
                     Annotation annotation, Class clazz, InjectionSetter inputSetter)
        {
            InjectRequestAttribute input = (InjectRequestAttribute) annotation;
            
            String attributeName = 
                AnnotationFactoryUtils.getAttributeName(inputSetter, input.name());
            Class autoCreateClass = input.autoCreate() ? inputSetter.getType() : null;
            
            RequestAttributeInjectionHandler handler = 
                new RequestAttributeInjectionHandler(attributeName, autoCreateClass);
        }
    }
    

    The factory class's main responsibilities, of course, are to identify the attribute name and to determine the value for the autoCreate property.

Note that you do not need to implement the mechanism to bind the value extracted using the InjectionHandler to the target action bean property. This is internalized in the Streck runtime dependency injection support.

SourceForge.net logo java.net Member logo Copyright © 2005-2007 Realsolve Solutions