You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2025/07/18 14:13:55 UTC

(commons-lang) branch master updated (91ebbc2d8 -> aebecb352)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git


    from 91ebbc2d8 Javadoc
     new dc9e94626 [javadoc] General improvements
     new 8a7b0da6f org.apache.commons.lang3.reflect.MethodUtils.getMethodObject(Class<?>, String, Class<?>...) now returns null instead of throwing a NullPointerException, as it does for other exception types
     new 6b4c7d627 Javadoc
     new 6fea2e956 Internal refactoring
     new 04e788561 Javadoc
     new aebecb352 Inline single use local variable

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/changes/changes.xml                            |   3 +
 .../commons/lang3/reflect/ConstructorUtils.java    | 327 ++++++++++++---------
 .../apache/commons/lang3/reflect/FieldUtils.java   |   3 +-
 .../apache/commons/lang3/reflect/MemberUtils.java  |   6 +-
 .../apache/commons/lang3/reflect/MethodUtils.java  | 198 +++++++++----
 .../commons/lang3/reflect/MethodUtilsTest.java     |  90 +++---
 6 files changed, 364 insertions(+), 263 deletions(-)


(commons-lang) 06/06: Inline single use local variable

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit aebecb3529c0ec7af4943a43c2febe0466640853
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 09:59:25 2025 -0400

    Inline single use local variable
---
 src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java b/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
index d37b24f55..9e5378bf8 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
@@ -73,8 +73,7 @@ public static List<Field> getAllFieldsList(final Class<?> cls) {
         final List<Field> allFields = new ArrayList<>();
         Class<?> currentClass = cls;
         while (currentClass != null) {
-            final Field[] declaredFields = currentClass.getDeclaredFields();
-            Collections.addAll(allFields, declaredFields);
+            Collections.addAll(allFields, currentClass.getDeclaredFields());
             currentClass = currentClass.getSuperclass();
         }
         return allFields;


(commons-lang) 04/06: Internal refactoring

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 6fea2e95676f0c90d76ff7554e9d1b4c3826c214
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 09:28:36 2025 -0400

    Internal refactoring
---
 .../apache/commons/lang3/reflect/MethodUtils.java   | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
index 5d4e1f1fe..22ea49f72 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
@@ -545,26 +545,29 @@ public static Set<Method> getOverrideHierarchy(final Method method, final Interf
      * @since 3.5
      */
     static Object[] getVarArgs(final Object[] args, final Class<?>[] methodParameterTypes) {
-        if (args.length == methodParameterTypes.length
-                && (args[args.length - 1] == null || args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1]))) {
-            // The args array is already in the canonical form for the method.
-            return args;
+        final int mptLength = methodParameterTypes.length;
+        if (args.length == mptLength) {
+            final Object lastArg = args[args.length - 1];
+            if (lastArg == null || lastArg.getClass().equals(methodParameterTypes[mptLength - 1])) {
+                // The args array is already in the canonical form for the method.
+                return args;
+            }
         }
         // Construct a new array matching the method's declared parameter types.
         // Copy the normal (non-varargs) parameters
-        final Object[] newArgs = ArrayUtils.arraycopy(args, 0, 0, methodParameterTypes.length - 1, () -> new Object[methodParameterTypes.length]);
+        final Object[] newArgs = ArrayUtils.arraycopy(args, 0, 0, mptLength - 1, () -> new Object[mptLength]);
         // Construct a new array for the variadic parameters
-        final Class<?> varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType();
-        final int varArgLength = args.length - methodParameterTypes.length + 1;
+        final Class<?> varArgComponentType = methodParameterTypes[mptLength - 1].getComponentType();
+        final int varArgLength = args.length - mptLength + 1;
         // Copy the variadic arguments into the varargs array.
-        Object varArgsArray = ArrayUtils.arraycopy(args, methodParameterTypes.length - 1, 0, varArgLength,
+        Object varArgsArray = ArrayUtils.arraycopy(args, mptLength - 1, 0, varArgLength,
                 s -> Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength));
         if (varArgComponentType.isPrimitive()) {
             // unbox from wrapper type to primitive type
             varArgsArray = ArrayUtils.toPrimitive(varArgsArray);
         }
         // Store the varargs array in the last position of the array to return
-        newArgs[methodParameterTypes.length - 1] = varArgsArray;
+        newArgs[mptLength - 1] = varArgsArray;
         // Return the canonical varargs array.
         return newArgs;
     }


(commons-lang) 03/06: Javadoc

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 6b4c7d627967211b0528b32e5333547d4508f932
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 09:07:49 2025 -0400

    Javadoc
    
    - Use final
---
 .../apache/commons/lang3/reflect/MemberUtils.java  |   6 +-
 .../apache/commons/lang3/reflect/MethodUtils.java  | 156 ++++++++++++++++-----
 2 files changed, 121 insertions(+), 41 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/MemberUtils.java b/src/main/java/org/apache/commons/lang3/reflect/MemberUtils.java
index 7073397f7..a244c5eb2 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/MemberUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/MemberUtils.java
@@ -281,7 +281,7 @@ static boolean isMatchingMethod(final Method method, final Class<?>[] parameterT
     /**
      * Tests whether a given set of modifiers implies package access.
      *
-     * @param modifiers to test
+     * @param modifiers to test.
      * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
      */
     static boolean isPackageAccess(final int modifiers) {
@@ -292,7 +292,7 @@ static boolean isPackageAccess(final int modifiers) {
      * Tests whether a {@link Member} is public.
      *
      * @param member Member to test, may be null.
-     * @return {@code true} if {@code m} is public
+     * @return {@code true} if {@code m} is public.
      */
     static boolean isPublic(final Member member) {
         return member != null && Modifier.isPublic(member.getModifiers());
@@ -302,7 +302,7 @@ static boolean isPublic(final Member member) {
      * Tests whether a {@link Member} is static.
      *
      * @param member Member to test, may be null.
-     * @return {@code true} if {@code m} is static
+     * @return {@code true} if {@code m} is static.
      */
     static boolean isStatic(final Member member) {
         return member != null && Modifier.isStatic(member.getModifiers());
diff --git a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
index be5e9a439..5d4e1f1fe 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
@@ -680,9 +680,20 @@ public static Object invokeExactMethod(final Object object, final String methodN
      * @param methodName get method with this name
      * @param args       use these arguments - treat {@code null} as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException     if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException    if the requested method is not accessible via reflection
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      */
     public static Object invokeExactStaticMethod(final Class<?> cls, final String methodName, final Object... args)
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -702,9 +713,20 @@ public static Object invokeExactStaticMethod(final Class<?> cls, final String me
      * @param args           use these arguments - treat {@code null} as empty array
      * @param parameterTypes match these parameters - treat {@code null} as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException     if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException    if the requested method is not accessible via reflection
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      */
     public static Object invokeExactStaticMethod(final Class<?> cls, final String methodName, final Object[] args, final Class<?>[] parameterTypes)
             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -727,10 +749,21 @@ public static Object invokeExactStaticMethod(final Class<?> cls, final String me
      * @param forceAccess force access to invoke method even if it's not accessible
      * @param methodName get method with this name
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws NullPointerException        Thrown if the specified {@code object} is null.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      * @since 3.5
      */
@@ -757,11 +790,21 @@ public static Object invokeMethod(final Object object, final boolean forceAccess
      * @param methodName get method with this name
      * @param args use these arguments - treat null as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws NullPointerException if the object or method name are {@code null}
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws NullPointerException        Thrown if the specified {@code object} is null.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      * @since 3.5
      */
@@ -786,11 +829,21 @@ public static Object invokeMethod(final Object object, final boolean forceAccess
      * @param args use these arguments - treat null as empty array
      * @param parameterTypes match these parameters - treat null as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws NullPointerException if the object or method name are {@code null}
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws NullPointerException        Thrown if the specified {@code object} is null.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      * @since 3.5
      */
@@ -893,10 +946,21 @@ public static Object invokeMethod(final Object object, final String methodName,
      * @param args use these arguments - treat null as empty array
      * @param parameterTypes match these parameters - treat null as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws NullPointerException        Thrown if the specified {@code object} is null.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      */
     public static Object invokeMethod(final Object object, final String methodName, final Object[] args, final Class<?>[] parameterTypes)
@@ -924,10 +988,20 @@ public static Object invokeMethod(final Object object, final String methodName,
      * @param methodName get method with this name
      * @param args use these arguments - treat {@code null} as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      */
     public static Object invokeStaticMethod(final Class<?> cls, final String methodName, final Object... args)
@@ -953,10 +1027,20 @@ public static Object invokeStaticMethod(final Class<?> cls, final String methodN
      * @param args use these arguments - treat {@code null} as empty array
      * @param parameterTypes match these parameters - treat {@code null} as empty array
      * @return The value returned by the invoked method
-     * @throws NoSuchMethodException if there is no such accessible method
-     * @throws InvocationTargetException wraps an exception thrown by the method invoked
-     * @throws IllegalAccessException if the requested method is not accessible via reflection
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @throws NoSuchMethodException       Thrown if there is no such accessible method.
+     * @throws IllegalAccessException      Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+     *                                     the class or interface declaring the underlying method (or of a subclass or interface implementor);</li>
+     *                                     <li>the number of actual and formal parameters differ;</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion.</li>
+     *                                     </ul>
+     * @throws InvocationTargetException   Thrown if the underlying method throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
      * @see SecurityManager#checkPermission
      */
     public static Object invokeStaticMethod(final Class<?> cls, final String methodName, final Object[] args, final Class<?>[] parameterTypes)
@@ -968,12 +1052,8 @@ public static Object invokeStaticMethod(final Class<?> cls, final String methodN
         return method.invoke(null, toVarArgs(method, ArrayUtils.nullToEmpty(args)));
     }
 
-    private static Object[] toVarArgs(final Method method, Object[] args) {
-        if (method.isVarArgs()) {
-            final Class<?>[] methodParameterTypes = method.getParameterTypes();
-            args = getVarArgs(args, methodParameterTypes);
-        }
-        return args;
+    private static Object[] toVarArgs(final Method method, final Object[] args) {
+        return method.isVarArgs() ? getVarArgs(args, method.getParameterTypes()) : args;
     }
 
     /**


(commons-lang) 05/06: Javadoc

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 04e7885617298f55f773a9ceeb68162c81f38717
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 09:58:27 2025 -0400

    Javadoc
    
    - Use final
    - Use longer lines
---
 .../commons/lang3/reflect/ConstructorUtils.java    | 327 ++++++++++++---------
 1 file changed, 182 insertions(+), 145 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java b/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
index e9795b0e5..d0cad85e7 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.commons.lang3.reflect;
 
 import java.lang.reflect.Constructor;
@@ -24,22 +25,20 @@
 import org.apache.commons.lang3.ClassUtils;
 
 /**
- *  Utility reflection methods focused on constructors, modeled after
- * {@link MethodUtils}.
+ * Utility reflection methods focused on constructors, modeled after {@link MethodUtils}.
  *
  * <h2>Known Limitations</h2>
  * <h3>Accessing Public Constructors In A Default Access Superclass</h3>
- * <p>There is an issue when invoking {@code public} constructors
- * contained in a default access superclass. Reflection correctly locates these
- * constructors and assigns them as {@code public}. However, an
- * {@link IllegalAccessException} is thrown if the constructor is
- * invoked.</p>
+ * <p>
+ * There is an issue when invoking {@code public} constructors contained in a default access superclass. Reflection correctly locates these constructors and
+ * assigns them as {@code public}. However, an {@link IllegalAccessException} is thrown if the constructor is invoked.
+ * </p>
  *
- * <p>{@link ConstructorUtils} contains a workaround for this situation: it
- * will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this constructor. If this
- * call succeeds, then the method can be invoked as normal. This call will only
- * succeed when the application has sufficient security privileges. If this call
- * fails then a warning will be logged and the method may fail.</p>
+ * <p>
+ * {@link ConstructorUtils} contains a workaround for this situation: it will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
+ * on this constructor. If this call succeeds, then the method can be invoked as normal. This call will only succeed when the application has sufficient
+ * security privileges. If this call fails then a warning will be logged and the method may fail.
+ * </p>
  *
  * @since 2.5
  */
@@ -48,19 +47,22 @@ public class ConstructorUtils {
     /**
      * Finds a constructor given a class and signature, checking accessibility.
      *
-     * <p>This finds the constructor and ensures that it is accessible.
-     * The constructor signature must match the parameter types exactly.</p>
+     * <p>
+     * This finds the constructor and ensures that it is accessible. The constructor signature must match the parameter types exactly.
+     * </p>
      *
-     * @param <T> the constructor type
-     * @param cls the class to find a constructor for, not {@code null}
-     * @param parameterTypes the array of parameter types, {@code null} treated as empty
-     * @return the constructor, {@code null} if no matching accessible constructor found
+     * @param <T>            the constructor type.
+     * @param cls            the class to find a constructor for, not {@code null}.
+     * @param parameterTypes the array of parameter types, {@code null} treated as empty.
+     * @return the constructor, {@code null} if no matching accessible constructor found.
+     * @throws NullPointerException if {@code cls} is {@code null}
+     * @throws SecurityException    Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class loader
+     *                              for the class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the package of the
+     *                              class.
      * @see Class#getConstructor
      * @see #getAccessibleConstructor(java.lang.reflect.Constructor)
-     * @throws NullPointerException if {@code cls} is {@code null}
      */
-    public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls,
-            final Class<?>... parameterTypes) {
+    public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls, final Class<?>... parameterTypes) {
         Objects.requireNonNull(cls, "cls");
         try {
             return getAccessibleConstructor(cls.getConstructor(parameterTypes));
@@ -72,42 +74,45 @@ public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls,
     /**
      * Checks if the specified constructor is accessible.
      *
-     * <p>This simply ensures that the constructor is accessible.</p>
+     * <p>
+     * This simply ensures that the constructor is accessible.
+     * </p>
      *
-     * @param <T> the constructor type
-     * @param ctor  the prototype constructor object, not {@code null}
-     * @return the constructor, {@code null} if no matching accessible constructor found
+     * @param <T>  the constructor type.
+     * @param ctor the prototype constructor object, not {@code null}.
+     * @return the constructor, {@code null} if no matching accessible constructor found.
      * @see SecurityManager
      * @throws NullPointerException if {@code ctor} is {@code null}
+     * @throws SecurityException    Thrown if a security manager is present and a caller's class loader is not the same as or an ancestor of the class loader
+     *                              for a class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the package of the class.
      */
     public static <T> Constructor<T> getAccessibleConstructor(final Constructor<T> ctor) {
         Objects.requireNonNull(ctor, "ctor");
-        return MemberUtils.isAccessible(ctor)
-                && isAccessible(ctor.getDeclaringClass()) ? ctor : null;
+        return MemberUtils.isAccessible(ctor) && isAccessible(ctor.getDeclaringClass()) ? ctor : null;
     }
 
     /**
      * Finds an accessible constructor with compatible parameters.
      *
-     * <p>This checks all the constructor and finds one with compatible parameters
-     * This requires that every parameter is assignable from the given parameter types.
-     * This is a more flexible search than the normal exact matching algorithm.</p>
+     * <p>
+     * This checks all the constructor and finds one with compatible parameters This requires that every parameter is assignable from the given parameter types.
+     * This is a more flexible search than the normal exact matching algorithm.
+     * </p>
+     * <p>
+     * First it checks if there is a constructor matching the exact signature. If not then all the constructors of the class are checked to see if their
+     * signatures are assignment-compatible with the parameter types. The first assignment-compatible matching constructor is returned.
+     * </p>
      *
-     * <p>First it checks if there is a constructor matching the exact signature.
-     * If not then all the constructors of the class are checked to see if their
-     * signatures are assignment-compatible with the parameter types.
-     * The first assignment-compatible matching constructor is returned.</p>
-     *
-     * @param <T> the constructor type
-     * @param cls  the class to find a constructor for, not {@code null}
-     * @param parameterTypes find method with compatible parameters
-     * @return the constructor, null if no matching accessible constructor found
-     * @throws NullPointerException if {@code cls} is {@code null}
-     * @throws SecurityException if an underlying accessible object's method denies the request.
-     * @see SecurityManager#checkPermission
+     * @param <T>            the constructor type.
+     * @param cls            the class to find a constructor for, not {@code null}.
+     * @param parameterTypes find method with compatible parameters.
+     * @return the constructor, null if no matching accessible constructor found.
+     * @throws NullPointerException Thrown if {@code cls} is {@code null}
+     * @throws SecurityException    Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class loader for the
+     *                              class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the package of the class.
+     * @see SecurityManager#checkPackageAccess(String)
      */
-    public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T> cls,
-            final Class<?>... parameterTypes) {
+    public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T> cls, final Class<?>... parameterTypes) {
         Objects.requireNonNull(cls, "cls");
         // see if we can find the constructor directly
         // most of the time this works and it's much faster
@@ -118,11 +123,9 @@ public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T>
         }
         Constructor<T> result = null;
         /*
-         * (1) Class.getConstructors() is documented to return Constructor<T> so as
-         * long as the array is not subsequently modified, everything's fine.
+         * (1) Class.getConstructors() is documented to return Constructor<T> so as long as the array is not subsequently modified, everything's fine.
          */
         final Constructor<?>[] ctors = cls.getConstructors();
-
         // return best match:
         for (Constructor<?> ctor : ctors) {
             // compare parameters
@@ -144,132 +147,167 @@ public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T>
     }
 
     /**
-     * Returns a new instance of the specified class inferring the right constructor
-     * from the types of the arguments.
+     * Returns a new instance of the specified class inferring the right constructor from the types of the arguments.
      *
-     * <p>This locates and calls a constructor.
-     * The constructor signature must match the argument types by assignment compatibility.</p>
+     * <p>
+     * This locates and calls a constructor. The constructor signature must match the argument types by assignment compatibility.
+     * </p>
      *
-     * @param <T> the type to be constructed
-     * @param cls  the class to be constructed, not {@code null}
-     * @param args  the array of arguments, {@code null} treated as empty
-     * @return new instance of {@code cls}, not {@code null}
-     * @throws NullPointerException if {@code cls} is {@code null}
-     * @throws NoSuchMethodException if a matching constructor cannot be found
-     * @throws IllegalAccessException if invocation is not permitted by security
-     * @throws InvocationTargetException if an error occurs on invocation
-     * @throws InstantiationException if an error occurs on instantiation
-     * @throws SecurityException if an underlying accessible object's method denies the request.
-     * @see SecurityManager#checkPermission
+     * @param <T>  the type to be constructed.
+     * @param cls  the class to be constructed, not {@code null}.
+     * @param args the array of arguments, {@code null} treated as empty.
+     * @return new instance of {@code cls}, not {@code null}.
+     * @throws NullPointerException        Thrown if {@code cls} is {@code null}.
+     * @throws NoSuchMethodException       Thrown if a matching constructor cannot be found.
+     * @throws IllegalAccessException      Thrown if the found {@code Constructor} is enforcing Java language access control and the underlying constructor is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the number of actual and formal parameters differ; or</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion; if this constructor pertains to an enum type.
+     *                                     </ul>
+     * @throws InstantiationException      Thrown if the class that declares the underlying constructor represents an abstract class.
+     * @throws InvocationTargetException   Thrown if the underlying constructor throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+     * @throws SecurityException           Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class
+     *                                     loader for the class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the
+     *                                     package of the class.
      * @see #invokeConstructor(Class, Object[], Class[])
      */
-    public static <T> T invokeConstructor(final Class<T> cls, Object... args)
-            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
-            InstantiationException {
-        args = ArrayUtils.nullToEmpty(args);
-        return invokeConstructor(cls, args, ClassUtils.toClass(args));
+    public static <T> T invokeConstructor(final Class<T> cls, final Object... args)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+        final Object[] actuals = ArrayUtils.nullToEmpty(args);
+        return invokeConstructor(cls, actuals, ClassUtils.toClass(actuals));
     }
 
     /**
-     * Returns a new instance of the specified class choosing the right constructor
-     * from the list of parameter types.
+     * Returns a new instance of the specified class choosing the right constructor from the list of parameter types.
      *
-     * <p>This locates and calls a constructor.
-     * The constructor signature must match the parameter types by assignment compatibility.</p>
+     * <p>
+     * This locates and calls a constructor. The constructor signature must match the parameter types by assignment compatibility.
+     * </p>
      *
-     * @param <T> the type to be constructed
-     * @param cls  the class to be constructed, not {@code null}
-     * @param args  the array of arguments, {@code null} treated as empty
-     * @param parameterTypes  the array of parameter types, {@code null} treated as empty
+     * @param <T>            the type to be constructed.
+     * @param cls            the class to be constructed, not {@code null}.
+     * @param args           the array of arguments, {@code null} treated as empty.
+     * @param parameterTypes the array of parameter types, {@code null} treated as empty.
      * @return new instance of {@code cls}, not {@code null}
-     * @throws NullPointerException if {@code cls} is {@code null}
-     * @throws NoSuchMethodException if a matching constructor cannot be found
-     * @throws IllegalAccessException if invocation is not permitted by security
-     * @throws InvocationTargetException if an error occurs on invocation
-     * @throws InstantiationException if an error occurs on instantiation
-     * @throws SecurityException if an underlying accessible object's method denies the request.
-     * @see SecurityManager#checkPermission
+     * @throws NullPointerException        Thrown if {@code cls} is {@code null}.
+     * @throws NoSuchMethodException       Thrown if a matching constructor cannot be found.
+     * @throws IllegalAccessException      Thrown if the found {@code Constructor} is enforcing Java language access control and the underlying constructor is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the number of actual and formal parameters differ; or</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion; if this constructor pertains to an enum type.
+     *                                     </ul>
+     * @throws InstantiationException      Thrown if the class that declares the underlying constructor represents an abstract class.
+     * @throws InvocationTargetException   Thrown if the underlying constructor throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+     * @throws SecurityException           Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class
+     *                                     loader for the class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the
+     *                                     package of the class.
+     * @see Constructor#newInstance(Object...)
      * @see Constructor#newInstance
      */
-    public static <T> T invokeConstructor(final Class<T> cls, Object[] args, Class<?>[] parameterTypes)
-            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
-            InstantiationException {
-        args = ArrayUtils.nullToEmpty(args);
-        parameterTypes = ArrayUtils.nullToEmpty(parameterTypes);
-        final Constructor<T> ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
+    public static <T> T invokeConstructor(final Class<T> cls, final Object[] args, final Class<?>[] parameterTypes)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+        final Object[] actuals = ArrayUtils.nullToEmpty(args);
+        final Constructor<T> ctor = getMatchingAccessibleConstructor(cls, ArrayUtils.nullToEmpty(parameterTypes));
         if (ctor == null) {
-            throw new NoSuchMethodException(
-                "No such accessible constructor on object: " + cls.getName());
-        }
-        if (ctor.isVarArgs()) {
-            final Class<?>[] methodParameterTypes = ctor.getParameterTypes();
-            args = MethodUtils.getVarArgs(args, methodParameterTypes);
+            throw new NoSuchMethodException("No such accessible constructor on object: " + cls.getName());
         }
-        return ctor.newInstance(args);
+        return ctor.newInstance(ctor.isVarArgs() ? MethodUtils.getVarArgs(actuals, ctor.getParameterTypes()) : actuals);
     }
 
     /**
-     * Returns a new instance of the specified class inferring the right constructor
-     * from the types of the arguments.
+     * Returns a new instance of the specified class inferring the right constructor from the types of the arguments.
      *
-     * <p>This locates and calls a constructor.
-     * The constructor signature must match the argument types exactly.</p>
+     * <p>
+     * This locates and calls a constructor. The constructor signature must match the argument types exactly.
+     * </p>
      *
-     * @param <T> the type to be constructed
-     * @param cls the class to be constructed, not {@code null}
-     * @param args the array of arguments, {@code null} treated as empty
-     * @return new instance of {@code cls}, not {@code null}
-     * @throws NullPointerException if {@code cls} is {@code null}
-     * @throws NoSuchMethodException if a matching constructor cannot be found
-     * @throws IllegalAccessException if invocation is not permitted by security
-     * @throws InvocationTargetException if an error occurs on invocation
-     * @throws InstantiationException if an error occurs on instantiation
+     * @param <T>  the type to be constructed.
+     * @param cls  the class to be constructed, not {@code null}.
+     * @param args the array of arguments, {@code null} treated as empty.
+     * @return new instance of {@code cls}, not {@code null}.
+     * @throws NullPointerException        Thrown if {@code cls} is {@code null}.
+     * @throws NoSuchMethodException       Thrown if a matching constructor cannot be found.
+     * @throws IllegalAccessException      Thrown if the found {@code Constructor} is enforcing Java language access control and the underlying constructor is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the number of actual and formal parameters differ; or</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion; if this constructor pertains to an enum type.
+     *                                     </ul>
+     * @throws InstantiationException      Thrown if the class that declares the underlying constructor represents an abstract class.
+     * @throws InvocationTargetException   Thrown if the underlying constructor throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+     * @throws SecurityException           Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class
+     *                                     loader for the class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the
+     *                                     package of the class.
+     * @see Constructor#newInstance(Object...)
      * @see #invokeExactConstructor(Class, Object[], Class[])
      */
-    public static <T> T invokeExactConstructor(final Class<T> cls, Object... args)
-            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
-            InstantiationException {
-        args = ArrayUtils.nullToEmpty(args);
-        return invokeExactConstructor(cls, args, ClassUtils.toClass(args));
+    public static <T> T invokeExactConstructor(final Class<T> cls, final Object... args)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+        final Object[] actuals = ArrayUtils.nullToEmpty(args);
+        return invokeExactConstructor(cls, actuals, ClassUtils.toClass(actuals));
     }
 
     /**
-     * Returns a new instance of the specified class choosing the right constructor
-     * from the list of parameter types.
+     * Returns a new instance of the specified class choosing the right constructor from the list of parameter types.
      *
-     * <p>This locates and calls a constructor.
-     * The constructor signature must match the parameter types exactly.</p>
+     * <p>
+     * This locates and calls a constructor. The constructor signature must match the parameter types exactly.
+     * </p>
      *
-     * @param <T> the type to be constructed
-     * @param cls the class to be constructed, not {@code null}
-     * @param args the array of arguments, {@code null} treated as empty
-     * @param parameterTypes  the array of parameter types, {@code null} treated as empty
-     * @return new instance of {@code cls}, not {@code null}
-     * @throws NullPointerException if {@code cls} is {@code null}
-     * @throws NoSuchMethodException if a matching constructor cannot be found
-     * @throws IllegalAccessException if invocation is not permitted by security
-     * @throws InvocationTargetException if an error occurs on invocation
-     * @throws InstantiationException if an error occurs on instantiation
-     * @see Constructor#newInstance
+     * @param <T>            the type to construct.
+     * @param cls            the class to construct, not {@code null}.
+     * @param args           the array of arguments, {@code null} treated as empty.
+     * @param parameterTypes the array of parameter types, {@code null} treated as empty.
+     * @return new instance of {@code cls}, not {@code null}.
+     * @throws NullPointerException        Thrown if {@code cls} is {@code null}.
+     * @throws NoSuchMethodException       Thrown if a matching constructor cannot be found.
+     * @throws IllegalAccessException      Thrown if the found {@code Constructor} is enforcing Java language access control and the underlying constructor is
+     *                                     inaccessible.
+     * @throws IllegalArgumentException    Thrown if:
+     *                                     <ul>
+     *                                     <li>the number of actual and formal parameters differ; or</li>
+     *                                     <li>an unwrapping conversion for primitive arguments fails; or</li>
+     *                                     <li>after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a
+     *                                     method invocation conversion; if this constructor pertains to an enum type.
+     *                                     </ul>
+     * @throws InstantiationException      Thrown if the class that declares the underlying constructor represents an abstract class.
+     * @throws InvocationTargetException   Thrown if the underlying constructor throws an exception.
+     * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+     * @throws SecurityException           Thrown if a security manager is present and the caller's class loader is not the same as or an ancestor of the class
+     *                                     loader for the class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the
+     *                                     package of the class.
+     * @see Constructor#newInstance(Object...)
      */
-    public static <T> T invokeExactConstructor(final Class<T> cls, Object[] args,
-            Class<?>[] parameterTypes) throws NoSuchMethodException, IllegalAccessException,
-            InvocationTargetException, InstantiationException {
-        args = ArrayUtils.nullToEmpty(args);
-        parameterTypes = ArrayUtils.nullToEmpty(parameterTypes);
-        final Constructor<T> ctor = getAccessibleConstructor(cls, parameterTypes);
+    public static <T> T invokeExactConstructor(final Class<T> cls, final Object[] args, final Class<?>[] parameterTypes)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+        final Constructor<T> ctor = getAccessibleConstructor(cls, ArrayUtils.nullToEmpty(parameterTypes));
         if (ctor == null) {
             throw new NoSuchMethodException("No such accessible constructor on object: " + cls.getName());
         }
-        return ctor.newInstance(args);
+        return ctor.newInstance(ArrayUtils.nullToEmpty(args));
     }
 
     /**
-     * Tests whether the specified class is generally accessible, i.e. is
-     * declared in an entirely {@code public} manner.
-     * @param type to check
-     * @return {@code true} if {@code type} and any enclosing classes are
-     *         {@code public}.
+     * Tests whether the specified class is generally accessible, i.e. is declared in an entirely {@code public} manner.
+     *
+     * @param type to check.
+     * @return {@code true} if {@code type} and any enclosing classes are {@code public}.
+     * @throws SecurityException Thrown if a security manager is present and a caller's class loader is not the same as or an ancestor of the class loader for a
+     *                           class and invocation of {@link SecurityManager#checkPackageAccess(String)} denies access to the package of the class.
      */
     private static boolean isAccessible(final Class<?> type) {
         Class<?> cls = type;
@@ -283,12 +321,12 @@ private static boolean isAccessible(final Class<?> type) {
     }
 
     /**
-     * ConstructorUtils instances should NOT be constructed in standard
-     * programming. Instead, the class should be used as
+     * ConstructorUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
      * {@code ConstructorUtils.invokeConstructor(cls, args)}.
      *
-     * <p>This constructor is {@code public} to permit tools that require a JavaBean
-     * instance to operate.</p>
+     * <p>
+     * This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
+     * </p>
      *
      * @deprecated TODO Make private in 4.0.
      */
@@ -296,5 +334,4 @@ private static boolean isAccessible(final Class<?> type) {
     public ConstructorUtils() {
         // empty
     }
-
 }


(commons-lang) 02/06: org.apache.commons.lang3.reflect.MethodUtils.getMethodObject(Class, String, Class...) now returns null instead of throwing a NullPointerException, as it does for other exception types

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 8a7b0da6fc783127f8272d955d9f06f1966949ec
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 08:57:03 2025 -0400

    org.apache.commons.lang3.reflect.MethodUtils.getMethodObject(Class<?>,
    String, Class<?>...) now returns null instead of throwing a
    NullPointerException, as it does for other exception types
---
 src/changes/changes.xml                            |  2 +
 .../apache/commons/lang3/reflect/MethodUtils.java  | 21 +++--
 .../commons/lang3/reflect/MethodUtilsTest.java     | 90 +++++++++-------------
 3 files changed, 47 insertions(+), 66 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 606469e51..cebd5f4da 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -50,6 +50,8 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="fix" dev="ggregory" due-to="Hassan A Hashim">[javadoc] Fix Javadocs in ClassUtils #1410.</action>
     <action issue="LANG-1778" type="fix" dev="ggregory" due-to="wuwu2000">MethodUtils.getMatchingMethod() doesn't respect the hierarchy of methods #1414.</action>
     <action                   type="fix" dev="ggregory" due-to="Gary Gregory">[javadoc] General improvements.</action>
+    <action                   type="fix" dev="ggregory" due-to="Gary Gregory">[javadoc] Fix thrown exception documentation for org.apache.commons.lang3.reflect.MethodUtils.getMethodObject(Class&lt;?&gt;, String, Class&lt;?&gt;...).</action>
+    <action                   type="fix" dev="ggregory" due-to="Gary Gregory">org.apache.commons.lang3.reflect.MethodUtils.getMethodObject(Class&lt;?&gt;, String, Class&lt;?&gt;...) now returns null instead of throwing a NullPointerException, as it does for other exception types.</action>
     <!-- ADD -->
     <!-- UPDATE -->
   </release>
diff --git a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
index f50433f54..be5e9a439 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
@@ -99,10 +99,10 @@ private static int distance(final Class<?>[] fromClassArray, final Class<?>[] to
      * Gets an accessible method (that is, one that can be invoked via reflection) with given name and parameters. If no such method can be found, return
      * {@code null}. This is just a convenience wrapper for {@link #getAccessibleMethod(Method)}.
      *
-     * @param cls            get method from this class
-     * @param methodName     get method with this name
-     * @param parameterTypes with these parameters types
-     * @return The accessible method
+     * @param cls            get method from this class.
+     * @param methodName     get method with this name.
+     * @param parameterTypes with these parameters types.
+     * @return The accessible method.
      */
     public static Method getAccessibleMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) {
         return getAccessibleMethod(getMethodObject(cls, methodName, parameterTypes));
@@ -393,20 +393,19 @@ public static Method getMatchingMethod(final Class<?> cls, final String methodNa
     }
 
     /**
-     * Gets a Method or null if a {@link Class#getMethod(String, Class...) documented} exception is thrown.
+     * Gets a Method, or {@code null} if a documented {@link Class#getMethod(String, Class...) } exception is thrown.
      *
-     * @param cls Receiver for {@link Class#getMethod(String, Class...)}.
-     * @param name the name of the method
-     * @param parameterTypes the list of parameters
-     * @return a Method or null.
-     * @throws SecurityException if an underlying accessible object's method denies the request.
+     * @param cls            Receiver for {@link Class#getMethod(String, Class...)}.
+     * @param name           the name of the method.
+     * @param parameterTypes the list of parameters.
+     * @return a Method or {@code null}.
      * @see SecurityManager#checkPermission
      * @see Class#getMethod(String, Class...)
      * @since 3.15.0
      */
     public static Method getMethodObject(final Class<?> cls, final String name, final Class<?>... parameterTypes) {
         try {
-            return cls.getMethod(name, parameterTypes);
+            return name != null && cls != null ? cls.getMethod(name, parameterTypes) : null;
         } catch (final NoSuchMethodException | SecurityException e) {
             return null;
         }
diff --git a/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java b/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java
index d81234d9b..ace3af8e3 100644
--- a/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java
@@ -695,6 +695,14 @@ void testGetMethodObject() throws Exception {
         assertEquals(MutableObject.class.getMethod("getValue", ArrayUtils.EMPTY_CLASS_ARRAY),
                 MethodUtils.getMethodObject(MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY));
         assertNull(MethodUtils.getMethodObject(MutableObject.class, "does not exist, at all", ArrayUtils.EMPTY_CLASS_ARRAY));
+        assertNull(MethodUtils.getMethodObject(null, "does not exist, at all", ArrayUtils.EMPTY_CLASS_ARRAY));
+        assertNull(MethodUtils.getMethodObject(null, null, ArrayUtils.EMPTY_CLASS_ARRAY));
+        assertNull(MethodUtils.getMethodObject(MutableObject.class, null, ArrayUtils.EMPTY_CLASS_ARRAY));
+        // 0 args
+        assertNull(MethodUtils.getMethodObject(MutableObject.class, "getValue", new Class[] { null }));
+        // 1 args
+        assertNull(MethodUtils.getMethodObject(MutableObject.class, "equals", new Class[] { null }));
+        assertNull(MethodUtils.getMethodObject(MutableObject.class, "equals", new Class[] { String.class, null, String.class }));
     }
 
     @Test
@@ -867,10 +875,10 @@ void testInvokeExactMethod() throws Exception {
         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE));
         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE));
         assertThrows(NullPointerException.class, () -> MethodUtils.invokeExactMethod(null, "foo", NumberUtils.BYTE_ONE));
-        assertThrows(NullPointerException.class, () -> MethodUtils.invokeExactMethod(testBean, null, NumberUtils.BYTE_ONE));
+        assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, null, NumberUtils.BYTE_ONE));
         assertThrows(NullPointerException.class,
                 () -> MethodUtils.invokeExactMethod(null, "foo", new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
-        assertThrows(NullPointerException.class,
+        assertThrows(NoSuchMethodException.class,
                 () -> MethodUtils.invokeExactMethod(testBean, null, new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
     }
 
@@ -939,65 +947,40 @@ void testInvokeJavaVarargsOverloadingResolution() throws Exception {
 
     @Test
     void testInvokeMethod() throws Exception {
-        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
-                (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
+        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
         assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo"));
-        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
-                (Object[]) null));
-        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
-                null, null));
-        assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo",
-                ""));
-        assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
-                new Object()));
-        assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
-                Boolean.TRUE));
-        assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo",
-                NumberUtils.INTEGER_ONE));
-        assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo",
-                NumberUtils.BYTE_ONE));
-        assertEquals("foo(long)", MethodUtils.invokeMethod(testBean, "foo",
-                NumberUtils.LONG_ONE));
-        assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo",
-                NumberUtils.DOUBLE_ONE));
-        assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo",
-                "a", "b", "c"));
-        assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo",
-                "a", "b", "c"));
-        assertEquals("foo(int, String...)", MethodUtils.invokeMethod(testBean, "foo",
-                5, "a", "b", "c"));
-        assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo",
-                1L, 2L));
-
+        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", (Object[]) null));
+        assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", null, null));
+        assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo", ""));
+        assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", new Object()));
+        assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", Boolean.TRUE));
+        assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.INTEGER_ONE));
+        assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.BYTE_ONE));
+        assertEquals("foo(long)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.LONG_ONE));
+        assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.DOUBLE_ONE));
+        assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", "a", "b", "c"));
+        assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", "a", "b", "c"));
+        assertEquals("foo(int, String...)", MethodUtils.invokeMethod(testBean, "foo", 5, "a", "b", "c"));
+        assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", 1L, 2L));
         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "foo", 1, 2));
-
-        TestBean.verify(new ImmutablePair<>("String...", new String[]{"x", "y"}),
-                MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
-        TestBean.verify(new ImmutablePair<>("Number...", new Number[]{17, 23, 42}),
-                MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
-        TestBean.verify(new ImmutablePair<>("String...", new String[]{"x", "y"}),
-                MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
-        TestBean.verify(new ImmutablePair<>("Number...", new Number[]{17, 23, 42}),
-                MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
-
+        TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
+        TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
+        TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
+        TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
         assertNullPointerException(() -> MethodUtils.invokeMethod(null, "foo", 1, 2));
-        assertNullPointerException(() -> MethodUtils.invokeMethod(testBean, null, 1, 2));
+        assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, null, 1, 2));
     }
 
     @Test
     void testInvokeMethod_VarArgsNotUniqueResolvable() throws Exception {
-      assertEquals("Boolean...", MethodUtils.invokeMethod(testBean, "varOverload",
-                                                         new Object[] {null}));
-      assertEquals("Object...", MethodUtils.invokeMethod(testBean, "varOverload",
-                                                         (Object[]) null));
+        assertEquals("Boolean...", MethodUtils.invokeMethod(testBean, "varOverload", new Object[] { null }));
+        assertEquals("Object...", MethodUtils.invokeMethod(testBean, "varOverload", (Object[]) null));
     }
 
     @Test
     void testInvokeMethod_VarArgsWithNullValues() throws Exception {
-        assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload",
-                "a", null, "c"));
-        assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload",
-                                                                "a", "b", null));
+        assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload", "a", null, "c"));
+        assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload", "a", "b", null));
     }
 
     @Test
@@ -1011,11 +994,8 @@ void testInvokeMethodForceAccessWithArgs() throws Exception {
         assertEquals("privateStringStuff(double)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", 5.0d));
         assertEquals("privateStringStuff(String)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", "Hi There"));
         assertEquals("privateStringStuff(Object)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", new Date()));
-
-        assertNullPointerException(
-                () -> MethodUtils.invokeMethod(null, true, "privateStringStuff", "Hi There"));
-        assertNullPointerException(
-                () -> MethodUtils.invokeMethod(testBean, true, null, "Hi There"));
+        assertNullPointerException(() -> MethodUtils.invokeMethod(null, true, "privateStringStuff", "Hi There"));
+        assertNullPointerException(() -> MethodUtils.invokeMethod(testBean, true, null, "Hi There"));
     }
 
     @Test


(commons-lang) 01/06: [javadoc] General improvements

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit dc9e94626e19615b8970e2ba2532a7d11ea8f5da
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jul 18 08:20:05 2025 -0400

    [javadoc] General improvements
---
 src/changes/changes.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index bdf00cd4e..606469e51 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -49,6 +49,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="fix" dev="ppkarwasz" due-to="Sebastian Steiner">[javadoc] Fix typo in Javadoc of Strings instances #1406.</action>
     <action                   type="fix" dev="ggregory" due-to="Hassan A Hashim">[javadoc] Fix Javadocs in ClassUtils #1410.</action>
     <action issue="LANG-1778" type="fix" dev="ggregory" due-to="wuwu2000">MethodUtils.getMatchingMethod() doesn't respect the hierarchy of methods #1414.</action>
+    <action                   type="fix" dev="ggregory" due-to="Gary Gregory">[javadoc] General improvements.</action>
     <!-- ADD -->
     <!-- UPDATE -->
   </release>