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