Clover coverage report - PicoContainer - 1.0-RC-1
Coverage timestamp: Tue May 18 2004 16:19:33 EDT
file stats: LOC: 246   Methods: 8
NCLOC: 167   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 98.1% 97.8% 100% 98%
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.11 $
 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  235
     public ConstructorInjectionComponentAdapter(final Object componentKey,
 53   
                                        final Class componentImplementation,
 54   
                                        Parameter[] parameters) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 55  235
         super(componentKey, componentImplementation, parameters);
 56   
     }
 57   
 
 58   
     /**
 59   
      * Use default parameters.
 60   
      */
 61  17
     public ConstructorInjectionComponentAdapter(Object componentKey,
 62   
                                        Class componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 63  17
         this(componentKey, componentImplementation, null);
 64   
     }
 65   
 
 66  220
     protected Constructor getGreediestSatisifableConstructor(List adapterInstantiationOrderTrackingList) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 67  220
         Constructor greediestConstructor = null;
 68  220
         final Set conflicts = new HashSet();
 69  220
         final Set unsatisfiableDependencyTypes = new HashSet();
 70  220
         if(sortedMatchingConstructors == null) {
 71  192
             sortedMatchingConstructors = getSortedMatchingConstructors();
 72   
         }
 73  220
         for (int i = 0; i < sortedMatchingConstructors.size(); i++) {
 74  427
             List adapterDependencies = new ArrayList();
 75  427
             boolean failedDependency = false;
 76  427
             Constructor constructor = (Constructor) sortedMatchingConstructors.get(i);
 77  427
             Class[] parameterTypes = constructor.getParameterTypes();
 78  427
             Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
 79   
 //            Type[] genericParameterTypes = constructor.getGenericParameterTypes();
 80   
 
 81   
             // remember: all constructors with less arguments than the given parameters are filtered out already
 82  427
             for (int j = 0; j < currentParameters.length; j++) {
 83  547
                 ComponentAdapter adapter = currentParameters[j].resolveAdapter(getContainer(), parameterTypes[j]);
 84  545
                 if (adapter == null) {
 85   
                     // perhaps it is an array or a generic collection
 86  341
                     if (parameterTypes[j].getComponentType() != null) {
 87  115
                         ComponentAdapter genericCollectionComponentAdapter = getGenericCollectionComponentAdapter(parameterTypes[j].getComponentType());
 88  115
                         if (genericCollectionComponentAdapter != null) {
 89  6
                             genericCollectionComponentAdapter.setContainer(getContainer());
 90  6
                             adapterDependencies.add(genericCollectionComponentAdapter);
 91   
                         } else {
 92  109
                             failedDependency = true;
 93  109
                             unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 94   
                         }
 95   
                     } else {
 96  226
                         failedDependency = true;
 97  226
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 98   
                     }
 99   
                 } else {
 100   
                     // we can't depend on ourself
 101  204
                     if (adapter.equals(this)) {
 102  36
                         failedDependency = true;
 103  36
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 104  168
                     } else if (getComponentKey().equals(adapter.getComponentKey())) {
 105  11
                         failedDependency = true;
 106  11
                         unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
 107   
                     } else {
 108  157
                         adapterDependencies.add(adapter);
 109   
                     }
 110   
                 }
 111   
             }
 112  425
             if (!failedDependency) {
 113  210
                 if(conflicts.size() == 0 && greediestConstructor == null) {
 114  203
                     greediestConstructor = constructor;
 115  203
                     adapterInstantiationOrderTrackingList.addAll(adapterDependencies);
 116  7
                 } else if (conflicts.size() == 0 && greediestConstructor.getParameterTypes().length > parameterTypes.length) {
 117   
                     // remember: we're sorted by length, therefore we've already found the optimal constructor
 118  5
                     break;
 119   
                 } else {
 120  2
                     if (greediestConstructor != null) {
 121  1
                         conflicts.add(greediestConstructor);
 122  1
                         greediestConstructor = null;
 123   
                     }
 124  2
                     conflicts.add(constructor);
 125  2
                     adapterInstantiationOrderTrackingList.clear();
 126   
                 }
 127   
             }
 128   
         }
 129  218
         if (!conflicts.isEmpty()) {
 130  1
             throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts);
 131   
         }
 132  217
         if (greediestConstructor == null && unsatisfiableDependencyTypes.size() > 0) {
 133  13
             throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
 134   
         }
 135  204
         if (greediestConstructor == null) {
 136   
             // be nice to the user, show all constructors that were filtered out 
 137  2
             final Set nonMatching = new HashSet();
 138  2
             final Constructor[] constructors = getComponentImplementation().getConstructors();
 139  2
             for (int i = 0; i < constructors.length; i++) {
 140  1
                 if (!sortedMatchingConstructors.contains(constructors[i])) {
 141  1
                     nonMatching.add(constructors[i]);
 142   
                 } else {
 143   
                     // TODO - will it ever get here?, is the if() bogus?
 144   
                 }
 145   
             }
 146  2
             if (nonMatching.size() > 0) {
 147  1
                 throw new PicoInitializationException("The specified parameters do not match any of the following constructors: " + nonMatching.toString() + " for '" + getComponentImplementation() + "'");
 148   
             } else {
 149  1
                 throw new PicoInitializationException("There are no public constructors for '" + getComponentImplementation() + "'");
 150   
             }
 151   
         }
 152  202
         return greediestConstructor;
 153   
     }
 154   
 
 155  115
     private ComponentAdapter getGenericCollectionComponentAdapter(Class componentType) {
 156  115
         GenericCollectionComponentAdapter result = null;
 157   
 
 158  115
         if(getContainer().getComponentAdaptersOfType(componentType).size() == 0) {
 159  109
             return null;
 160   
         } else {
 161  6
             Object componentKey = new Object[]{this, componentType};
 162  6
             return new GenericCollectionComponentAdapter(componentKey, null, componentType, Array.class);
 163   
         }
 164   
     }
 165   
 
 166   
 //    private ComponentAdapter getGenericCollectionComponentAdapter(Class parameterType, Type genericType) {
 167   
 //        ComponentAdapter result = null;
 168   
 //
 169   
 //        boolean isMap = Map.class.isAssignableFrom(parameterType);
 170   
 //        boolean isCollection = Collection.class.isAssignableFrom(parameterType);
 171   
 //        if((isMap || isCollection) && genericType instanceof ParameterizedType) {
 172   
 //            ParameterizedType parameterizedType = (ParameterizedType) genericType;
 173   
 //            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
 174   
 //            Class keyType = null;
 175   
 //            Class valueType = null;
 176   
 //            if(isMap) {
 177   
 //                keyType = (Class) actualTypeArguments[0];
 178   
 //                valueType = (Class) actualTypeArguments[1];
 179   
 //            } else {
 180   
 //                valueType = (Class) actualTypeArguments[0];
 181   
 //            }
 182   
 //            Object componentKey = new Object[]{this, genericType};
 183   
 //            result = new GenericCollectionComponentAdapter(componentKey, keyType, valueType, parameterType);
 184   
 //        }
 185   
 //        return result;
 186   
 //    }
 187   
 
 188  205
     protected Object instantiateComponent(List adapterInstantiationOrderTrackingList) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 189  205
         try {
 190  205
             Constructor constructor = getGreediestSatisifableConstructor(adapterInstantiationOrderTrackingList);
 191  193
             if (instantiating) {
 192  3
                 throw new CyclicDependencyException(constructor.getParameterTypes());
 193   
             }
 194  190
             instantiating = true;
 195  190
             Object[] parameters = getConstructorArguments(adapterInstantiationOrderTrackingList);
 196   
 
 197  185
             return constructor.newInstance(parameters);
 198   
         } catch (InvocationTargetException e) {
 199  4
             if (e.getTargetException() instanceof RuntimeException) {
 200  2
                 throw (RuntimeException) e.getTargetException();
 201  2
             } else if (e.getTargetException() instanceof Error) {
 202  1
                 throw (Error) e.getTargetException();
 203   
             }
 204  1
             throw new PicoInvocationTargetInitializationException(e.getTargetException()); // <here>
 205   
         } catch (InstantiationException e) {
 206   
             // Handled by prior invocation of checkConcrete() is superclass. Caught and rethrown in line marked <here> above.
 207  0
             throw new RuntimeException("Should never get here");
 208   
         } catch (IllegalAccessException 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   
         } finally {
 212  205
             instantiating = false;
 213   
         }
 214   
     }
 215   
     
 216  190
     protected Object[] getConstructorArguments(List adapterDependencies) {
 217  190
         Object[] result = new Object[adapterDependencies.size()];
 218  190
         for (int i = 0; i < adapterDependencies.size(); i++) {
 219  114
             ComponentAdapter adapterDependency = (ComponentAdapter) adapterDependencies.get(i);
 220  114
             result[i] = adapterDependency.getComponentInstance();
 221   
         }
 222  185
         return result;
 223   
     }
 224   
     
 225  192
     private List getSortedMatchingConstructors() {
 226  192
         List matchingConstructors = new ArrayList();
 227  192
         Constructor[] allConstructors = getComponentImplementation().getConstructors();
 228   
         // filter out all constructors that will definately not match 
 229  192
         for (int i = 0; i < allConstructors.length; i++) {
 230  333
             Constructor constructor = allConstructors[i];
 231  333
             if (parameters == null || constructor.getParameterTypes().length == parameters.length) {
 232  303
                 matchingConstructors.add(constructor);
 233   
             }
 234   
         }
 235   
         // optimize list of constructors moving the longest at the beginning
 236  192
         if (parameters == null) {
 237  171
             Collections.sort(matchingConstructors, new Comparator() {
 238  161
                 public int compare(Object arg0, Object arg1) {
 239  161
                     return ((Constructor)arg1).getParameterTypes().length - ((Constructor)arg0).getParameterTypes().length;
 240   
                 }
 241   
             });
 242   
         }
 243  192
         return matchingConstructors;
 244   
     }
 245   
 }
 246