    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 java.lang.annotation.Annotation;
    013    import java.lang.reflect.AccessibleObject;
    014    import java.lang.reflect.Field;
    015    import java.lang.reflect.InvocationTargetException;
    016    import java.lang.reflect.Type;
    017    import java.security.AccessController;
    018    import java.security.PrivilegedAction;
    019    import java.util.ArrayList;
    020    import java.util.Arrays;
    021    import java.util.Collections;
    022    import java.util.List;
    023
    024    import org.picocontainer.ComponentMonitor;
    025    import org.picocontainer.LifecycleStrategy;
    026    import org.picocontainer.NameBinding;
    027    import org.picocontainer.Parameter;
    028    import org.picocontainer.annotations.Bind;
    029
    030    /**
    031     * Injection happens after instantiation, and fields are marked as
    032     * injection points via a named field.
    033     */
    034    @SuppressWarnings("serial")
    035    public class NamedFieldInjector extends IterativeInjector {
    036
    037
    038        private final List<String> fieldNames;
    039
    040        public NamedFieldInjector(Object key,
    041                                      Class<?> impl,
    042                                      Parameter[] parameters,
    043                                      ComponentMonitor componentMonitor,
    044                                      LifecycleStrategy lifecycleStrategy,
    045                                      String fieldNames) {
    046
    047            super(key, impl, parameters, componentMonitor, lifecycleStrategy, true);
    048            this.fieldNames = Arrays.asList(fieldNames.trim().split(" "));
    049        }
    050
    051        protected void initializeInjectionMembersAndTypeLists() {
    052            injectionMembers = new ArrayList<AccessibleObject>();
    053            List<Annotation> bindingIds = new ArrayList<Annotation>();
    054            final List<Type> typeList = new ArrayList<Type>();
    055            final Field[] fields = getFields();
    056            for (final Field field : fields) {
    057                if (isNamedForInjection(field)) {
    058                    injectionMembers.add(field);
    059                    typeList.add(box(field.getType()));
    060                    bindingIds.add(getBinding(field));
    061                }
    062            }
    063            injectionTypes = typeList.toArray(new Type[0]);
    064            bindings = bindingIds.toArray(new Annotation[0]);
    065        }
    066
    067        private Annotation getBinding(Field field) {
    068            Annotation[] annotations = field.getAnnotations();
    069            for (Annotation annotation : annotations) {
    070                if (annotation.annotationType().isAnnotationPresent(Bind.class)) {
    071                    return annotation;
    072                }
    073            }
    074            return null;
    075        }
    076
    077        protected boolean isNamedForInjection(Field field) {
    078            return fieldNames.contains(field.getName());
    079        }
    080
    081        private Field[] getFields() {
    082            return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
    083                public Object run() {
    084                    return getComponentImplementation().getDeclaredFields();
    085                }
    086            });
    087        }
    088
    089
    090        protected Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject)
    091            throws IllegalAccessException, InvocationTargetException {
    092            Field field = (Field) member;
    093            field.setAccessible(true);
    094            field.set(componentInstance, toInject);
    095            return null;
    096        }
    097
    098        public String getDescriptor() {
    099            return "NamedFieldInjector-";
    100        }
    101
    102        protected NameBinding makeParameterNameImpl(final AccessibleObject member) {
    103            return new NameBinding() {
    104                public String getName() {
    105                    return ((Field) member).getName();
    106                }
    107            };
    108        }
    109
    110        protected Object memberInvocationReturn(Object lastReturn, AccessibleObject member, Object instance) {
    111            return instance;
    112        }
    113
    114        List<String> getInjectionFieldNames() {
    115            return Collections.unmodifiableList(fieldNames);
    116        }
    117
    118
    119    }