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 *****************************************************************************/
009 package org.picocontainer.injectors;
010
011 import org.picocontainer.Parameter;
012 import org.picocontainer.ComponentMonitor;
013 import org.picocontainer.LifecycleStrategy;
014 import org.picocontainer.ParameterName;
015 import org.picocontainer.PicoContainer;
016
017 import java.lang.reflect.AccessibleObject;
018 import java.lang.reflect.Method;
019 import java.lang.reflect.Constructor;
020 import java.lang.reflect.Field;
021 import java.lang.reflect.Modifier;
022 import java.lang.reflect.Member;
023
024 /** @author Paul Hammant */
025 public abstract class SingleMemberInjector extends AbstractInjector {
026
027 private transient ParanamerProxy paranamer;
028
029 private static final String[] EMPTY_NAMES = new String[]{};
030 private static final String COMMA = ",";
031 private static final String SPACE = " ";
032
033 public SingleMemberInjector(Object componentKey,
034 Class componentImplementation,
035 Parameter[] parameters,
036 ComponentMonitor monitor,
037 LifecycleStrategy lifecycleStrategy) {
038 super(componentKey, componentImplementation, parameters, monitor, lifecycleStrategy);
039 }
040
041
042 private void createIfNeededParanamerProxy() {
043 if (paranamer == null) {
044 try {
045 paranamer = new ParanamerProxy();
046 } catch (NoClassDefFoundError e) {
047 }
048 }
049 }
050
051
052 // copied from DefaultParanamer
053 protected String[] lookupParameterNames(AccessibleObject methodOrCtor) {
054 Class[] types = null;
055 Class declaringClass = null;
056 String name = null;
057 if (methodOrCtor instanceof Method) {
058 Method method = (Method) methodOrCtor;
059 types = method.getParameterTypes();
060 name = method.getName();
061 declaringClass = method.getDeclaringClass();
062 } else {
063 Constructor constructor = (Constructor) methodOrCtor;
064 types = constructor.getParameterTypes();
065 declaringClass = constructor.getDeclaringClass();
066 name = "<init>";
067 }
068
069 if (types.length == 0) {
070 // faster ?
071 return EMPTY_NAMES;
072 }
073 final String parameterTypeNames = getParameterTypeNamesCSV(types);
074 final String[] names = getParameterNames(declaringClass, parameterTypeNames, name + SPACE);
075
076 if (names != null) {
077 return names;
078 }
079 createIfNeededParanamerProxy();
080 if (paranamer != null) {
081 return paranamer.lookupParameterNames((Constructor)methodOrCtor);
082 }
083 return new String[0];
084 }
085
086 protected Object[] getMemberArguments(PicoContainer container, final AccessibleObject member, final Class[] parameterTypes) {
087 Object[] result = new Object[parameterTypes.length];
088 Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
089
090 for (int i = 0; i < currentParameters.length; i++) {
091 result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i],
092 new MemberInjectorParameterName(member, i));
093 }
094 return result;
095 }
096
097
098
099 // copied from DefaultParanamer
100 private static String getParameterTypeNamesCSV(Class[] parameterTypes) {
101 StringBuffer sb = new StringBuffer();
102 for (int i = 0; i < parameterTypes.length; i++) {
103 sb.append(parameterTypes[i].getName());
104 if (i < parameterTypes.length - 1) {
105 sb.append(COMMA);
106 }
107 }
108 return sb.toString();
109 }
110 // copied from DefaultParanamer
111 private static String[] getParameterNames(Class declaringClass, String parameterTypes, String prefix) {
112 String data = getParameterListResource(declaringClass);
113 String line = findFirstMatchingLine(data, prefix + parameterTypes);
114 String[] parts = line.split(SPACE);
115 // assumes line structure: constructorName parameterTypes parameterNames
116 if (parts.length == 3 && parts[1].equals(parameterTypes)) {
117 String parameterNames = parts[2];
118 return parameterNames.split(COMMA);
119 }
120 return null;
121 }
122 // copied from DefaultParanamer
123 private static String getParameterListResource(Class declaringClass) {
124 try {
125 Field field = declaringClass.getDeclaredField("__PARANAMER_DATA");
126 if(!Modifier.isStatic(field.getModifiers()) || !field.getType().equals(String.class)) {
127 return null;
128 }
129 return (String) field.get(null);
130 } catch (NoSuchFieldException e) {
131 return null;
132 } catch (IllegalAccessException e) {
133 return null;
134 }
135 }
136 // copied from DefaultParanamer
137 private static String findFirstMatchingLine(String data, String prefix) {
138 if (data == null) {
139 return "";
140 }
141 int ix = data.indexOf(prefix);
142 if (ix > 0) {
143 int iy = data.indexOf("\n", ix);
144 if(iy >0) {
145 return data.substring(ix,iy);
146 }
147 }
148 return "";
149 }
150
151 protected class MemberInjectorParameterName implements ParameterName {
152 private final AccessibleObject member;
153 private final int index;
154
155 public MemberInjectorParameterName(AccessibleObject member, int index) {
156 this.member = member;
157 this.index = index;
158 }
159
160 public String getName() {
161 createIfNeededParanamerProxy();
162 if (paranamer != null) {
163 String[] strings = lookupParameterNames(member);
164 return strings.length == 0 ? "" : strings[index];
165 }
166 return null;
167 }
168 }
169
170
171
172
173 }