001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3.reflect; 018 019import static org.junit.Assert.assertEquals; 020import static org.junit.Assert.assertNotNull; 021import static org.junit.Assert.assertNotSame; 022import static org.junit.Assert.assertNull; 023import static org.junit.Assert.assertSame; 024import static org.junit.Assert.assertTrue; 025import static org.junit.Assert.fail; 026 027import java.lang.reflect.Method; 028import java.util.Arrays; 029import java.util.HashMap; 030import java.util.Map; 031 032import org.apache.commons.lang3.ArrayUtils; 033import org.apache.commons.lang3.math.NumberUtils; 034import org.apache.commons.lang3.mutable.Mutable; 035import org.apache.commons.lang3.mutable.MutableObject; 036import org.junit.Before; 037import org.junit.Test; 038 039/** 040 * Unit tests MethodUtils 041 * @version $Id: MethodUtilsTest.java 1436770 2013-01-22 07:09:45Z ggregory $ 042 */ 043public class MethodUtilsTest { 044 045 private static interface PrivateInterface {} 046 047 static class TestBeanWithInterfaces implements PrivateInterface { 048 public String foo() { 049 return "foo()"; 050 } 051 } 052 053 public static class TestBean { 054 055 public static String bar() { 056 return "bar()"; 057 } 058 059 public static String bar(final int i) { 060 return "bar(int)"; 061 } 062 063 public static String bar(final Integer i) { 064 return "bar(Integer)"; 065 } 066 067 public static String bar(final double d) { 068 return "bar(double)"; 069 } 070 071 public static String bar(final String s) { 072 return "bar(String)"; 073 } 074 075 public static String bar(final Object o) { 076 return "bar(Object)"; 077 } 078 079 public static void oneParameterStatic(final String s) { 080 // empty 081 } 082 083 @SuppressWarnings("unused") 084 private void privateStuff() { 085 } 086 087 088 public String foo() { 089 return "foo()"; 090 } 091 092 public String foo(final int i) { 093 return "foo(int)"; 094 } 095 096 public String foo(final Integer i) { 097 return "foo(Integer)"; 098 } 099 100 public String foo(final double d) { 101 return "foo(double)"; 102 } 103 104 public String foo(final String s) { 105 return "foo(String)"; 106 } 107 108 public String foo(final Object o) { 109 return "foo(Object)"; 110 } 111 112 public void oneParameter(final String s) { 113 // empty 114 } 115 } 116 117 private static class TestMutable implements Mutable<Object> { 118 @Override 119 public Object getValue() { 120 return null; 121 } 122 123 @Override 124 public void setValue(final Object value) { 125 } 126 } 127 128 private TestBean testBean; 129 private final Map<Class<?>, Class<?>[]> classCache = new HashMap<Class<?>, Class<?>[]>(); 130 131 @Before 132 public void setUp() throws Exception { 133 testBean = new TestBean(); 134 classCache.clear(); 135 } 136 137 @Test 138 public void testConstructor() throws Exception { 139 assertNotNull(MethodUtils.class.newInstance()); 140 } 141 142 @Test 143 public void testInvokeMethod() throws Exception { 144 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", 145 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); 146 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", 147 (Object[]) null)); 148 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", 149 (Object[]) null, (Class<?>[]) null)); 150 assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo", 151 "")); 152 assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", 153 new Object())); 154 assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", 155 Boolean.TRUE)); 156 assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo", 157 NumberUtils.INTEGER_ONE)); 158 assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo", 159 NumberUtils.BYTE_ONE)); 160 assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", 161 NumberUtils.LONG_ONE)); 162 assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", 163 NumberUtils.DOUBLE_ONE)); 164 } 165 166 @Test 167 public void testInvokeExactMethod() throws Exception { 168 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", 169 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); 170 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", 171 (Object[]) null)); 172 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", 173 (Object[]) null, (Class<?>[]) null)); 174 assertEquals("foo(String)", MethodUtils.invokeExactMethod(testBean, 175 "foo", "")); 176 assertEquals("foo(Object)", MethodUtils.invokeExactMethod(testBean, 177 "foo", new Object())); 178 assertEquals("foo(Integer)", MethodUtils.invokeExactMethod(testBean, 179 "foo", NumberUtils.INTEGER_ONE)); 180 assertEquals("foo(double)", MethodUtils.invokeExactMethod(testBean, 181 "foo", new Object[] { NumberUtils.DOUBLE_ONE }, 182 new Class[] { Double.TYPE })); 183 184 try { 185 MethodUtils 186 .invokeExactMethod(testBean, "foo", NumberUtils.BYTE_ONE); 187 fail("should throw NoSuchMethodException"); 188 } catch (final NoSuchMethodException e) { 189 } 190 try { 191 MethodUtils 192 .invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE); 193 fail("should throw NoSuchMethodException"); 194 } catch (final NoSuchMethodException e) { 195 } 196 try { 197 MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE); 198 fail("should throw NoSuchMethodException"); 199 } catch (final NoSuchMethodException e) { 200 } 201 } 202 203 @Test 204 public void testInvokeStaticMethod() throws Exception { 205 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, 206 "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); 207 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, 208 "bar", (Object[]) null)); 209 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, 210 "bar", (Object[]) null, (Class<?>[]) null)); 211 assertEquals("bar(String)", MethodUtils.invokeStaticMethod( 212 TestBean.class, "bar", "")); 213 assertEquals("bar(Object)", MethodUtils.invokeStaticMethod( 214 TestBean.class, "bar", new Object())); 215 assertEquals("bar(Object)", MethodUtils.invokeStaticMethod( 216 TestBean.class, "bar", Boolean.TRUE)); 217 assertEquals("bar(Integer)", MethodUtils.invokeStaticMethod( 218 TestBean.class, "bar", NumberUtils.INTEGER_ONE)); 219 assertEquals("bar(int)", MethodUtils.invokeStaticMethod(TestBean.class, 220 "bar", NumberUtils.BYTE_ONE)); 221 assertEquals("bar(double)", MethodUtils.invokeStaticMethod( 222 TestBean.class, "bar", NumberUtils.LONG_ONE)); 223 assertEquals("bar(double)", MethodUtils.invokeStaticMethod( 224 TestBean.class, "bar", NumberUtils.DOUBLE_ONE)); 225 226 try { 227 MethodUtils.invokeStaticMethod(TestBean.class, "does_not_exist"); 228 fail("should throw NoSuchMethodException"); 229 } catch (final NoSuchMethodException e) { 230 } 231 } 232 233 @Test 234 public void testInvokeExactStaticMethod() throws Exception { 235 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, 236 "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); 237 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, 238 "bar", (Object[]) null)); 239 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, 240 "bar", (Object[]) null, (Class<?>[]) null)); 241 assertEquals("bar(String)", MethodUtils.invokeExactStaticMethod( 242 TestBean.class, "bar", "")); 243 assertEquals("bar(Object)", MethodUtils.invokeExactStaticMethod( 244 TestBean.class, "bar", new Object())); 245 assertEquals("bar(Integer)", MethodUtils.invokeExactStaticMethod( 246 TestBean.class, "bar", NumberUtils.INTEGER_ONE)); 247 assertEquals("bar(double)", MethodUtils.invokeExactStaticMethod( 248 TestBean.class, "bar", new Object[] { NumberUtils.DOUBLE_ONE }, 249 new Class[] { Double.TYPE })); 250 251 try { 252 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", 253 NumberUtils.BYTE_ONE); 254 fail("should throw NoSuchMethodException"); 255 } catch (final NoSuchMethodException e) { 256 } 257 try { 258 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", 259 NumberUtils.LONG_ONE); 260 fail("should throw NoSuchMethodException"); 261 } catch (final NoSuchMethodException e) { 262 } 263 try { 264 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", 265 Boolean.TRUE); 266 fail("should throw NoSuchMethodException"); 267 } catch (final NoSuchMethodException e) { 268 } 269 } 270 271 @Test 272 public void testGetAccessibleInterfaceMethod() throws Exception { 273 final Class<?>[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null }; 274 for (final Class<?>[] element : p) { 275 final Method method = TestMutable.class.getMethod("getValue", element); 276 final Method accessibleMethod = MethodUtils.getAccessibleMethod(method); 277 assertNotSame(accessibleMethod, method); 278 assertSame(Mutable.class, accessibleMethod.getDeclaringClass()); 279 } 280 } 281 282 @Test 283 public void testGetAccessibleMethodPrivateInterface() throws Exception { 284 final Method expected = TestBeanWithInterfaces.class.getMethod("foo"); 285 assertNotNull(expected); 286 final Method actual = MethodUtils.getAccessibleMethod(TestBeanWithInterfaces.class, "foo"); 287 assertNull(actual); 288 } 289 290 @Test 291 public void testGetAccessibleInterfaceMethodFromDescription() 292 throws Exception { 293 final Class<?>[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null }; 294 for (final Class<?>[] element : p) { 295 final Method accessibleMethod = MethodUtils.getAccessibleMethod( 296 TestMutable.class, "getValue", element); 297 assertSame(Mutable.class, accessibleMethod.getDeclaringClass()); 298 } 299 } 300 301 @Test 302 public void testGetAccessiblePublicMethod() throws Exception { 303 assertSame(MutableObject.class, MethodUtils.getAccessibleMethod( 304 MutableObject.class.getMethod("getValue", 305 ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass()); 306 } 307 308 @Test 309 public void testGetAccessiblePublicMethodFromDescription() throws Exception { 310 assertSame(MutableObject.class, MethodUtils.getAccessibleMethod( 311 MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY) 312 .getDeclaringClass()); 313 } 314 315 @Test 316 public void testGetAccessibleMethodInaccessible() throws Exception { 317 final Method expected = TestBean.class.getDeclaredMethod("privateStuff"); 318 final Method actual = MethodUtils.getAccessibleMethod(expected); 319 assertNull(actual); 320 } 321 322 @Test 323 public void testGetMatchingAccessibleMethod() throws Exception { 324 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 325 ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY); 326 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 327 null, ArrayUtils.EMPTY_CLASS_ARRAY); 328 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 329 singletonArray(String.class), singletonArray(String.class)); 330 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 331 singletonArray(Object.class), singletonArray(Object.class)); 332 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 333 singletonArray(Boolean.class), singletonArray(Object.class)); 334 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 335 singletonArray(Byte.class), singletonArray(Integer.TYPE)); 336 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 337 singletonArray(Byte.TYPE), singletonArray(Integer.TYPE)); 338 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 339 singletonArray(Short.class), singletonArray(Integer.TYPE)); 340 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 341 singletonArray(Short.TYPE), singletonArray(Integer.TYPE)); 342 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 343 singletonArray(Character.class), singletonArray(Integer.TYPE)); 344 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 345 singletonArray(Character.TYPE), singletonArray(Integer.TYPE)); 346 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 347 singletonArray(Integer.class), singletonArray(Integer.class)); 348 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 349 singletonArray(Integer.TYPE), singletonArray(Integer.TYPE)); 350 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 351 singletonArray(Long.class), singletonArray(Double.TYPE)); 352 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 353 singletonArray(Long.TYPE), singletonArray(Double.TYPE)); 354 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 355 singletonArray(Float.class), singletonArray(Double.TYPE)); 356 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 357 singletonArray(Float.TYPE), singletonArray(Double.TYPE)); 358 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 359 singletonArray(Double.class), singletonArray(Double.TYPE)); 360 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 361 singletonArray(Double.TYPE), singletonArray(Double.TYPE)); 362 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", 363 singletonArray(Double.TYPE), singletonArray(Double.TYPE)); 364 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", 365 singletonArray(ParentObject.class), singletonArray(ParentObject.class)); 366 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", 367 singletonArray(ChildObject.class), singletonArray(ParentObject.class)); 368 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", 369 singletonArray(ParentObject.class), singletonArray(GrandParentObject.class)); 370 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", 371 singletonArray(ChildObject.class), singletonArray(ChildInterface.class)); 372 } 373 374 @Test 375 public void testNullArgument() { 376 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "oneParameter", 377 singletonArray(null), singletonArray(String.class)); 378 } 379 380 private void expectMatchingAccessibleMethodParameterTypes(final Class<?> cls, 381 final String methodName, final Class<?>[] requestTypes, final Class<?>[] actualTypes) { 382 final Method m = MethodUtils.getMatchingAccessibleMethod(cls, methodName, 383 requestTypes); 384 assertTrue(toString(m.getParameterTypes()) + " not equals " 385 + toString(actualTypes), Arrays.equals(actualTypes, m 386 .getParameterTypes())); 387 } 388 389 private String toString(final Class<?>[] c) { 390 return Arrays.asList(c).toString(); 391 } 392 393 private Class<?>[] singletonArray(final Class<?> c) { 394 Class<?>[] result = classCache.get(c); 395 if (result == null) { 396 result = new Class[] { c }; 397 classCache.put(c, result); 398 } 399 return result; 400 } 401 402 public static class InheritanceBean { 403 public void testOne(final Object obj) {} 404 public void testOne(final GrandParentObject obj) {} 405 public void testOne(final ParentObject obj) {} 406 public void testTwo(final Object obj) {} 407 public void testTwo(final GrandParentObject obj) {} 408 public void testTwo(final ChildInterface obj) {} 409 } 410 411 interface ChildInterface {} 412 public static class GrandParentObject {} 413 public static class ParentObject extends GrandParentObject {} 414 public static class ChildObject extends ParentObject implements ChildInterface {} 415 416}