ADDITIONAL SYSTEM INFORMATION :
OS = Windows 11, but I am 99% certain that this occurs for most Windows Operating systems. The relevant ones to test would be Windows 10 and Windows 8.
$ javac --version
javac 18
$ java --version
java 18 2022-03-22
Java(TM) SE Runtime Environment (build 18+36-2087)
Java HotSpot(TM) 64-Bit Server VM (build 18+36-2087, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
Here is a relevant StackOverflow post -- https://stackoverflow.com/q/72438283/10118965
On Windows, if I have an ABC.java and an Abc.java in the same folder, then they are treated as the same filename, and thus, forbidden, as you cannot have duplicate filenames in the same folder. That is because Windows is case-insensitive.
Java, on the other hand, IS case-sensitive. Therefore, ABC.java and Abc.java are considered meaningfully unique type names, and thus, are permitted.
This causes problems when making local classes (and maybe other parts of Java too). In the attached example, I have a local enum called ABC inside of method1(), and another local enum called Abc inside of method2(). Then, I use the following command to compile the class.
javac ClassLoaderIssue.java
Then I use the following command to run it.
java ClassLoaderIssue
Which then throws the following error.
Error: Could not find or load main class ClassLoaderIssue
Caused by: java.lang.NoClassDefFoundError: io/github/davidalayachew/ClassLoaderIssue (wrong name: ClassLoaderIssue)
If you look at the folder to see the generated .class files, you will see that there was only 1 of the local enums generated. On my machine, I see that only ClassLoaderIssue$1ABC.class was created, but there was no ClassLoaderIssue$1Abc.class. That is because Java treats these 2 names is unique, and therefore, is unable to create 2 different files of the same name. If I had to guess, the first local enum is created, and then the second one is created and either overwrites the first one, or silently fails to create a file.
Regardless, the point is, this is a problem. As you can see, this is a Windows specific problem, but if I am on a Linux system (or another operating system that IS case sensitive), then this problem will not exist.
I believe there is a very easy and simple fix here - simply increment the number when creating the local enum. Doing so should solve the problem, whether or not the underlying operating is case sensitive or case insensitive.
So, the expected output of compiling this program should be something like the following.
ClassLoaderIssue.class
ClassLoaderIssue$1ABC.class
ClassLoaderIssue$2Abc.class
This way, we can be case sensitive regardless of the underlying operating system file name case sensitivity.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1 - Create a new folder named ClassLoaderIssue
2 - Place the attached ClassLoaderIssue.java file into that folder
3 - Open a command line terminal and navigate into the above folder containing the above file
4 - Enter the following command
javac ClassLoaderIssue.java
5 - Look at the contents of the folder. If you are using CommandPrompt, that would be dir. If you are using a Linux system, that would be ls
6 - Notice how there is only ClassLoaderIssue.java, and then only a single ClassLoaderIssue$1...........java file. We should expect 2 files of that format because there are 2 local enums inside of ClassLoaderIssue.java
7 - Execute the following command
java ClassLoaderIssue
8 - If you are running this on Windows, you should receive the error mentioned in the description
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected my class to run without error
ACTUAL -
It received the following error upon execution
Error: Could not find or load main class ClassLoaderIssue
Caused by: java.lang.NoClassDefFoundError: io/github/davidalayachew/ClassLoaderIssue (wrong name: ClassLoaderIssue)
---------- BEGIN SOURCE ----------
/** There seems to be a class loader error when running the below method in main(). */
public class ClassLoaderIssue
{
/** Method 1. */
private void method1()
{
enum ABC { A, B, C, ; }
System.out.println(ABC.A);
}
/** Method 2. */
private void method2()
{
enum Abc { A, B, C, ; }
System.out.println(Abc.A);
}
/**
*
* Main method.
*
* @param args commandline arguments that we don't care about for this example.
*
*/
public static void main(String[] args)
{
new ClassLoaderIssue().method1();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I could rename the enum. Regardless, this is still a problem and something that definitely needs to be fixed.
FREQUENCY : always