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