[LANG-1771] Handle malformed array input '[String' in getShortCanonicalName#1391
[LANG-1771] Handle malformed array input '[String' in getShortCanonicalName#1391abhisripathi wants to merge 4 commits intoapache:masterfrom
Conversation
garydgregory
left a comment
There was a problem hiding this comment.
@abhisripathi
Please remove "countUpperCaseLetters" as it has nothing to do with this PR.
|
|
||
| @Test | ||
| public void test_getShortCanonicalName_MalformedInput() { | ||
| String input = "[String"; |
There was a problem hiding this comment.
Inline all of these local variables.
There was a problem hiding this comment.
Thanks for the feedback, Gary!
I’ve removed the unrelated countUpperCaseLetters code and inlined the local variables in the test as requested.
Let me know if anything else needs to be updated.
a5e5ac4 to
91368c0
Compare
garydgregory
left a comment
There was a problem hiding this comment.
Hello @abhisripathi
Thank you for your update. Please see my comments.
| className = reverseAbbreviationMap.get(className.substring(0, 1)); | ||
| } | ||
| // else if (!className.isEmpty()) { | ||
| // className = reverseAbbreviationMap.get(className.substring(0, 1)); |
There was a problem hiding this comment.
Why is this comment needed?
There was a problem hiding this comment.
Good point — I’ve removed the commented-out code to keep the file clean. It was left in unintentionally during the initial iteration. Thanks for pointing it out!
| assertFalse(StringUtils.isAllUpperCase("A/C")); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Run mvn by itself to catch all build errors.
There was a problem hiding this comment.
Ran mvn clean install and the full build passed successfully.
There was a problem hiding this comment.
That's not the same as running 'mvn' solo which runs the default Maven goal which contains all build checks.
There was a problem hiding this comment.
Ran mvn standalone — all build checks, Javadoc, RAT, and Checkstyle passed with BUILD SUCCESS.
Let me know if anything else is needed!
| // else if (!className.isEmpty()) { | ||
| // className = reverseAbbreviationMap.get(className.substring(0, 1)); | ||
| // } | ||
| else if (!className.isEmpty() && className.length() == 1 && reverseAbbreviationMap.containsKey(className)) { |
There was a problem hiding this comment.
If the length is 1, then it can't be empty, or am I missing something?
There was a problem hiding this comment.
You're right — since className.length() == 1, the string can’t be empty.
I'm planning to remove the !className.isEmpty() check and keep just className.length() == 1 — does that sound good?
There was a problem hiding this comment.
You're right — since className.length() == 1, the string can’t be empty. I'm planning to remove the !className.isEmpty() check and keep just className.length() == 1 — does that sound good?
You tell me! ;-) Does this change need more test coverage? Are all formats for canonical names tested?
There was a problem hiding this comment.
I reviewed the test suite and found that most formats (primitive, object arrays, inner classes, null) are already covered. I’ve added tests specifically for the malformed descriptors [String and [LString which are directly related to this fix.
91368c0 to
b051362
Compare
b051362 to
4c7ecd9
Compare
|
-1: Hm, now that I look at this PR again, this test doesn't make sense: We would be inventing a new syntax for array type names. I don't see where the JRE, Java Language Specification, or Java VM Specification allows such a syntax. The legal values are:
For example: assertEquals("String[]", ClassUtils.getShortCanonicalName(String[].class.getName()));
assertEquals("String[]", ClassUtils.getShortCanonicalName(String[].class.getCanonicalName()));
assertEquals("String[]", ClassUtils.getShortCanonicalName("String[]")); |
|
Hi Gary, |
|
Hello @abhisripathi I don't think we should return bad output for bad input; bad input should throw an IAE. Unfortunately, the current implementation is inconsistent, sometimes it throws an exception, sometimes it's GIGO. For example (now in git master): // Note that we throw RuntimeException (but not which one) for the following bad inputs:
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName(""));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("["));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("[]"));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("[;"));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("[];"));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName(" "));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("[$"));
assertThrows(RuntimeException.class, () -> ClassUtils.getShortCanonicalName("[$a"));We should probably re-implement the heart of this parsing using regular expressions instead of custom code. |
|
Thanks for the clarification, Gary — that makes sense. |
garydgregory
left a comment
There was a problem hiding this comment.
@abhisripathi
It looks to me like your assumptions on legal inputs are incorrect. Please see my comments.
|
|
||
| @Test | ||
| public void test_getShortCanonicalName_MalformedInput() { | ||
| assertEquals("String[]", ClassUtils.getShortCanonicalName("[String")); |
There was a problem hiding this comment.
I do not see how "[String" is a legal name, but "[Ljava.lang.String;" is legal. Do you read the JLS to allow this? For an unpackaged class Foo, an array would be "[LFoo;".
| } | ||
| @Test | ||
| public void test_getShortCanonicalName_MissingSemicolon() { | ||
| assertEquals("String[]", ClassUtils.getShortCanonicalName("[LString")); |
There was a problem hiding this comment.
I do not see how "[LString" is a legal name, but "[Ljava.lang.String;" is legal. Do you read the JLS to allow this? For an unpackaged class Foo, an array would be "[LFoo;".
|
Closing in favor of #1437 |
This PR fixes issue LANG-1771 where the input "[String" was incorrectly interpreted as "short[]" by the getShortCanonicalName method in ClassUtils.
✅ Root Cause:
The internal descriptor parser treated the first character 'S' from "String" as a JVM type abbreviation for short.
✅ Fix:
✅ Tests:
Closes: https://issues.apache.org/jira/browse/LANG-1771