Clover coverage report - picocontainer - 1.2-beta-1
Coverage timestamp: Sun May 29 2005 14:29:04 BST
file stats: LOC: 218   Methods: 10
NCLOC: 158   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ConstructorInjectionComponentAdapter.java 100% 100% 100% 100%
coverage
 1    /*****************************************************************************
 2    * Copyright (c) PicoContainer Organization. All rights reserved. *
 3    * ------------------------------------------------------------------------- *
 4    * The software in this package is published under the terms of the BSD *
 5    * style license a copy of which has been included with this distribution in *
 6    * the LICENSE.txt file. *
 7    * *
 8    * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
 9    *****************************************************************************/
 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    /**
 30    * Instantiates components using Constructor Injection.
 31    * <em>
 32    * Note that this class doesn't cache instances. If you want caching,
 33    * use a {@link CachingComponentAdapter} around this one.
 34    * </em>
 35    *
 36    * @author Paul Hammant
 37    * @author Aslak Helles&oslash;y
 38    * @author Jon Tirs&eacute;n
 39    * @author Zohar Melamed
 40    * @author J&ouml;rg Schaible
 41    * @version $Revision: 1840 $
 42    */
 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  970 private void setArguments(PicoContainer container) {
 52  970 this.guardedContainer = container;
 53    }
 54    }
 55   
 56    /**
 57    * Explicitly specifies parameters. If parameters are null, default parameters
 58    * will be used.
 59    */
 60  1146 public ConstructorInjectionComponentAdapter(final Object componentKey,
 61    final Class componentImplementation,
 62    Parameter[] parameters,
 63    boolean allowNonPublicClasses,
 64    ComponentMonitor componentMonitor) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 65  1146 super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
 66  1146 this.componentMonitor = componentMonitor;
 67    }
 68   
 69  130 public ConstructorInjectionComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters) {
 70  130 this(componentKey, componentImplementation, parameters, false, NullComponentMonitor.getInstance());
 71    }
 72   
 73    /**
 74    * Use default parameters.
 75    */
 76  114 public ConstructorInjectionComponentAdapter(Object componentKey,
 77    Class componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 78  114 this(componentKey, componentImplementation, null);
 79    }
 80   
 81  1018 protected Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 82  1018 Constructor greediestConstructor = null;
 83  1018 final Set conflicts = new HashSet();
 84  1018 final Set unsatisfiableDependencyTypes = new HashSet();
 85  1018 if (sortedMatchingConstructors == null) {
 86  848 sortedMatchingConstructors = getSortedMatchingConstructors();
 87    }
 88  1018 int lastSatisfiableConstructorSize = -1;
 89  1018 for (int i = 0; i < sortedMatchingConstructors.size(); i++) {
 90  2040 boolean failedDependency = false;
 91  2040 Constructor constructor = (Constructor) sortedMatchingConstructors.get(i);
 92  2040 Class[] parameterTypes = constructor.getParameterTypes();
 93  2040 Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
 94   
 95    // remember: all constructors with less arguments than the given parameters are filtered out already
 96  2040 for (int j = 0; j < currentParameters.length; j++) {
 97    // check wether this constructor is statisfiable
 98  1762 if (currentParameters[j].isResolvable(container, this, parameterTypes[j])) {
 99  670 continue;
 100    }
 101  1078 unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 102  1078 failedDependency = true;
 103  1078 break;
 104    }
 105   
 106  2026 if (greediestConstructor != null && parameterTypes.length != lastSatisfiableConstructorSize) {
 107  16 if (conflicts.isEmpty()) {
 108    // we found our match [aka. greedy and satisfied]
 109  14 return greediestConstructor;
 110    } else {
 111    // fits although not greedy
 112  2 conflicts.add(constructor);
 113    }
 114  2010 } else if (!failedDependency && lastSatisfiableConstructorSize == parameterTypes.length) {
 115    // satisfied and same size as previous one?
 116  2 conflicts.add(constructor);
 117  2 conflicts.add(greediestConstructor);
 118  2008 } else if (!failedDependency) {
 119  930 greediestConstructor = constructor;
 120  930 lastSatisfiableConstructorSize = parameterTypes.length;
 121    }
 122    }
 123  990 if (!conflicts.isEmpty()) {
 124  2 throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts);
 125  988 } else if (greediestConstructor == null && !unsatisfiableDependencyTypes.isEmpty()) {
 126  72 throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
 127  916 } else if (greediestConstructor == null) {
 128    // be nice to the user, show all constructors that were filtered out
 129  2 final Set nonMatching = new HashSet();
 130  2 final Constructor[] constructors = getComponentImplementation().getDeclaredConstructors();
 131  2 for (int i = 0; i < constructors.length; i++) {
 132  2 nonMatching.add(constructors[i]);
 133    }
 134  2 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  914 return greediestConstructor;
 137    }
 138   
 139  970 public Object getComponentInstance(PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 140  970 if (instantiationGuard == null) {
 141  802 instantiationGuard = new Guard() {
 142  956 public Object run() {
 143  956 final Constructor constructor;
 144  956 try {
 145  956 constructor = getGreediestSatisfiableConstructor(guardedContainer);
 146    } catch (AmbiguousComponentResolutionException e) {
 147  14 e.setComponent(getComponentImplementation());
 148  14 throw e;
 149    }
 150  894 try {
 151  894 Object[] parameters = getConstructorArguments(guardedContainer, constructor);
 152  864 componentMonitor.instantiating(constructor);
 153  864 long startTime = System.currentTimeMillis();
 154  864 Object inst = newInstance(constructor, parameters);
 155  854 componentMonitor.instantiated(constructor, startTime, System.currentTimeMillis() - startTime);
 156  854 return inst;
 157    } catch (InvocationTargetException e) {
 158  10 componentMonitor.instantiationFailed(constructor, e);
 159  10 if (e.getTargetException() instanceof RuntimeException) {
 160  4 throw (RuntimeException) e.getTargetException();
 161  6 } else if (e.getTargetException() instanceof Error) {
 162  2 throw (Error) e.getTargetException();
 163    }
 164  4 throw new PicoInvocationTargetInitializationException(e.getTargetException());
 165    } catch (InstantiationException e) {
 166    // can't get here because checkConcrete() will catch it earlier, but see PICO-191
 167    ///CLOVER:OFF
 168    componentMonitor.instantiationFailed(constructor, e);
 169    throw new PicoInitializationException("Should never get here");
 170    ///CLOVER:ON
 171    } catch (IllegalAccessException e) {
 172    // can't get here because either filtered or access mode set
 173    ///CLOVER:OFF
 174    componentMonitor.instantiationFailed(constructor, e);
 175    throw new PicoInitializationException(e);
 176    ///CLOVER:ON
 177    }
 178    }
 179    };
 180    }
 181  970 instantiationGuard.setArguments(container);
 182  970 return instantiationGuard.observe(getComponentImplementation());
 183    }
 184   
 185  894 protected Object[] getConstructorArguments(PicoContainer container, Constructor ctor) {
 186  894 Class[] parameterTypes = ctor.getParameterTypes();
 187  894 Object[] result = new Object[parameterTypes.length];
 188  894 Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
 189   
 190  894 for (int i = 0; i < currentParameters.length; i++) {
 191  570 result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i]);
 192    }
 193  864 return result;
 194    }
 195   
 196  848 private List getSortedMatchingConstructors() {
 197  848 List matchingConstructors = new ArrayList();
 198  848 Constructor[] allConstructors = getComponentImplementation().getDeclaredConstructors();
 199    // filter out all constructors that will definately not match
 200  848 Constructor constructor;
 201  848 for (int i = 0; i < allConstructors.length; i++) {
 202  1348 constructor = allConstructors[i];
 203  1348 if ((parameters == null || constructor.getParameterTypes().length == parameters.length)
 204    && (allowNonPublicClasses || (constructor.getModifiers() & Modifier.PUBLIC) != 0)) {
 205  1242 matchingConstructors.add(constructor);
 206    }
 207    }
 208    // optimize list of constructors moving the longest at the beginning
 209  848 if (parameters == null) {
 210  722 Collections.sort(matchingConstructors, new Comparator() {
 211  780 public int compare(Object arg0, Object arg1) {
 212  780 return ((Constructor) arg1).getParameterTypes().length - ((Constructor) arg0).getParameterTypes().length;
 213    }
 214    });
 215    }
 216  848 return matchingConstructors;
 217    }
 218    }