1 10 11 package org.picocontainer.defaults; 12 13 import org.picocontainer.Parameter; 14 import org.picocontainer.PicoContainer; 15 import org.picocontainer.PicoInitializationException; 16 import org.picocontainer.PicoIntrospectionException; 17 18 import java.lang.reflect.Constructor ; 19 import java.lang.reflect.InvocationTargetException ; 20 import java.lang.reflect.Modifier ; 21 import java.util.ArrayList ; 22 import java.util.Arrays ; 23 import java.util.Collections ; 24 import java.util.Comparator ; 25 import java.util.HashSet ; 26 import java.util.List ; 27 import java.util.Set ; 28 29 43 public class ConstructorInjectionComponentAdapter extends InstantiatingComponentAdapter { 44 private transient List sortedMatchingConstructors; 45 private transient Guard instantiationGuard; 46 private ComponentMonitor componentMonitor; 47 48 private static abstract class Guard extends ThreadLocalCyclicDependencyGuard { 49 protected PicoContainer guardedContainer; 50 51 private void setArguments(PicoContainer container) { 52 this.guardedContainer = container; 53 } 54 } 55 56 60 public ConstructorInjectionComponentAdapter(final Object componentKey, 61 final Class componentImplementation, 62 Parameter[] parameters, 63 boolean allowNonPublicClasses, 64 ComponentMonitor componentMonitor) throws AssignabilityRegistrationException, NotConcreteRegistrationException { 65 super(componentKey, componentImplementation, parameters, allowNonPublicClasses); 66 this.componentMonitor = componentMonitor; 67 } 68 69 public ConstructorInjectionComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters) { 70 this(componentKey, componentImplementation, parameters, false, NullComponentMonitor.getInstance()); 71 } 72 73 76 public ConstructorInjectionComponentAdapter(Object componentKey, 77 Class componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException { 78 this(componentKey, componentImplementation, null); 79 } 80 81 protected Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException { 82 Constructor greediestConstructor = null; 83 final Set conflicts = new HashSet (); 84 final Set unsatisfiableDependencyTypes = new HashSet (); 85 if (sortedMatchingConstructors == null) { 86 sortedMatchingConstructors = getSortedMatchingConstructors(); 87 } 88 int lastSatisfiableConstructorSize = -1; 89 for (int i = 0; i < sortedMatchingConstructors.size(); i++) { 90 boolean failedDependency = false; 91 Constructor constructor = (Constructor ) sortedMatchingConstructors.get(i); 92 Class [] parameterTypes = constructor.getParameterTypes(); 93 Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes); 94 95 for (int j = 0; j < currentParameters.length; j++) { 97 if (currentParameters[j].isResolvable(container, this, parameterTypes[j])) { 99 continue; 100 } 101 unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes)); 102 failedDependency = true; 103 break; 104 } 105 106 if (greediestConstructor != null && parameterTypes.length != lastSatisfiableConstructorSize) { 107 if (conflicts.isEmpty()) { 108 return greediestConstructor; 110 } else { 111 conflicts.add(constructor); 113 } 114 } else if (!failedDependency && lastSatisfiableConstructorSize == parameterTypes.length) { 115 conflicts.add(constructor); 117 conflicts.add(greediestConstructor); 118 } else if (!failedDependency) { 119 greediestConstructor = constructor; 120 lastSatisfiableConstructorSize = parameterTypes.length; 121 } 122 } 123 if (!conflicts.isEmpty()) { 124 throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts); 125 } else if (greediestConstructor == null && !unsatisfiableDependencyTypes.isEmpty()) { 126 throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes); 127 } else if (greediestConstructor == null) { 128 final Set nonMatching = new HashSet (); 130 final Constructor [] constructors = getComponentImplementation().getDeclaredConstructors(); 131 for (int i = 0; i < constructors.length; i++) { 132 nonMatching.add(constructors[i]); 133 } 134 throw new PicoInitializationException("Either do the specified parameters not match any of the following constructors: " + nonMatching.toString() + " or the constructors were not accessible for '" + getComponentImplementation() + "'"); 135 } 136 return greediestConstructor; 137 } 138 139 public Object getComponentInstance(PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException { 140 if (instantiationGuard == null) { 141 instantiationGuard = new Guard() { 142 public Object run() { 143 final Constructor constructor; 144 try { 145 constructor = getGreediestSatisfiableConstructor(guardedContainer); 146 } catch (AmbiguousComponentResolutionException e) { 147 e.setComponent(getComponentImplementation()); 148 throw e; 149 } 150 try { 151 Object [] parameters = getConstructorArguments(guardedContainer, constructor); 152 componentMonitor.instantiating(constructor); 153 long startTime = System.currentTimeMillis(); 154 Object inst = newInstance(constructor, parameters); 155 componentMonitor.instantiated(constructor, startTime, System.currentTimeMillis() - startTime); 156 return inst; 157 } catch (InvocationTargetException e) { 158 componentMonitor.instantiationFailed(constructor, e); 159 if (e.getTargetException() instanceof RuntimeException ) { 160 throw (RuntimeException ) e.getTargetException(); 161 } else if (e.getTargetException() instanceof Error ) { 162 throw (Error ) e.getTargetException(); 163 } 164 throw new PicoInvocationTargetInitializationException(e.getTargetException()); 165 } catch (InstantiationException e) { 166 componentMonitor.instantiationFailed(constructor, e); 169 throw new PicoInitializationException("Should never get here"); 170 } catch (IllegalAccessException e) { 172 componentMonitor.instantiationFailed(constructor, e); 175 throw new PicoInitializationException(e); 176 } 178 } 179 }; 180 } 181 instantiationGuard.setArguments(container); 182 return instantiationGuard.observe(getComponentImplementation()); 183 } 184 185 protected Object [] getConstructorArguments(PicoContainer container, Constructor ctor) { 186 Class [] parameterTypes = ctor.getParameterTypes(); 187 Object [] result = new Object [parameterTypes.length]; 188 Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes); 189 190 for (int i = 0; i < currentParameters.length; i++) { 191 result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i]); 192 } 193 return result; 194 } 195 196 private List getSortedMatchingConstructors() { 197 List matchingConstructors = new ArrayList (); 198 Constructor [] allConstructors = getComponentImplementation().getDeclaredConstructors(); 199 Constructor constructor; 201 for (int i = 0; i < allConstructors.length; i++) { 202 constructor = allConstructors[i]; 203 if ((parameters == null || constructor.getParameterTypes().length == parameters.length) 204 && (allowNonPublicClasses || (constructor.getModifiers() & Modifier.PUBLIC) != 0)) { 205 matchingConstructors.add(constructor); 206 } 207 } 208 if (parameters == null) { 210 Collections.sort(matchingConstructors, new Comparator () { 211 public int compare(Object arg0, Object arg1) { 212 return ((Constructor ) arg1).getParameterTypes().length - ((Constructor ) arg0).getParameterTypes().length; 213 } 214 }); 215 } 216 return matchingConstructors; 217 } 218 } 219 | Popular Tags |