Clover coverage report - PicoContainer - 1.0
Coverage timestamp: Sat Jun 5 2004 21:34:14 EDT
file stats: LOC: 176   Methods: 5
NCLOC: 128   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
SetterInjectionComponentAdapter.java 82.4% 85.5% 100% 85.2%
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   
  * Original code by                                                          *
 9   
  *****************************************************************************/
 10   
 package org.picocontainer.defaults;
 11   
 
 12   
 import org.picocontainer.ComponentAdapter;
 13   
 import org.picocontainer.Parameter;
 14   
 import org.picocontainer.PicoInitializationException;
 15   
 import org.picocontainer.PicoIntrospectionException;
 16   
 
 17   
 import java.lang.reflect.Constructor;
 18   
 import java.lang.reflect.InvocationTargetException;
 19   
 import java.lang.reflect.Method;
 20   
 import java.util.ArrayList;
 21   
 import java.util.Collections;
 22   
 import java.util.HashSet;
 23   
 import java.util.List;
 24   
 import java.util.Set;
 25   
 
 26   
 /**
 27   
  * Instantiates components using empty constructors and
 28   
  * <a href="http://docs.codehaus.org/display/PICO/Setter+Injection">Setter Injection</a>.
 29   
  * For easy setting of primitive properties, also see {@link BeanPropertyComponentAdapter}.
 30   
  * <p/>
 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 Aslak Helles&oslash;y
 37   
  * @author J&ouml;rg Schaible
 38   
  * @version $Revision: 1.6 $
 39   
  */
 40   
 public class SetterInjectionComponentAdapter extends InstantiatingComponentAdapter {
 41   
     private transient boolean instantiating;
 42   
     private transient List setters;
 43   
     private transient List setterNames;
 44   
     private transient Class[] setterTypes;
 45   
 
 46   
     /**
 47   
      * Explicitly specifies parameters, if null uses default parameters.
 48   
      * {@inheritDoc}
 49   
      */
 50  13
     public SetterInjectionComponentAdapter(final Object componentKey,
 51   
                                            final Class componentImplementation,
 52   
                                            Parameter[] parameters,
 53   
                                            boolean allowNonPublicClasses) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 54  13
         super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
 55   
     }
 56   
 
 57  9
     public SetterInjectionComponentAdapter(final Object componentKey,
 58   
                                            final Class componentImplementation,
 59   
                                            Parameter[] parameters) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 60  9
         super(componentKey, componentImplementation, parameters, false);
 61   
     }
 62   
 
 63   
     /**
 64   
      * @see org.picocontainer.defaults.InstantiatingComponentAdapter#getGreediestSatisifableConstructor(java.util.List)
 65   
      */
 66  19
     protected Constructor getGreediestSatisifableConstructor(List adapterInstantiationOrderTrackingList) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 67  19
         final Constructor constructor;
 68  19
         try {
 69  19
             constructor = getComponentImplementation().getConstructor(null);
 70   
         } catch (NoSuchMethodException e) {
 71  1
             throw new PicoInvocationTargetInitializationException(e);
 72   
         } catch (SecurityException e) {
 73  0
             throw new PicoInvocationTargetInitializationException(e);
 74   
         }
 75   
 
 76  18
         if (setters == null) {
 77  17
             initializeSetterAndTypeLists();
 78   
         }
 79   
 
 80  18
         final List matchingTypeList = new ArrayList(Collections.nCopies(setters.size(), null));
 81  18
         final Set nonMatchingParameterPositions = new HashSet();
 82  18
         final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(setterTypes);
 83  18
         for (int i = 0; i < currentParameters.length; i++) {
 84  34
             final Parameter parameter = currentParameters[i];
 85  34
             boolean failedDependency = true;
 86  34
             for (int j = 0; j < setterTypes.length; j++) {
 87  66
                 if (matchingTypeList.get(j) == null) {
 88  36
                     final ComponentAdapter adapter = parameter.resolveAdapter(getContainer(), setterTypes[j]);
 89  36
                     if (adapter != null && !adapter.equals(this) && !getComponentKey().equals(adapter.getComponentKey())) {
 90  32
                         matchingTypeList.set(j, adapter);
 91  32
                         failedDependency = false;
 92  32
                         break;
 93   
                     }
 94   
                 }
 95   
             }
 96  34
             if (failedDependency) {
 97  2
                 nonMatchingParameterPositions.add(new Integer(i));
 98   
             }
 99   
         }
 100   
 
 101  18
         final Set unsatisfiableDependencyTypes = new HashSet();
 102  18
         for (int i = 0; i < matchingTypeList.size(); i++) {
 103  34
             if (matchingTypeList.get(i) == null) {
 104  2
                 unsatisfiableDependencyTypes.add(setterTypes[i]);
 105   
             }
 106   
         }
 107  18
         if (unsatisfiableDependencyTypes.size() > 0) {
 108  1
             throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
 109   
         }
 110   
 
 111  17
         if (nonMatchingParameterPositions.size() > 0) {
 112  0
             throw new PicoInitializationException("Following parameters do not match any of the setters for "
 113   
                     + getComponentImplementation() + ": " + nonMatchingParameterPositions.toString());
 114   
         }
 115  17
         adapterInstantiationOrderTrackingList.addAll(matchingTypeList);
 116  17
         return constructor;
 117   
     }
 118   
 
 119   
     /**
 120   
      * @see org.picocontainer.defaults.InstantiatingComponentAdapter#instantiateComponent(java.util.List)
 121   
      */
 122  19
     protected Object instantiateComponent(List adapterInstantiationOrderTrackingList) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 123  19
         try {
 124  19
             final Constructor constructor = getGreediestSatisifableConstructor(adapterInstantiationOrderTrackingList);
 125  17
             if (instantiating) {
 126  0
                 throw new CyclicDependencyException(setterTypes);
 127   
             }
 128  17
             instantiating = true;
 129  17
             final Object componentInstance = newInstance(constructor, null);
 130  17
             for (int i = 0; i < setters.size(); i++) {
 131  31
                 final Method setter = (Method) setters.get(i);
 132  31
                 final ComponentAdapter adapter = (ComponentAdapter) adapterInstantiationOrderTrackingList.get(i);
 133  31
                 setter.invoke(componentInstance, new Object[]{adapter.getComponentInstance()});
 134   
             }
 135   
 
 136  17
             return componentInstance;
 137   
         } catch (InvocationTargetException e) {
 138  0
             if (e.getTargetException() instanceof RuntimeException) {
 139  0
                 throw (RuntimeException) e.getTargetException();
 140  0
             } else if (e.getTargetException() instanceof Error) {
 141  0
                 throw (Error) e.getTargetException();
 142   
             }
 143  0
             throw new PicoInvocationTargetInitializationException(e.getTargetException());
 144   
         } catch (InstantiationException e) {
 145  0
             throw new PicoInvocationTargetInitializationException(e);
 146   
         } catch (IllegalAccessException e) {
 147  0
             throw new PicoInvocationTargetInitializationException(e);
 148   
         } finally {
 149  19
             instantiating = false;
 150   
         }
 151   
     }
 152   
 
 153  17
     private void initializeSetterAndTypeLists() {
 154  17
         setters = new ArrayList();
 155  17
         setterNames = new ArrayList();
 156  17
         final List typeList = new ArrayList();
 157  17
         final Method[] methods = getComponentImplementation().getMethods();
 158  17
         for (int i = 0; i < methods.length; i++) {
 159  228
             final Method method = methods[i];
 160  228
             final Class[] parameterTypes = method.getParameterTypes();
 161   
             // We're only interested if there is only one parameter and the method name is bean-style.
 162  228
             if (parameterTypes.length == 1) {
 163  68
                 String methodName = method.getName();
 164  68
                 boolean isBeanStyle = methodName.length() >= 4 && methodName.startsWith("set") && Character.isUpperCase(methodName.charAt(3));
 165  68
                 if (isBeanStyle) {
 166  34
                     String attribute = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
 167  34
                     setters.add(method);
 168  34
                     setterNames.add(attribute);
 169  34
                     typeList.add(parameterTypes[0]);
 170   
                 }
 171   
             }
 172   
         }
 173  17
         setterTypes = (Class[]) typeList.toArray(new Class[0]);
 174   
     }
 175   
 }
 176