Skip to content

Commit 7f386be

Browse files
committed
Types: add method accessor
This is analogous to the field accessor, but for methods.
1 parent 1389a55 commit 7f386be

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

src/main/java/org/scijava/util/Types.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,41 @@ public static Field field(final Class<?> c, final String name) {
536536
return field(c.getSuperclass(), name);
537537
}
538538

539+
/**
540+
* Gets the method with the specified name and argument types, of the given
541+
* class, or superclass thereof.
542+
* <p>
543+
* Unlike {@link Class#getMethod(String, Class[])}, this method will return
544+
* methods of any visibility, not just {@code public}. And unlike
545+
* {@link Class#getDeclaredMethod(String, Class[])}, it will do so
546+
* recursively, returning the first method of the given name and argument
547+
* types from the class's superclass hierarchy.
548+
* </p>
549+
* <p>
550+
* Note that this method does not guarantee that the returned method is
551+
* accessible; if the method is not {@code public}, calling code will need to
552+
* use {@link Method#setAccessible(boolean)} in order to invoke the method.
553+
* </p>
554+
*
555+
* @param c The class (or subclass thereof) containing the desired method.
556+
* @param name Name of the method.
557+
* @param parameterTypes Types of the method parameters.
558+
* @return The first method with the given name and argument types in the
559+
* class's superclass hierarchy.
560+
* @throws IllegalArgumentException If the specified class does not contain a
561+
* method with the given name and argument types.
562+
*/
563+
public static Method method(final Class<?> c, final String name,
564+
final Class<?>... parameterTypes)
565+
{
566+
if (c == null) throw iae("No such field: " + name);
567+
try {
568+
return c.getDeclaredMethod(name, parameterTypes);
569+
}
570+
catch (final NoSuchMethodException exc) {}
571+
return method(c.getSuperclass(), name, parameterTypes);
572+
}
573+
539574
/**
540575
* Gets the array class corresponding to the given element type.
541576
* <p>

src/test/java/org/scijava/util/TypesTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import java.io.OutputStream;
4848
import java.io.Serializable;
4949
import java.lang.reflect.Field;
50+
import java.lang.reflect.Method;
5051
import java.lang.reflect.Type;
5152
import java.lang.reflect.TypeVariable;
5253
import java.math.BigDecimal;
@@ -373,6 +374,28 @@ public void testField() {
373374
assertEquals("T", ((TypeVariable<?>) field.getGenericType()).getName());
374375
}
375376

377+
/** Tests {@link Types#method}. */
378+
@Test
379+
public void testMethod() {
380+
final Method objectMethod = Types.method(Thing.class, "toString");
381+
assertSame(Object.class, objectMethod.getDeclaringClass());
382+
assertEquals("toString", objectMethod.getName());
383+
assertSame(String.class, objectMethod.getReturnType());
384+
assertEquals(0, objectMethod.getParameterTypes().length);
385+
386+
final Method wordsMethod = //
387+
Types.method(Words.class, "valueOf", String.class);
388+
// NB: What is going on under the hood to make the Enum
389+
// subtype Words be the declaring class for the 'valueOf'
390+
// method? The compiler must internally override the valueOf
391+
// method for each enum type, to narrow the return type...
392+
assertSame(Words.class, wordsMethod.getDeclaringClass());
393+
assertEquals("valueOf", wordsMethod.getName());
394+
assertSame(Words.class, wordsMethod.getReturnType());
395+
assertEquals(1, wordsMethod.getParameterTypes().length);
396+
assertSame(String.class, wordsMethod.getParameterTypes()[0]);
397+
}
398+
376399
/** Tests {@link Types#array}. */
377400
@Test
378401
public void testArray() {

0 commit comments

Comments
 (0)