    001    /*****************************************************************************
    002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
    003     * ------------------------------------------------------------------------- *
    004     * The software in this package is published under the terms of the BSD      *
    005     * style license a copy of which has been included with this distribution in *
    006     * the LICENSE.txt file.                                                     *
    007     *                                                                           *
    008     * Original code by                                                          *
    009     *****************************************************************************/
    010    package org.picocontainer.injectors;
    011
    012    import org.picocontainer.ComponentMonitor;
    013    import org.picocontainer.LifecycleStrategy;
    014    import org.picocontainer.Parameter;
    015    import org.picocontainer.NameBinding;
    016    import org.picocontainer.annotations.Bind;
    017
    018    import java.lang.annotation.Annotation;
    019    import java.lang.reflect.AccessibleObject;
    020    import java.lang.reflect.Field;
    021    import java.lang.reflect.InvocationTargetException;
    022    import java.lang.reflect.Type;
    023    import java.security.AccessController;
    024    import java.security.PrivilegedAction;
    025    import java.util.ArrayList;
    026    import java.util.List;
    027
    028    /**
    029     * Injection happens after instantiation, and through fields marked as injection points via an Annotation.
    030     * The default annotation of org.picocontainer.annotations.@Inject can be overridden.
    031     */
    032    @SuppressWarnings("serial")
    033    public class AnnotatedFieldInjector extends IterativeInjector {
    034
    035
    036        private final Class<? extends Annotation> injectionAnnotation;
    037
    038        public AnnotatedFieldInjector(Object key,
    039                                      Class<?> impl,
    040                                      Parameter[] parameters,
    041                                      ComponentMonitor componentMonitor,
    042                                      LifecycleStrategy lifecycleStrategy,
    043                                      Class<? extends Annotation> injectionAnnotation, boolean useNames) {
    044
    045            super(key, impl, parameters, componentMonitor, lifecycleStrategy, useNames);
    046            this.injectionAnnotation = injectionAnnotation;
    047        }
    048
    049        protected void initializeInjectionMembersAndTypeLists() {
    050            injectionMembers = new ArrayList<AccessibleObject>();
    051            List<Annotation> bindingIds = new ArrayList<Annotation>();
    052            final List<Type> typeList = new ArrayList<Type>();
    053            Class drillInto = getComponentImplementation();
    054            while (drillInto != Object.class) {
    055                final Field[] fields = getFields(drillInto);
    056                for (final Field field : fields) {
    057                    if (isAnnotatedForInjection(field)) {
    058                        injectionMembers.add(field);
    059                        typeList.add(box(field.getType()));
    060                        bindingIds.add(getBinding(field));
    061                    }
    062                }
    063                drillInto = drillInto.getSuperclass();
    064            }
    065            injectionTypes = typeList.toArray(new Type[0]);
    066            bindings = bindingIds.toArray(new Annotation[0]);
    067        }
    068
    069        private Annotation getBinding(Field field) {
    070            Annotation[] annotations = field.getAnnotations();
    071            for (Annotation annotation : annotations) {
    072                if (annotation.annotationType().isAnnotationPresent(Bind.class)) {
    073                    return annotation;
    074                }
    075            }
    076            return null;
    077        }
    078
    079        protected boolean isAnnotatedForInjection(Field field) {
    080            return field.getAnnotation(injectionAnnotation) != null;
    081        }
    082
    083        private Field[] getFields(final Class clazz) {
    084            return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
    085                public Object run() {
    086                    return clazz.getDeclaredFields();
    087                }
    088            });
    089        }
    090
    091
    092        protected Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject)
    093                throws IllegalAccessException, InvocationTargetException {
    094            Field field = (Field) member;
    095            field.setAccessible(true);
    096            field.set(componentInstance, toInject);
    097            return null;
    098        }
    099
    100        public String getDescriptor() {
    101            return "AnnotatedFieldInjector-";
    102        }
    103
    104        protected NameBinding makeParameterNameImpl(final AccessibleObject member) {
    105            return new NameBinding() {
    106                public String getName() {
    107                    return ((Field) member).getName();
    108                }
    109            };
    110        }
    111
    112        protected Object memberInvocationReturn(Object lastReturn, AccessibleObject member, Object instance) {
    113            return instance;
    114        }
    115    }