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
44 static class PrivateClass {
45 @SuppressWarnings("unused")
46 public static class PublicInnerClass {
47 public PublicInnerClass() {
48 }
49 }
50
51 @SuppressWarnings("unused")
52 public PrivateClass() {
53 }
54 }
55
56 private static final class SubClass extends BaseClass {
57 }
58
59 public static class TestBean {
60 private final String toString;
61 final String[] varArgs;
62
63 public TestBean() {
64 toString = "()";
65 varArgs = null;
66 }
67
68 public TestBean(final BaseClass bc, final String... s) {
69 toString = "(BaseClass, String...)";
70 varArgs = s;
71 }
72
73 public TestBean(final double d) {
74 toString = "(double)";
75 varArgs = null;
76 }
77
78 public TestBean(final int i) {
79 toString = "(int)";
80 varArgs = null;
81 }
82
83 public TestBean(final Integer i) {
84 toString = "(Integer)";
85 varArgs = null;
86 }
87
88 public TestBean(final Integer first, final int... args) {
89 toString = "(Integer, String...)";
90 varArgs = new String[args.length];
91 for (int i = 0; i < args.length; ++i) {
92 varArgs[i] = Integer.toString(args[i]);
93 }
94 }
95
96 public TestBean(final Integer i, final String... s) {
97 toString = "(Integer, String...)";
98 varArgs = s;
99 }
100
101 public TestBean(final Object o) {
102 toString = "(Object)";
103 varArgs = null;
104 }
105
106 public TestBean(final String s) {
107 toString = "(String)";
108 varArgs = null;
109 }
110
111 public TestBean(final String... s) {
112 toString = "(String...)";
113 varArgs = s;
114 }
115
116 @Override
117 public String toString() {
118 return toString;
119 }
120
121 void verify(final String str, final String[] args) {
122 assertEquals(str, toString);
123 assertArrayEquals(args, varArgs);
124 }
125 }
126
127 private final Map<Class<?>, Class<?>[]> classCache;
128
129 public ConstructorUtilsTest() {
130 classCache = new HashMap<>();
131 }
132
133 private void expectMatchingAccessibleConstructorParameterTypes(final Class<?> cls, final Class<?>[] requestTypes, final Class<?>[] actualTypes) {
134 final Constructor<?> c = ConstructorUtils.getMatchingAccessibleConstructor(cls, requestTypes);
135 assertArrayEquals(actualTypes, c.getParameterTypes(), toString(c.getParameterTypes()) + " not equals " + toString(actualTypes));
136 }
137
138 @BeforeEach
139 public void setUp() {
140 classCache.clear();
141 }
142
143 private Class<?>[] singletonArray(final Class<?> c) {
144 Class<?>[] result = classCache.get(c);
145 if (result == null) {
146 result = new Class[] { c };
147 classCache.put(c, result);
148 }
149 return result;
150 }
151
152 @Test
153 void testConstructor() throws Exception {
154 assertNotNull(MethodUtils.class.getConstructor().newInstance());
155 }
156
157 @Test
158 void testGetAccessibleConstructor() throws Exception {
159 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class.getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
160 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.class.getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
161 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.PublicInnerClass.class));
162 }
163
164 @Test
165 void testGetAccessibleConstructorFromDescription() {
166 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class, ArrayUtils.EMPTY_CLASS_ARRAY));
167 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.class, ArrayUtils.EMPTY_CLASS_ARRAY));
168 }
169
170 @Test
171 void testGetMatchingAccessibleMethod() {
172 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
173 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, null, ArrayUtils.EMPTY_CLASS_ARRAY);
174 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(String.class), singletonArray(String.class));
175 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Object.class), singletonArray(Object.class));
176 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Boolean.class), singletonArray(Object.class));
177 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Byte.class), singletonArray(Integer.TYPE));
178 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
179 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Short.class), singletonArray(Integer.TYPE));
180 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
181 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Character.class), singletonArray(Integer.TYPE));
182 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
183 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Integer.class), singletonArray(Integer.class));
184 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
185 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Long.class), singletonArray(Double.TYPE));
186 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Long.TYPE), singletonArray(Double.TYPE));
187 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Float.class), singletonArray(Double.TYPE));
188 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Float.TYPE), singletonArray(Double.TYPE));
189 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Double.class), singletonArray(Double.TYPE));
190 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, singletonArray(Double.TYPE), singletonArray(Double.TYPE));
191 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, new Class<?>[] { SubClass.class, String[].class },
192 new Class<?>[] { BaseClass.class, String[].class });
193 }
194
195 @Test
196 void testInvokeConstructor() throws Exception {
197 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class, (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
198 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class, (Object[]) null).toString());
199 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class).toString());
200 assertEquals("(String)", ConstructorUtils.invokeConstructor(TestBean.class, "").toString());
201 assertEquals("(Object)", ConstructorUtils.invokeConstructor(TestBean.class, new Object()).toString());
202 assertEquals("(Object)", ConstructorUtils.invokeConstructor(TestBean.class, Boolean.TRUE).toString());
203 assertEquals("(Integer)", ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.INTEGER_ONE).toString());
204 assertEquals("(int)", ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.BYTE_ONE).toString());
205 assertEquals("(double)", ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.LONG_ONE).toString());
206 assertEquals("(double)", ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.DOUBLE_ONE).toString());
207 ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.INTEGER_ONE).verify("(Integer)", null);
208 ConstructorUtils.invokeConstructor(TestBean.class, "a", "b").verify("(String...)", new String[] { "a", "b" });
209 ConstructorUtils.invokeConstructor(TestBean.class, NumberUtils.INTEGER_ONE, "a", "b").verify("(Integer, String...)", new String[] { "a", "b" });
210 ConstructorUtils.invokeConstructor(TestBean.class, new SubClass(), new String[] { "a", "b" }).verify("(BaseClass, String...)",
211 new String[] { "a", "b" });
212 }
213
214 @Test
215 void testInvokeExactConstructor() throws Exception {
216 assertEquals("()", ConstructorUtils.invokeExactConstructor(TestBean.class, (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
217 assertEquals("()", ConstructorUtils.invokeExactConstructor(TestBean.class, (Object[]) null).toString());
218 assertEquals("(String)", ConstructorUtils.invokeExactConstructor(TestBean.class, "").toString());
219 assertEquals("(Object)", ConstructorUtils.invokeExactConstructor(TestBean.class, new Object()).toString());
220 assertEquals("(Integer)", ConstructorUtils.invokeExactConstructor(TestBean.class, NumberUtils.INTEGER_ONE).toString());
221 assertEquals("(double)",
222 ConstructorUtils.invokeExactConstructor(TestBean.class, new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }).toString());
223
224 assertThrows(NoSuchMethodException.class, () -> ConstructorUtils.invokeExactConstructor(TestBean.class, NumberUtils.BYTE_ONE));
225 assertThrows(NoSuchMethodException.class, () -> ConstructorUtils.invokeExactConstructor(TestBean.class, NumberUtils.LONG_ONE));
226 assertThrows(NoSuchMethodException.class, () -> ConstructorUtils.invokeExactConstructor(TestBean.class, Boolean.TRUE));
227 }
228
229 @Test
230 void testNullArgument() {
231 expectMatchingAccessibleConstructorParameterTypes(MutableObject.class, singletonArray(null), singletonArray(Object.class));
232 }
233
234 @Test
235 void testVarArgsUnboxing() throws Exception {
236 final TestBean testBean = ConstructorUtils.invokeConstructor(TestBean.class, Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3));
237
238 assertArrayEquals(new String[] { "2", "3" }, testBean.varArgs);
239 }
240
241 private String toString(final Class<?>[] c) {
242 return Arrays.asList(c).toString();
243 }
244
245 }