Clover coverage report - PicoContainer - 1.1
Coverage timestamp: Thu Nov 4 2004 11:55:45 CST
file stats: LOC: 191   Methods: 10
NCLOC: 148   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 97.4% 91% 90% 92.9%
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.Parameter;
 13   
 import org.picocontainer.PicoContainer;
 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.14 $
 39   
  */
 40   
 public class SetterInjectionComponentAdapter extends InstantiatingComponentAdapter {
 41   
     private transient Guard instantiationGuard;
 42   
     private transient List setters;
 43   
     private transient List setterNames;
 44   
     private transient Class[] setterTypes;
 45   
 
 46   
     /**
 47   
      * {@inheritDoc}
 48   
      * Explicitly specifies parameters, if null uses default parameters.
 49   
      */
 50  20
     public SetterInjectionComponentAdapter(final Object componentKey,
 51   
                                            final Class componentImplementation,
 52   
                                            Parameter[] parameters,
 53   
                                            boolean allowNonPublicClasses) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 54  20
         super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
 55   
     }
 56   
 
 57  38
     public SetterInjectionComponentAdapter(final Object componentKey,
 58   
                                            final Class componentImplementation,
 59   
                                            Parameter[] parameters) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
 60  38
         super(componentKey, componentImplementation, parameters, false);
 61   
     }
 62   
 
 63  0
     protected Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 64  0
         final Constructor constructor = getConstructor();
 65  0
         getMatchingParameterListForSetters(container);
 66  0
         return constructor;
 67   
     }
 68   
     
 69  50
     private Constructor getConstructor() throws PicoInvocationTargetInitializationException {
 70  50
         final Constructor constructor;
 71  50
         try {
 72  50
             constructor = getComponentImplementation().getConstructor(null);
 73   
         } catch (NoSuchMethodException e) {
 74  2
             throw new PicoInvocationTargetInitializationException(e);
 75   
         } catch (SecurityException e) {
 76  0
             throw new PicoInvocationTargetInitializationException(e);
 77   
         }
 78   
 
 79  48
         return constructor;
 80   
     }
 81   
     
 82  56
     private Parameter[] getMatchingParameterListForSetters(PicoContainer container) throws PicoInitializationException, UnsatisfiableDependenciesException {
 83  56
         if (setters == null) {
 84  48
             initializeSetterAndTypeLists();
 85   
         }
 86   
 
 87  56
         final List matchingParameterList = new ArrayList(Collections.nCopies(setters.size(), null));
 88  56
         final Set nonMatchingParameterPositions = new HashSet();
 89  56
         final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(setterTypes);
 90  56
         for (int i = 0; i < currentParameters.length; i++) {
 91  66
             final Parameter parameter = currentParameters[i];
 92  66
             boolean failedDependency = true;
 93  66
             for (int j = 0; j < setterTypes.length; j++) {
 94  88
                 if (matchingParameterList.get(j) == null && parameter.isResolvable(container, this, setterTypes[j])) {
 95  62
                     matchingParameterList.set(j, parameter);
 96  62
                     failedDependency = false;
 97  62
                     break;
 98   
                 }
 99   
             }
 100  66
             if (failedDependency) {
 101  4
                 nonMatchingParameterPositions.add(new Integer(i));
 102   
             }
 103   
         }
 104   
 
 105  56
         final Set unsatisfiableDependencyTypes = new HashSet();
 106  56
         for (int i = 0; i < matchingParameterList.size(); i++) {
 107  70
             if (matchingParameterList.get(i) == null) {
 108  8
                 unsatisfiableDependencyTypes.add(setterTypes[i]);
 109   
             }
 110   
         }
 111  56
         if (unsatisfiableDependencyTypes.size() > 0) {
 112  6
             throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
 113  50
         } else  if (nonMatchingParameterPositions.size() > 0) {
 114  0
             throw new PicoInitializationException("Following parameters do not match any of the setters for "
 115   
                     + getComponentImplementation() + ": " + nonMatchingParameterPositions.toString());
 116   
         }
 117  50
         return (Parameter[]) matchingParameterList.toArray(new Parameter[matchingParameterList.size()]);
 118   
     }
 119   
 
 120  50
     public Object getComponentInstance(final PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
 121  50
         final Constructor constructor = getConstructor();
 122  48
         if (instantiationGuard == null) {
 123  40
             instantiationGuard = new Guard() {
 124  46
                 public Object run() {
 125  46
                     final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
 126  42
                     try {
 127  42
                         final Object componentInstance = newInstance(constructor, null);
 128  36
                         for (int i = 0; i < setters.size(); i++) {
 129  38
                             final Method setter = (Method) setters.get(i);
 130  38
                             setter.invoke(componentInstance, new Object[]{matchingParameters[i].resolveInstance(guardedContainer, SetterInjectionComponentAdapter.this, setterTypes[i])});
 131   
                         }
 132  32
                         return componentInstance;
 133   
                     } catch (InvocationTargetException e) {
 134  6
                         if (e.getTargetException() instanceof RuntimeException) {
 135  2
                             throw (RuntimeException) e.getTargetException();
 136  4
                         } else if (e.getTargetException() instanceof Error) {
 137  2
                             throw (Error) e.getTargetException();
 138   
                         }
 139  2
                         throw new PicoInvocationTargetInitializationException(e.getTargetException());
 140   
                     } catch (InstantiationException e) {
 141  0
                         throw new PicoInvocationTargetInitializationException(e);
 142   
                     } catch (IllegalAccessException e) {
 143  0
                         throw new PicoInvocationTargetInitializationException(e);
 144   
                     }
 145   
                 }
 146   
             };
 147   
         }
 148  48
         instantiationGuard.setArguments(container);
 149  48
         return instantiationGuard.observe(getComponentImplementation());
 150   
     }
 151   
 
 152  12
     public void verify(final PicoContainer container) throws PicoIntrospectionException {
 153  12
         if (verifyingGuard == null) {
 154  10
             verifyingGuard = new Guard() {
 155  10
                 public Object run() {
 156  10
                     final Parameter[] currentParameters = getMatchingParameterListForSetters(guardedContainer);
 157  8
                     for (int i = 0; i < currentParameters.length; i++) {
 158  8
                         currentParameters[i].verify(container, SetterInjectionComponentAdapter.this, setterTypes[i]);
 159   
                     }
 160  4
                     return null;
 161   
                 }
 162   
             };
 163   
         }
 164  12
         verifyingGuard.setArguments(container);
 165  12
         verifyingGuard.observe(getComponentImplementation());
 166   
     }
 167   
     
 168  48
     private void initializeSetterAndTypeLists() {
 169  48
         setters = new ArrayList();
 170  48
         setterNames = new ArrayList();
 171  48
         final List typeList = new ArrayList();
 172  48
         final Method[] methods = getComponentImplementation().getMethods();
 173  48
         for (int i = 0; i < methods.length; i++) {
 174  562
             final Method method = methods[i];
 175  562
             final Class[] parameterTypes = method.getParameterTypes();
 176   
             // We're only interested if there is only one parameter and the method name is bean-style.
 177  562
             if (parameterTypes.length == 1) {
 178  158
                 String methodName = method.getName();
 179  158
                 boolean isBeanStyle = methodName.length() >= 4 && methodName.startsWith("set") && Character.isUpperCase(methodName.charAt(3));
 180  158
                 if (isBeanStyle) {
 181  62
                     String attribute = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
 182  62
                     setters.add(method);
 183  62
                     setterNames.add(attribute);
 184  62
                     typeList.add(parameterTypes[0]);
 185   
                 }
 186   
             }
 187   
         }
 188  48
         setterTypes = (Class[]) typeList.toArray(new Class[0]);
 189   
     }
 190   
 }
 191