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 }