[ 
https://issues.apache.org/jira/browse/LANG-1818?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Gary D. Gregory resolved LANG-1818.
-----------------------------------
    Fix Version/s: 3.21.0
       Resolution: Fixed

Thank you [~iponomarev] 

PR merged, 3.21.0-SNAPSHOT build deployed.

> ClassUtils.getShortClassName(Class) misinterprets '$' in legitimate class 
> names
> -------------------------------------------------------------------------------
>
>                 Key: LANG-1818
>                 URL: https://issues.apache.org/jira/browse/LANG-1818
>             Project: Commons Lang
>          Issue Type: Improvement
>            Reporter: Ivan Ponomarev
>            Priority: Minor
>             Fix For: 3.21.0
>
>
> h3.Description
> {{ClassUtils.getShortClassName(String)}} operates on JVM binary names and 
> necessarily relies on heuristics. As documented in its Javadoc, it cannot 
> reliably distinguish package names, outer classes, and inner classes in all 
> cases when given only a {{String}}.
> However, these limitations should not apply to {{getShortClassName(Class)}} 
> (and {{getShortClassName(Object))}}, which currently delegate to the 
> string-based method:
> {code:java}
> public static String getShortClassName(final Class<?> cls) {
>     if (cls == null) {
>         return StringUtils.EMPTY;
>     }
>     return getShortClassName(cls.getName());
> }
> {code}
> When a {{Class<?>}} instance is available, we have unambiguous metadata. 
> Delegating to the string-based implementation causes legitimate $ characters 
> in class identifiers to be incorrectly interpreted as inner-class separators.
> h3.Motivation
> Although uncommon, {{$}} is a valid character in Java identifiers and is used 
> in practice (e.g. generated code, DSL-heavy libraries, test fixtures, 
> Selenide library exports {{$}} and {{$$}} names). Treating every $ as an 
> inner-class separator leads to incorrect results even for top-level and 
> member classes.
> While this ambiguity is unavoidable for {{getShortClassName(String)}}, it is 
> avoidable for {{getShortClassName(Class)}}.
> h3.Reproducer
> {code:java}
> class $trange {}
> class Pa$$word {}
> class ClassUtilsShortClassNameTest {
>     class $Inner {}
>     class Inner {
>         class Ne$ted {}
>     }
>     @Test
>     void testDollarSignImmediatelyAfterPackage() {
>         assertEquals("$trange", ClassUtils.getShortClassName($trange.class));
>         // Actual (before fix): ".trange"
>     }
>     @Test
>     void testDollarSignWithinName() {
>         assertEquals("Pa$$word", 
> ClassUtils.getShortClassName(Pa$$word.class));
>         // Actual (before fix): "Pa..word"
>     }
>     @Test
>     void testMultipleDollarSigns() {
>         assertEquals(
>             getClass().getSimpleName() + ".$Inner",
>             ClassUtils.getShortClassName($Inner.class)
>         );
>         // Actual (before fix): "ClassUtilsShortClassNameTest..Inner"
>     }
>     @Test
>     void testNe$tedClassName() {
>         assertEquals(
>             getClass().getSimpleName() + ".Inner.Ne$ted",
>             ClassUtils.getShortClassName(Inner.Ne$ted.class)
>         );
>         // Actual (before fix): "ClassUtilsShortClassNameTest.Inner.Ne.ted"
>     }
> }
> {code}
> h3.Proposed fix
> * Reimplement {{getShortClassName(Class)}} using {{Class}} metadata 
> ({{getSimpleName()}}, {{getDeclaringClass()}}, {{getEnclosingClass()}}, array 
> component handling) instead of delegating to the string-based method.
> * Preserve existing behavior for local and anonymous classes 
> (compiler-generated ordinal names) by falling back to the legacy string-based 
> logic, ensuring backward compatibility with existing tests.
> * Leave {{getShortClassName(String)}} unchanged and continue to document its 
> inherent ambiguity.
> As a result: {{getShortCanonicalName(String)}} continues to rely on the 
> string-based implementation and remains subject to the documented 
> limitations; this is expected and unchanged. This change improves correctness 
> for the Class-based APIs without altering behavior for purely string-based 
> usage.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to