    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 field type.
    033     */
    034    @SuppressWarnings("serial")
    035    public class TypedFieldInjector extends IterativeInjector {
    036
    037        /**
    038             * Serialization UUID.
    039             */
    040
    041        private final List<String> classes;
    042
    043        public TypedFieldInjector(Object key,
    044                                      Class<?> impl,
    045                                      Parameter[] parameters,
    046                                      ComponentMonitor componentMonitor,
    047                                      LifecycleStrategy lifecycleStrategy,
    048                                      String classNames) {
    049
    050            super(key, impl, parameters, componentMonitor, lifecycleStrategy, true);
    051            this.classes = Arrays.asList(classNames.trim().split(" "));
    052        }
    053
    054        protected void initializeInjectionMembersAndTypeLists() {
    055            injectionMembers = new ArrayList<AccessibleObject>();
    056            List<Annotation> bindingIds = new ArrayList<Annotation>();
    057            final List<Type> typeList = new ArrayList<Type>();
    058            final Field[] fields = getFields();
    059            for (final Field field : fields) {
    060                if (isTypedForInjection(field)) {
    061                    injectionMembers.add(field);
    062                    typeList.add(box(field.getType()));
    063                    bindingIds.add(getBinding(field));
    064                }
    065            }
    066            injectionTypes = typeList.toArray(new Type[0]);
    067            bindings = bindingIds.toArray(new Annotation[0]);
    068        }
    069
    070        private Annotation getBinding(Field field) {
    071            Annotation[] annotations = field.getAnnotations();
    072            for (Annotation annotation : annotations) {
    073                if (annotation.annotationType().isAnnotationPresent(Bind.class)) {
    074                    return annotation;
    075                }
    076            }
    077            return null;
    078        }
    079
    080        protected boolean isTypedForInjection(Field field) {
    081            return classes.contains(field.getType().getName());
    082        }
    083
    084        private Field[] getFields() {
    085            return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
    086                public Object run() {
    087                    return getComponentImplementation().getDeclaredFields();
    088                }
    089            });
    090        }
    091
    092
    093        protected Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject)
    094            throws IllegalAccessException, InvocationTargetException {
    095            Field field = (Field) member;
    096            field.setAccessible(true);
    097            field.set(componentInstance, toInject);
    098            return null;
    099        }
    100
    101        public String getDescriptor() {
    102            return "TypedFieldInjector-";
    103        }
    104
    105        protected NameBinding makeParameterNameImpl(final AccessibleObject member) {
    106            return new NameBinding() {
    107                public String getName() {
    108                    return ((Field) member).getName();
    109                }
    110            };
    111        }
    112
    113        protected Object memberInvocationReturn(Object lastReturn, AccessibleObject member, Object instance) {
    114            return instance;
    115        }
    116
    117        List<String> getInjectionFieldTypes() {
    118            return Collections.unmodifiableList(classes);
    119        }
    120
    121
    122    }