This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 824837751 Fix ConstructorUtils.getMatchingAccessibleConstructor on
non-public classes (#1793)
824837751 is described below
commit 82483775157159a8edcc9220498f034fa1621611
Author: gaurav kumar pandey <[email protected]>
AuthorDate: Sat Sep 19 20:16:42 2026 +0530
Fix ConstructorUtils.getMatchingAccessibleConstructor on non-public classes
(#1793)
* Fix ConstructorUtils.getMatchingAccessibleConstructor on non-public
classes
* Update ConstructorUtils class-level Javadoc for non-public class
accessibility behavior
---
.../commons/lang3/reflect/ConstructorUtils.java | 26 +++++++++------
.../lang3/reflect/ConstructorUtilsTest.java | 38 ++++++++++++++++++++++
2 files changed, 54 insertions(+), 10 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 cee2ebca5..860622f1f 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
@@ -28,16 +28,13 @@
* Utility reflection methods focused on constructors, modeled after {@link
MethodUtils}.
*
* <h2>Known Limitations</h2>
- * <h3>Accessing Public Constructors In A Default Access Superclass</h3>
+ * <h3>Accessing Constructors In A Non-Public Class</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>
- * {@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.
+ * Constructors in non-public classes (such as package-private classes or
classes enclosed in non-public classes) are
+ * not accessible. Methods such as {@link #getAccessibleConstructor(Class,
Class[])} and
+ * {@link #getMatchingAccessibleConstructor(Class, Class[])} return {@code
null} when invoked on non-public classes.
+ * Consequently, invocation methods such as {@link #invokeConstructor(Class,
Object...)} and
+ * {@link #invokeExactConstructor(Class, Object...)} throw a {@link
NoSuchMethodException}.
* </p>
*
* @since 2.5
@@ -64,6 +61,9 @@ public class ConstructorUtils {
*/
public static <T> Constructor<T> getAccessibleConstructor(final Class<T>
cls, final Class<?>... parameterTypes) {
Objects.requireNonNull(cls, "cls");
+ if (!isAccessible(cls)) {
+ return null;
+ }
try {
return
getAccessibleConstructor(cls.getConstructor(parameterTypes));
} catch (final NoSuchMethodException e) {
@@ -114,10 +114,16 @@ public static <T> Constructor<T>
getAccessibleConstructor(final Constructor<T> c
*/
public static <T> Constructor<T> getMatchingAccessibleConstructor(final
Class<T> cls, final Class<?>... parameterTypes) {
Objects.requireNonNull(cls, "cls");
+ if (!isAccessible(cls)) {
+ return null;
+ }
// see if we can find the constructor directly
// most of the time this works and it's much faster
try {
- return
MemberUtils.setAccessibleWorkaround(cls.getConstructor(parameterTypes));
+ final Constructor<T> ctor =
getAccessibleConstructor(cls.getConstructor(parameterTypes));
+ if (ctor != null) {
+ return MemberUtils.setAccessibleWorkaround(ctor);
+ }
} catch (final NoSuchMethodException ignored) {
// ignore
}
diff --git
a/src/test/java/org/apache/commons/lang3/reflect/ConstructorUtilsTest.java
b/src/test/java/org/apache/commons/lang3/reflect/ConstructorUtilsTest.java
index 9bb73ae98..5bbe2c627 100644
--- a/src/test/java/org/apache/commons/lang3/reflect/ConstructorUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/reflect/ConstructorUtilsTest.java
@@ -46,6 +46,8 @@ private static class BaseClass {
}
static class PrivateClass {
+ private final String value;
+
@SuppressWarnings("unused")
public static class PublicInnerClass {
public PublicInnerClass() {
@@ -54,6 +56,19 @@ public PublicInnerClass() {
@SuppressWarnings("unused")
public PrivateClass() {
+ this("default");
+ }
+
+ public PrivateClass(final String value) {
+ this.value = value;
+ }
+
+ public PrivateClass(final Number number) {
+ this.value = String.valueOf(number);
+ }
+
+ public String getValue() {
+ return value;
}
}
@@ -242,6 +257,29 @@ void testVarArgsUnboxing() throws Exception {
assertArrayEquals(new String[] { "2", "3" }, testBean.varArgs);
}
+ @Test
+ void testGetMatchingAccessibleConstructorOnNonPublicClass() {
+
assertNull(ConstructorUtils.getMatchingAccessibleConstructor(PrivateClass.class));
+
assertNull(ConstructorUtils.getMatchingAccessibleConstructor(PrivateClass.class,
String.class));
+
assertNull(ConstructorUtils.getMatchingAccessibleConstructor(PrivateClass.class,
Integer.class));
+
assertNull(ConstructorUtils.getMatchingAccessibleConstructor(PrivateClass.PublicInnerClass.class));
+ }
+
+ @Test
+ void testInvokeConstructorOnNonPublicClass() {
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeConstructor(PrivateClass.class));
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeConstructor(PrivateClass.class, "test"));
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeConstructor(PrivateClass.class, Integer.valueOf(1)));
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeConstructor(PrivateClass.PublicInnerClass.class));
+ }
+
+ @Test
+ void testInvokeExactConstructorOnNonPublicClass() {
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeExactConstructor(PrivateClass.class));
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeExactConstructor(PrivateClass.class, "test"));
+ assertThrows(NoSuchMethodException.class, () ->
ConstructorUtils.invokeExactConstructor(PrivateClass.PublicInnerClass.class));
+ }
+
private String toString(final Class<?>[] c) {
return Arrays.asList(c).toString();
}