Fix ConstructorUtils.getMatchingAccessibleConstructor on non-public classes - #1793
Alwaysgaurav1 wants to merge 2 commits into
Conversation
|
Hi @garydgregory, This is a companion fix to #1783 ( While #1783 addressed method lookup on non-public classes, |
There was a problem hiding this comment.
🟢 Approval recommended
Accessibility handling is consistently fixed and covered by regression tests.
Pull request overview
Fixes constructor lookup and invocation accessibility handling for non-public classes and nested classes.
Changes:
- Enforces class-level accessibility checks.
- Validates exact constructor matches consistently.
- Adds regression tests for matching and invocation behavior.
File summaries
| File | Description |
|---|---|
src/test/java/org/apache/commons/lang3/reflect/ConstructorUtilsTest.java |
Adds coverage for non-public class scenarios. |
src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java |
Enforces accessibility consistently for constructors. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@Alwaysgaurav1 |
…ssibility behavior
|
Thanks for the review, @garydgregory! I have updated the class-level Javadoc in ConstructorUtils to remove the obsolete setAccessible(true) workaround description and explicitly document that constructor lookup methods return null and invocation methods throw NoSuchMethodException for non-public classes. |
Summary
Fixes
ConstructorUtils.getMatchingAccessibleConstructorandConstructorUtils.invokeConstructorto properly enforce class accessibility checks on non-public classes (e.g. package-private classes or public inner classes declared inside non-public outer classes), achieving consistency across exact matching, inexact matching, andMethodUtils(following PR #1783).Problem
In
ConstructorUtils.getMatchingAccessibleConstructor(Class<T> cls, Class<?>... parameterTypes):cls.getConstructor(parameterTypes)directly.Class.getConstructor(...)returns any constructor with thepublicmodifier, even if declaring classclsis package-private or enclosed in a non-public outer class.MemberUtils.setAccessibleWorkaround(...)directly and returned the constructor without verifying whetherclsis accessible.getAccessibleConstructor(ctor), which checksMemberUtils.isAccessible(ctor) && isAccessible(ctor.getDeclaringClass()).This created inconsistent behavior:
ConstructorUtils.getAccessibleConstructor(PackagePrivateBean.class, exactTypes)returnednull.ConstructorUtils.getMatchingAccessibleConstructor(PackagePrivateBean.class, inexactTypes)returnednull.ConstructorUtils.getMatchingAccessibleConstructor(PackagePrivateBean.class, exactTypes)bypassed the check and returned the constructor.ConstructorUtils.invokeConstructor(PackagePrivateBean.class, exactArgs)attempted reflective instantiation on non-public classes (violating access control and throwingIllegalAccessExceptionorInaccessibleObjectExceptionunder JPMS), whereas inexact arguments threwNoSuchMethodException("No such accessible constructor on object: ...").Changes
ConstructorUtils.java:getMatchingAccessibleConstructor:if (!isAccessible(cls)) return null;. Since constructors are never inherited and always belong to their declaring class, an inaccessible class can never have an accessible constructor.tryblock, verified the candidate usinggetAccessibleConstructor(cls.getConstructor(parameterTypes))before returning.getAccessibleConstructor(Class<T> cls, Class<?>... parameterTypes):if (!isAccessible(cls)) return null;for consistent fast-path checking.ConstructorUtilsTest.java:testGetMatchingAccessibleConstructorOnNonPublicClassasserting thatgetMatchingAccessibleConstructorreturnsnullfor non-public classes and public inner classes of non-public outer classes (for both exact and inexact signatures).testInvokeConstructorOnNonPublicClassandtestInvokeExactConstructorOnNonPublicClassasserting thatNoSuchMethodExceptionis consistently thrown.