1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.reflect;
18
19 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24
25 import java.lang.reflect.Constructor;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import org.apache.commons.lang3.AbstractLangTest;
31 import org.apache.commons.lang3.ArrayUtils;
32 import org.apache.commons.lang3.math.NumberUtils;
33 import org.apache.commons.lang3.mutable.MutableObject;
34 import org.junit.jupiter.api.BeforeEach;
35 import org.junit.jupiter.api.Test;
36
37
38
39
40 public class ConstructorUtilsTest extends AbstractLangTest {
41 private static class BaseClass {}
42
43 static class PrivateClass {
44 @SuppressWarnings("unused")
45 public static class PublicInnerClass {
46 public PublicInnerClass() {
47 }
48 }
49
50 @SuppressWarnings("unused")
51 public PrivateClass() {
52 }
53 }
54
55 private static final class SubClass extends BaseClass {}
56
57 public static class TestBean {
58 private final String toString;
59 final String[] varArgs;
60
61 public TestBean() {
62 toString = "()";
63 varArgs = null;
64 }
65
66 public TestBean(final BaseClass bc, final String... s) {
67 toString = "(BaseClass, String...)";
68 varArgs = s;
69 }
70
71 public TestBean(final double d) {
72 toString = "(double)";
73 varArgs = null;
74 }
75
76 public TestBean(final int i) {
77 toString = "(int)";
78 varArgs = null;
79 }
80
81 public TestBean(final Integer i) {
82 toString = "(Integer)";
83 varArgs = null;
84 }
85
86 public TestBean(final Integer first, final int... args) {
87 toString = "(Integer, String...)";
88 varArgs = new String[args.length];
89 for (int i = 0; i < args.length; ++i) {
90 varArgs[i] = Integer.toString(args[i]);
91 }
92 }
93
94 public TestBean(final Integer i, final String... s) {
95 toString = "(Integer, String...)";
96 varArgs = s;
97 }
98
99 public TestBean(final Object o) {
100 toString = "(Object)";
101 varArgs = null;
102 }
103
104 public TestBean(final String s) {
105 toString = "(String)";
106 varArgs = null;
107 }
108
109 public TestBean(final String... s) {
110 toString = "(String...)";
111 varArgs = s;
112 }
113
114 @Override
115 public String toString() {
116 return toString;
117 }
118
119 void verify(final String str, final String[] args) {
120 assertEquals(str, toString);
121 assertArrayEquals(args, varArgs);
122 }
123 }
124
125 private final Map<Class<?>, Class<?>[]> classCache;
126
127 public ConstructorUtilsTest() {
128 classCache = new HashMap<>();
129 }
130
131
132 private void expectMatchingAccessibleConstructorParameterTypes(final Class<?> cls,
133 final Class<?>[] requestTypes, final Class<?>[] actualTypes) {
134 final Constructor<?> c = ConstructorUtils.getMatchingAccessibleConstructor(cls,
135 requestTypes);
136 assertArrayEquals(actualTypes, c.getParameterTypes(), toString(c.getParameterTypes()) + " not equals " + toString(actualTypes));
137 }
138
139 @BeforeEach
140 public void setUp() {
141 classCache.clear();
142 }
143
144 private Class<?>[] singletonArray(final Class<?> c) {
145 Class<?>[] result = classCache.get(c);
146 if (result == null) {
147 result = new Class[] { c };
148 classCache.put(c, result);
149 }
150 return result;
151 }
152
153 @Test
154 public void testConstructor() throws Exception {
155 assertNotNull(MethodUtils.class.getConstructor().newInstance());
156 }
157
158 @Test
159 public void testGetAccessibleConstructor() throws Exception {
160 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class
161 .getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
162 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.class
163 .getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
164 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.PublicInnerClass.class));
165 }
166
167 @Test
168 public void testGetAccessibleConstructorFromDescription() {
169 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class,
170 ArrayUtils.EMPTY_CLASS_ARRAY));
171 assertNull(ConstructorUtils.getAccessibleConstructor(
172 PrivateClass.class, ArrayUtils.EMPTY_CLASS_ARRAY));
173 }
174
175 @Test
176 public void testGetMatchingAccessibleMethod() {
177 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
178 ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
179 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, null,
180 ArrayUtils.EMPTY_CLASS_ARRAY);
181 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
182 singletonArray(String.class), singletonArray(String.class));
183 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
184 singletonArray(Object.class), singletonArray(Object.class));
185 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
186 singletonArray(Boolean.class), singletonArray(Object.class));
187 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
188 singletonArray(Byte.class), singletonArray(Integer.TYPE));
189 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
190 singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
191 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
192 singletonArray(Short.class), singletonArray(Integer.TYPE));
193 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
194 singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
195 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
196 singletonArray(Character.class), singletonArray(Integer.TYPE));
197 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
198 singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
199 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
200 singletonArray(Integer.class), singletonArray(Integer.class));
201 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
202 singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
203 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
204 singletonArray(Long.class), singletonArray(Double.TYPE));
205 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
206 singletonArray(Long.TYPE), singletonArray(Double.TYPE));
207 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
208 singletonArray(Float.class), singletonArray(Double.TYPE));
209 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
210 singletonArray(Float.TYPE), singletonArray(Double.TYPE));
211 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
212 singletonArray(Double.class), singletonArray(Double.TYPE));
213 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
214 singletonArray(Double.TYPE), singletonArray(Double.TYPE));
215 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
216 new Class<?>[]{SubClass.class, String[].class},
217 new Class<?>[]{BaseClass.class, String[].class});
218 }
219
220 @Test
221 public void testInvokeConstructor() throws Exception {
222 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
223 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
224 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
225 (Object[]) null).toString());
226 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class).toString());
227 assertEquals("(String)", ConstructorUtils.invokeConstructor(
228 TestBean.class, "").toString());
229 assertEquals("(Object)", ConstructorUtils.invokeConstructor(
230 TestBean.class, new Object()).toString());
231 assertEquals("(Object)", ConstructorUtils.invokeConstructor(
232 TestBean.class, Boolean.TRUE).toString());
233 assertEquals("(Integer)", ConstructorUtils.invokeConstructor(
234 TestBean.class, NumberUtils.INTEGER_ONE).toString());
235 assertEquals("(int)", ConstructorUtils.invokeConstructor(
236 TestBean.class, NumberUtils.BYTE_ONE).toString());
237 assertEquals("(double)", ConstructorUtils.invokeConstructor(
238 TestBean.class, NumberUtils.LONG_ONE).toString());
239 assertEquals("(double)", ConstructorUtils.invokeConstructor(
240 TestBean.class, NumberUtils.DOUBLE_ONE).toString());
241 ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.INTEGER_ONE)
242 .verify("(Integer)", null);
243 ConstructorUtils.invokeConstructor(TestBean.class, "a", "b")
244 .verify("(String...)", new String[]{"a", "b"});
245 ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.INTEGER_ONE, "a", "b")
246 .verify("(Integer, String...)", new String[]{"a", "b"});
247 ConstructorUtils.invokeConstructor(TestBean.class, new SubClass(), new String[]{"a", "b"})
248 .verify("(BaseClass, String...)", new String[]{"a", "b"});
249 }
250
251 @Test
252 public void testInvokeExactConstructor() throws Exception {
253 assertEquals("()", ConstructorUtils.invokeExactConstructor(
254 TestBean.class, (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
255 assertEquals("()", ConstructorUtils.invokeExactConstructor(
256 TestBean.class, (Object[]) null).toString());
257 assertEquals("(String)", ConstructorUtils.invokeExactConstructor(
258 TestBean.class, "").toString());
259 assertEquals("(Object)", ConstructorUtils.invokeExactConstructor(
260 TestBean.class, new Object()).toString());
261 assertEquals("(Integer)", ConstructorUtils.invokeExactConstructor(
262 TestBean.class, NumberUtils.INTEGER_ONE).toString());
263 assertEquals("(double)", ConstructorUtils.invokeExactConstructor(
264 TestBean.class, new Object[] { NumberUtils.DOUBLE_ONE },
265 new Class[] { Double.TYPE }).toString());
266
267 assertThrows(
268 NoSuchMethodException.class,
269 () -> ConstructorUtils.invokeExactConstructor(TestBean.class, NumberUtils.BYTE_ONE));
270 assertThrows(
271 NoSuchMethodException.class,
272 () -> ConstructorUtils.invokeExactConstructor(TestBean.class, NumberUtils.LONG_ONE));
273 assertThrows(
274 NoSuchMethodException.class,
275 () -> ConstructorUtils.invokeExactConstructor(TestBean.class, Boolean.TRUE));
276 }
277
278 @Test
279 public void testNullArgument() {
280 expectMatchingAccessibleConstructorParameterTypes(MutableObject.class,
281 singletonArray(null), singletonArray(Object.class));
282 }
283
284 @Test
285 public void testVarArgsUnboxing() throws Exception {
286 final TestBean testBean = ConstructorUtils.invokeConstructor(
287 TestBean.class, Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3));
288
289 assertArrayEquals(new String[]{"2", "3"}, testBean.varArgs);
290 }
291
292 private String toString(final Class<?>[] c) {
293 return Arrays.asList(c).toString();
294 }
295
296 }