|
|||||||||||||||||||
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 | |||||||||||||||
BeanStyleComponentFactory.java | 90% | 81.2% | 100% | 84.4% |
|
1 |
package picocontainer.extras;
|
|
2 |
|
|
3 |
import picocontainer.ComponentFactory;
|
|
4 |
import picocontainer.PicoInstantiationException;
|
|
5 |
import picocontainer.PicoIntrospectionException;
|
|
6 |
|
|
7 |
import java.lang.reflect.Method;
|
|
8 |
import java.lang.reflect.InvocationTargetException;
|
|
9 |
import java.util.List;
|
|
10 |
import java.util.ArrayList;
|
|
11 |
|
|
12 |
/**
|
|
13 |
* A Component factory that works with Java Bean style components. That is, components that
|
|
14 |
* have an empty constructor and zero or more setXxx methods with one argument to set dependencies.
|
|
15 |
* Note that this ComponentFactory does not use IoC type 3, but rather a "loosely typed" IoC type 1.
|
|
16 |
* (It's loosely typed since no interfaces need to be implemented - as the presence of setXxx
|
|
17 |
* methods in the component implementation classes is enough to have these methods called).
|
|
18 |
* <em>
|
|
19 |
* This class is provided for convenience only, so components adhering to IoC type 1 can be used
|
|
20 |
* without modification. It is however recommended to use {@link picocontainer.defaults.DefaultComponentFactory}
|
|
21 |
* as the basis for component creation, as this leads to a better component design.
|
|
22 |
* </em>
|
|
23 |
*
|
|
24 |
* @author Aslak Hellesøy
|
|
25 |
* @version $Revision: 1.2 $
|
|
26 |
*/
|
|
27 |
public class BeanStyleComponentFactory implements ComponentFactory { |
|
28 | 3 |
public Object createComponent(Class componentType, Class componentImplementation, Class[] dependencies, Object[] instanceDependencies) throws PicoInstantiationException, PicoIntrospectionException { |
29 |
// We'll assume there is an empty constructor
|
|
30 | 3 |
Object result = null;
|
31 | 3 |
try {
|
32 | 3 |
result = componentImplementation.newInstance(); |
33 |
} catch (InstantiationException e) {
|
|
34 | 0 |
throw new RuntimeException("#3 Can we have a concerted effort to try to force these excptions?"); |
35 |
} catch (IllegalAccessException e) {
|
|
36 | 0 |
throw new RuntimeException("#4 Can we have a concerted effort to try to force these excptions?"); |
37 |
} |
|
38 |
|
|
39 |
// Now set the dependencies by calling appropriate methods taking the dependencies as arguments.
|
|
40 | 3 |
Method[] setters = getSetters(componentImplementation); |
41 | 3 |
if (setters.length != instanceDependencies.length) {
|
42 | 0 |
throw new IllegalStateException("Unmatching number of dependencies: " + setters.length + " vs " + instanceDependencies.length); |
43 |
} |
|
44 |
// List arguments = new ArrayList(Arrays.asList(instanceDependencies));
|
|
45 | 3 |
for (int i = 0; i < setters.length; i++) { |
46 | 2 |
Method setter = setters[i]; |
47 |
// Object argument = extractArgument(arguments,setter);
|
|
48 |
// We can assume order is correct.
|
|
49 | 2 |
Object argument = instanceDependencies[i]; |
50 | 2 |
try {
|
51 | 2 |
setter.invoke(result, new Object[]{argument});
|
52 |
} catch (IllegalAccessException e) {
|
|
53 | 0 |
throw new RuntimeException("#5 Can we have a concerted effort to try to force these excptions?"); |
54 |
} catch (IllegalArgumentException e) {
|
|
55 | 0 |
throw new RuntimeException("#6 Can we have a concerted effort to try to force these excptions?"); |
56 |
} catch (InvocationTargetException e) {
|
|
57 | 0 |
throw new RuntimeException("#7 Can we have a concerted effort to try to force these excptions?"); |
58 |
} |
|
59 |
} |
|
60 | 3 |
return result;
|
61 |
} |
|
62 |
|
|
63 |
/*
|
|
64 |
Not necessary, since we can assume order is correct.
|
|
65 |
|
|
66 |
private Object extractArgument(List arguments, Method setter) throws NoArgumentForSetterException {
|
|
67 |
for (Iterator iterator = arguments.iterator(); iterator.hasNext();) {
|
|
68 |
Object argumentCandidate = iterator.next();
|
|
69 |
if( setter.getParameterTypes()[0].isAssignableFrom(argumentCandidate.getClass())) {
|
|
70 |
// Got it. Remove it so we don't use it again.
|
|
71 |
iterator.remove();
|
|
72 |
return argumentCandidate;
|
|
73 |
}
|
|
74 |
}
|
|
75 |
// We didn't find one. That's bad.
|
|
76 |
throw new NoArgumentForSetterException(setter);
|
|
77 |
}
|
|
78 |
*/
|
|
79 |
|
|
80 |
/**
|
|
81 |
* {@inheritDoc}
|
|
82 |
*
|
|
83 |
* The dependencies are resolved by looking at the types of all setXxx methods
|
|
84 |
* taking one parameter.
|
|
85 |
*
|
|
86 |
* @param componentImplementation
|
|
87 |
* @return all classes that are defined in setXxx methods taking one argument.
|
|
88 |
* @throws PicoIntrospectionException
|
|
89 |
*/
|
|
90 | 4 |
public Class[] getDependencies(Class componentImplementation) throws PicoIntrospectionException { |
91 |
// TODO use caching.
|
|
92 | 4 |
Method[] setters = getSetters(componentImplementation); |
93 | 4 |
Class[] result = new Class[setters.length];
|
94 | 4 |
for (int i = 0; i < result.length; i++) { |
95 | 2 |
result[i] = setters[i].getParameterTypes()[0]; |
96 |
} |
|
97 | 4 |
return result;
|
98 |
} |
|
99 |
|
|
100 | 7 |
private Method[] getSetters(Class componentImplementation) {
|
101 |
// TODO use caching.
|
|
102 | 7 |
List setters = new ArrayList();
|
103 | 7 |
Method[] methods = componentImplementation.getMethods(); |
104 | 7 |
for (int i = 0; i < methods.length; i++) { |
105 | 71 |
Method method = methods[i]; |
106 | 71 |
Class[] parameterTypes = method.getParameterTypes(); |
107 |
// We're only interested if there is only one parameter and the method name is bean-style.
|
|
108 | 71 |
boolean hasOneParameter = parameterTypes.length == 1;
|
109 | 71 |
boolean isBeanStyle = method.getName().length() >= 4 && method.getName().startsWith("set") && Character.isUpperCase(method.getName().charAt(3)); |
110 | 71 |
if (hasOneParameter && isBeanStyle) {
|
111 | 4 |
setters.add(method); |
112 |
} |
|
113 |
} |
|
114 | 7 |
return (Method[]) setters.toArray(new Method[setters.size()]); |
115 |
} |
|
116 |
} |
|
117 |
|
|