Clover coverage report - PicoContainer - 1.0
Coverage timestamp: Sat Jun 5 2004 21:34:14 EDT
file stats: LOC: 248   Methods: 9
NCLOC: 170   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ConstructorInjectionComponentAdapter.java 96.2% 97.8% 100% 97.4%
coverage 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.ComponentAdapter;
 14   
 import org.picocontainer.Parameter;
 15   
 import org.picocontainer.PicoInitializationException;
 16   
 import org.picocontainer.PicoIntrospectionException;
 17   
 
 18   
 import java.lang.reflect.Array;
 19   
 import java.lang.reflect.Constructor;
 20   
 import java.lang.reflect.InvocationTargetException;
 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   
  * <p/>
 32   
  * <em>
 33   
  * Note that this class doesn't cache instances. If you want caching,
 34   
  * use a {@link CachingComponentAdapter} around this one.
 35   
  * </em>
 36   
  *
 37   
  * @author Paul Hammant
 38   
  * @author Aslak Helles&oslash;y
 39   
  * @author Jon Tirs&eacute;n
 40   
  * @author Zohar Melamed
 41   
  * @author J&ouml;rg Schaible
 42   
  * @version $Revision: 1.13 $
 43   
  */
 44   
 public class ConstructorInjectionComponentAdapter extends InstantiatingComponentAdapter {
 45   
     private transient boolean instantiating;
 46   
     private transient List sortedMatchingConstructors;
 47   
 
 48   
     /**
 49   
      * Explicitly specifies parameters. If parameters are null, default parameters
 50   
      * will be used.
 51   
      */
 52  229
     public ConstructorInjectionComponentAdapter(final Object componentKey,
 53   
                                                 final Class componentImplementation,
 54   
                                                 Parameter[] parameters,
 55   
                                                 boolean allowNonPublicClasses) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 56  229
         super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
 57   
     }
 58   
 
 59  222
     public ConstructorInjectionComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters) {
 60  222
         this(componentKey, componentImplementation, parameters, false);
 61   
     }
 62   
 
 63   
     /**
 64   
      * Use default parameters.
 65   
      */
 66  14
     public ConstructorInjectionComponentAdapter(Object componentKey,
 67   
                                                 Class componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 68  14
         this(componentKey, componentImplementation, null);
 69   
     }
 70   
 
 71  215
     protected Constructor getGreediestSatisifableConstructor(List adapterInstantiationOrderTrackingList) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 72  215
         Constructor greediestConstructor = null;
 73  215
         final Set conflicts = new HashSet();
 74  215
         final Set unsatisfiableDependencyTypes = new HashSet();
 75  215
         if (sortedMatchingConstructors == null) {
 76  187
             sortedMatchingConstructors = getSortedMatchingConstructors();
 77   
         }
 78  215
         for (int i = 0; i < sortedMatchingConstructors.size(); i++) {
 79  430
             List adapterDependencies = new ArrayList();
 80  430
             boolean failedDependency = false;
 81  430
             Constructor constructor = (Constructor) sortedMatchingConstructors.get(i);
 82  430
             Class[] parameterTypes = constructor.getParameterTypes();
 83  430
             Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
 84   
 //            Type[] genericParameterTypes = constructor.getGenericParameterTypes();
 85   
 
 86   
             // remember: all constructors with less arguments than the given parameters are filtered out already
 87  430
             for (int j = 0; j < currentParameters.length; j++) {
 88  580
                 ComponentAdapter adapter = currentParameters[j].resolveAdapter(getContainer(), parameterTypes[j]);
 89  578
                 if (adapter == null) {
 90   
                     // perhaps it is an array or a generic collection
 91  381
                     if (parameterTypes[j].getComponentType() != null) {
 92  130
                         ComponentAdapter genericCollectionComponentAdapter = getGenericCollectionComponentAdapter(parameterTypes[j].getComponentType());
 93  130
                         if (genericCollectionComponentAdapter != null) {
 94  8
                             genericCollectionComponentAdapter.setContainer(getContainer());
 95  8
                             adapterDependencies.add(genericCollectionComponentAdapter);
 96   
                         } else {
 97  122
                             failedDependency = true;
 98  122
                             unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 99   
                         }
 100   
                     } else {
 101  251
                         failedDependency = true;
 102  251
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 103   
                     }
 104   
                 } else {
 105   
                     // we can't depend on ourself
 106  197
                     if (adapter.equals(this)) {
 107  36
                         failedDependency = true;
 108  36
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 109  161
                     } else if (getComponentKey().equals(adapter.getComponentKey())) {
 110  8
                         failedDependency = true;
 111  8
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 112   
                     } else {
 113  153
                         adapterDependencies.add(adapter);
 114   
                     }
 115   
                 }
 116   
             }
 117  428
             if (!failedDependency) {
 118  204
                 if (conflicts.size() == 0 && greediestConstructor == null) {
 119  197
                     greediestConstructor = constructor;
 120  197
                     adapterInstantiationOrderTrackingList.addAll(adapterDependencies);
 121  7
                 } else if (conflicts.size() == 0 && greediestConstructor.getParameterTypes().length > parameterTypes.length) {
 122   
                     // remember: we're sorted by length, therefore we've already found the optimal constructor
 123  5
                     break;
 124   
                 } else {
 125  2
                     if (greediestConstructor != null) {
 126  1
                         conflicts.add(greediestConstructor);
 127  1
                         greediestConstructor = null;
 128   
                     }
 129  2
                     conflicts.add(constructor);
 130  2
                     adapterInstantiationOrderTrackingList.clear();
 131   
                 }
 132   
             }
 133   
         }
 134  213
         if (!conflicts.isEmpty()) {
 135  1
             throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts);
 136   
         }
 137  212
         if (greediestConstructor == null && unsatisfiableDependencyTypes.size() > 0) {
 138  15
             throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
 139   
         }
 140  197
         if (greediestConstructor == null) {
 141   
             // be nice to the user, show all constructors that were filtered out 
 142  1
             final Set nonMatching = new HashSet();
 143  1
             final Constructor[] constructors = getComponentImplementation().getDeclaredConstructors();
 144  1
             for (int i = 0; i < constructors.length; i++) {
 145  1
                 if (!sortedMatchingConstructors.contains(constructors[i])) {
 146  1
                     nonMatching.add(constructors[i]);
 147   
                 } else {
 148   
                     // TODO - will it ever get here?, is the if() bogus?
 149   
                 }
 150   
             }
 151  1
             if (nonMatching.size() > 0) {
 152  1
                 throw new PicoInitializationException("The specified parameters do not match any of the following constructors: " + nonMatching.toString() + " for '" + getComponentImplementation() + "'");
 153   
             } else {
 154  0
                 throw new PicoInitializationException("There are no public constructors for '" + getComponentImplementation() + "'");
 155   
             }
 156   
         }
 157  196
         return greediestConstructor;
 158   
     }
 159   
 
 160  130
     private ComponentAdapter getGenericCollectionComponentAdapter(Class componentType) {
 161  130
         if (getContainer().getComponentAdaptersOfType(componentType).size() == 0) {
 162  122
             return null;
 163   
         } else {
 164  8
             Object componentKey = new Object[]{this, componentType};
 165  8
             return new GenericCollectionComponentAdapter(componentKey, null, componentType, Array.class);
 166   
         }
 167   
     }
 168   
 
 169   
 //    private ComponentAdapter getGenericCollectionComponentAdapter(Class parameterType, Type genericType) {
 170   
 //        ComponentAdapter result = null;
 171   
 //
 172   
 //        boolean isMap = Map.class.isAssignableFrom(parameterType);
 173   
 //        boolean isCollection = Collection.class.isAssignableFrom(parameterType);
 174   
 //        if((isMap || isCollection) && genericType instanceof ParameterizedType) {
 175   
 //            ParameterizedType parameterizedType = (ParameterizedType) genericType;
 176   
 //            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
 177   
 //            Class keyType = null;
 178   
 //            Class valueType = null;
 179   
 //            if(isMap) {
 180   
 //                keyType = (Class) actualTypeArguments[0];
 181   
 //                valueType = (Class) actualTypeArguments[1];
 182   
 //            } else {
 183   
 //                valueType = (Class) actualTypeArguments[0];
 184   
 //            }
 185   
 //            Object componentKey = new Object[]{this, genericType};
 186   
 //            result = new GenericCollectionComponentAdapter(componentKey, keyType, valueType, parameterType);
 187   
 //        }
 188   
 //        return result;
 189   
 //    }
 190   
 
 191  200
     protected Object instantiateComponent(List adapterInstantiationOrderTrackingList) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 192  200
         try {
 193  200
             Constructor constructor = getGreediestSatisifableConstructor(adapterInstantiationOrderTrackingList);
 194  187
             if (instantiating) {
 195  3
                 throw new CyclicDependencyException(constructor.getParameterTypes());
 196   
             }
 197  184
             instantiating = true;
 198  184
             Object[] parameters = getConstructorArguments(adapterInstantiationOrderTrackingList);
 199   
 
 200  179
             return newInstance(constructor, parameters);
 201   
         } catch (InvocationTargetException e) {
 202  4
             if (e.getTargetException() instanceof RuntimeException) {
 203  2
                 throw (RuntimeException) e.getTargetException();
 204  2
             } else if (e.getTargetException() instanceof Error) {
 205  1
                 throw (Error) e.getTargetException();
 206   
             }
 207  1
             throw new PicoInvocationTargetInitializationException(e.getTargetException()); // <here>
 208   
         } catch (InstantiationException e) {
 209   
             // Handled by prior invocation of checkConcrete() is superclass. Caught and rethrown in line marked <here> above.
 210  0
             throw new RuntimeException("Should never get here");
 211   
         } catch (IllegalAccessException e) {
 212  1
             throw new PicoInitializationException(e);
 213   
         } finally {
 214  200
             instantiating = false;
 215   
         }
 216   
     }
 217   
 
 218  184
     protected Object[] getConstructorArguments(List adapterDependencies) {
 219  184
         Object[] result = new Object[adapterDependencies.size()];
 220  184
         for (int i = 0; i < adapterDependencies.size(); i++) {
 221  109
             ComponentAdapter adapterDependency = (ComponentAdapter) adapterDependencies.get(i);
 222  109
             result[i] = adapterDependency.getComponentInstance();
 223   
         }
 224  179
         return result;
 225   
     }
 226   
 
 227  187
     private List getSortedMatchingConstructors() {
 228  187
         List matchingConstructors = new ArrayList();
 229  187
         Constructor[] allConstructors = getComponentImplementation().getDeclaredConstructors();
 230   
         // filter out all constructors that will definately not match 
 231  187
         for (int i = 0; i < allConstructors.length; i++) {
 232  330
             Constructor constructor = allConstructors[i];
 233  330
             if (parameters == null || constructor.getParameterTypes().length == parameters.length) {
 234  298
                 matchingConstructors.add(constructor);
 235   
             }
 236   
         }
 237   
         // optimize list of constructors moving the longest at the beginning
 238  187
         if (parameters == null) {
 239  166
             Collections.sort(matchingConstructors, new Comparator() {
 240  173
                 public int compare(Object arg0, Object arg1) {
 241  173
                     return ((Constructor) arg1).getParameterTypes().length - ((Constructor) arg0).getParameterTypes().length;
 242   
                 }
 243   
             });
 244   
         }
 245  187
         return matchingConstructors;
 246   
     }
 247   
 }
 248