As reported in https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-October/082709.html
The static constructors of enum classes are executed at both CDS dump time and run time. E.g.,
public enum Modifier {
OPEN,
}
The Modifier::<clinit> method is a synthetic method created by javac. It essentially does this:
public static final Modifier OPEN = new Modifier("OPEN");
If a reference of Modifier.OPEN is stored inside the CDS archived heap, it will be different than the value of Modifier.OPEN that is re-created at runtime by the execution of Modifier.<clinit>
==============================
import java.lang.module.*;
import java.io.*;
import java.util.*;
public class EnumEquality {
public static void main(final String[] args) throws Exception {
String moduleName = "java.sql";
// load the "java.sql" module from boot layer
Optional<Module> bootModule = ModuleLayer.boot().findModule(moduleName);
if (bootModule.isEmpty()) {
throw new RuntimeException(moduleName + " module is missing in boot layer");
}
ModuleDescriptor m1 = bootModule.get().getDescriptor();
// now recreate the same module using the ModuleDescriptor.read on the module's module-info.class
ModuleDescriptor m2;
try (InputStream moduleInfo = bootModule.get().getResourceAsStream("module-info.class")) {
if (moduleInfo == null) {
throw new RuntimeException("Could not locate module-info.class in " + moduleName + " module");
}
// this will internally use a ModuleDescriptor.Builder to construct the ModuleDescriptor
m2 = ModuleDescriptor.read(moduleInfo);
}
if (!m1.equals(m2)) {
// root cause - the enums aren't "equal"
for (ModuleDescriptor.Requires r1 : m1.requires()) {
if (r1.name().equals("java.base")) {
for (ModuleDescriptor.Requires r2 : m2.requires()) {
if (r2.name().equals("java.base")) {
System.out.println("Modifiers r1 " + r1.modifiers() + " r2 " + r2.modifiers()
+ " --> equals? " + r1.modifiers().equals(r2.modifiers()));
}
}
}
}
throw new RuntimeException("ModuleDescriptor(s) aren't equal: \n" + m1 + "\n" + m2);
}
System.out.println("Success");
}
}