1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.objectfactory;
35
36 import java.lang.reflect.Constructor;
37 import java.lang.reflect.InvocationTargetException;
38 import java.lang.reflect.Modifier;
39
40 import javax.inject.Inject;
41
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49 public class ObjectManufacturer {
50
51 private static final Logger log = LoggerFactory.getLogger(ObjectManufacturer.class);
52
53
54
55
56
57
58
59
60 public Object newInstance(Class<?> clazz, ParameterResolver... parameterResolvers) {
61
62 Constructor<?>[] constructors = clazz.getDeclaredConstructors();
63
64 Constructor<?> selectedConstructor = null;
65 for (Constructor<?> constructor : constructors) {
66 if (constructor.isAnnotationPresent(Inject.class)) {
67 if (selectedConstructor != null) {
68 throw new MgnlInstantiationException("Only one constructor can use @Inject [" + clazz + "]");
69 }
70 selectedConstructor = constructor;
71 }
72 }
73 if (selectedConstructor != null) {
74 selectedConstructor.setAccessible(true);
75 Object[] parameters = resolveParameters(selectedConstructor, parameterResolvers);
76 if (parameters == null) {
77 throw new MgnlInstantiationException("Unable to resolve parameters for constructor " + selectedConstructor);
78 }
79 return newInstance(selectedConstructor, parameters);
80 }
81
82
83 int bestScore = -1;
84 Object[] bestParameters = null;
85 for (Constructor<?> constructor : constructors) {
86 if (!Modifier.isPublic(constructor.getModifiers())) {
87 continue;
88 }
89 int score = constructor.getParameterTypes().length;
90 if (score < bestScore) {
91 continue;
92 }
93 Object[] parameters = resolveParameters(constructor, parameterResolvers);
94 if (parameters == null) {
95 continue;
96 }
97 selectedConstructor = constructor;
98 bestScore = score;
99 bestParameters = parameters;
100 }
101 if (selectedConstructor != null) {
102 return newInstance(selectedConstructor, bestParameters);
103 }
104 throw new MgnlInstantiationException("No suitable constructor found for class [" + clazz + "]");
105 }
106
107 private Object newInstance(Constructor constructor, Object[] parameters) {
108 try {
109 return constructor.newInstance(parameters);
110 } catch (InstantiationException e) {
111 throw new MgnlInstantiationException(e);
112 } catch (IllegalAccessException e) {
113 throw new MgnlInstantiationException(e);
114 } catch (InvocationTargetException e) {
115 throw new MgnlInstantiationException(e);
116 }
117 }
118
119 private Object[] resolveParameters(Constructor<?> constructor, ParameterResolver[] parameterResolvers) {
120 Object[] parameters = new Object[constructor.getParameterTypes().length];
121 for (int parameterIndex = 0; parameterIndex < parameters.length; parameterIndex++) {
122 ParameterInfo constructorParameter = new ParameterInfo(constructor, parameterIndex);
123 Object parameter = resolveParameter(constructorParameter, parameterResolvers);
124 if (parameter == ParameterResolver.UNRESOLVED) {
125 return null;
126 }
127 parameters[parameterIndex] = parameter;
128 }
129 return parameters;
130 }
131
132 private Object resolveParameter(ParameterInfo constructorParameter, ParameterResolver[] parameterResolvers) {
133 for (ParameterResolver parameterResolver : parameterResolvers) {
134 Object parameter = parameterResolver.resolveParameter(constructorParameter);
135 if (parameter != ParameterResolver.UNRESOLVED) {
136 return parameter;
137 }
138 }
139 log.debug("Failed to resolve {}. parameter {} in constructor of {}. Will use other constructor (if available).", (constructorParameter.getParameterIndex() + 1), constructorParameter.getParameterType(), constructorParameter.getDeclaringClass());
140 return ParameterResolver.UNRESOLVED;
141 }
142
143 }