24
24
import java .util .Optional ;
25
25
import java .util .stream .Stream ;
26
26
27
- import static org .exist .start .CompatibleJavaVersionCheck .IncompatibleJavaVersion .IncompatibleJavaVersion ;
27
+ import static org .exist .start .CompatibleJavaVersionCheck .IncompatibleJavaVersion .create ;
28
28
import static org .exist .start .Main .ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED ;
29
29
30
+ /**
31
+ * Helper class for checking OpenJDK compatibility.
32
+ * <p>
33
+ * eXist-db has been compiled with Java21 (state of 2025Q2).
34
+ * <p>
35
+ * Older versions of Java contained a number of (runtime) HotSpot compiler bugs that caused database corruptions.
36
+ * These problematic versions are deprecated, and therefore, this class is not relevant anymore.
37
+ * <p>
38
+ * The code is kept for archival purposes and potential future re-usage.
39
+ * <p>
40
+ * ----------------------------
41
+ * <p>
42
+ * OpenJDK versions 12 through 15.0.1 suffer from a critical bug in the JIT C2 compiler that will
43
+ * cause data loss in eXist-db. The problem has been reported to the OpenJDK community.
44
+ * <p>
45
+ * For more information, see:
46
+ * - <a href="https://bugs.openjdk.java.net/browse/JDK-8253191">C2: Masked byte comparisons with large masks produce wrong result on x86</a>
47
+ * - <a href="https://github.com/eXist-db/exist/issues/3375">eXist-db does not run correctly on JDKs 12, 13, 14 and 15 #3375</a>
48
+ *
49
+ *
50
+ */
30
51
public class CompatibleJavaVersionCheck {
31
52
32
53
private static final IncompatibleJavaVersion [] INCOMPATIBLE_JAVA_VERSIONS = {
33
- IncompatibleJavaVersion (12 ),
34
- IncompatibleJavaVersion (13 ),
35
- IncompatibleJavaVersion (14 ),
36
- IncompatibleJavaVersion (15 , 0 , 2 )
54
+ create (12 ),
55
+ create (13 ),
56
+ create (14 ),
57
+ IncompatibleJavaVersion . create (15 , 0 , 2 ),
37
58
};
38
59
39
60
private static final String INCOMPATIBLE_JAVA_VERSION_NOTICE =
40
- "*****************************************************%n" +
41
- "Warning: Unreliable Java version has been detected!%n" +
42
- "%n" +
43
- "OpenJDK versions 12 through 15.0.1 suffer from a critical%n" +
44
- " bug in the JIT C2 compiler that will cause data loss in%n" +
45
- "eXist-db.%n" +
46
- "%n" +
47
- "The problem has been reported to the OpenJDK community.%n" +
48
- "%n" +
49
- "For more information, see:%n" +
50
- "\t * https://bugs.openjdk.java.net/browse/JDK-8253191%n" +
51
- "\t * https://github.com/eXist-db/exist/issues/3375%n" +
52
- "%n" +
53
- "The detected version of Java on your system is: %s.%n" +
54
- "%n" +
55
- "To prevent potential data loss, eXist-db will not be started.%n" +
56
- "To start eXist-db, we recommend using Java 8 or 11.%n" +
57
- "*****************************************************" ;
61
+ "*****************************************************%n"
62
+ + "Incorrect version of Java detected!%n"
63
+ + "%n"
64
+ + "The detected version of Java on your system is: %s.%n"
65
+ + "%n"
66
+ + "eXist-db has been developed and qualified using Java 21.%n"
67
+ + "%n"
68
+ + "Newer versions of Java might or might not work correctly.%n"
69
+ + "*****************************************************" ;
58
70
59
71
private static final Optional <String > RUNTIME_JAVA_VERSION = Optional .ofNullable (System .getProperty ("java.version" ));
60
72
@@ -71,16 +83,18 @@ public static void checkForCompatibleJavaVersion() throws StartException {
71
83
static void checkForCompatibleJavaVersion (final Optional <String > checkJavaVersion ) throws StartException {
72
84
final Optional <int []> maybeJavaVersionComponents = extractJavaVersionComponents (checkJavaVersion );
73
85
74
- if (! maybeJavaVersionComponents .isPresent ()) {
86
+ if (maybeJavaVersionComponents .isEmpty ()) {
75
87
// Could not determine major java version, so best to let the user proceed...
76
88
return ;
77
89
}
78
90
79
91
// check for incompatible java version
80
92
final int [] javaVersionComponents = maybeJavaVersionComponents .get ();
81
93
final int majorJavaVersion = javaVersionComponents [0 ];
82
- /* @Nullable */ final Integer minorJavaVersion = javaVersionComponents .length > 1 ? javaVersionComponents [1 ] : null ;
83
- /* @Nullable */ final Integer patchJavaVersion = javaVersionComponents .length > 2 ? javaVersionComponents [2 ] : null ;
94
+ /* @Nullable */
95
+ final Integer minorJavaVersion = javaVersionComponents .length > 1 ? javaVersionComponents [1 ] : null ;
96
+ /* @Nullable */
97
+ final Integer patchJavaVersion = javaVersionComponents .length > 2 ? javaVersionComponents [2 ] : null ;
84
98
85
99
for (final IncompatibleJavaVersion incompatibleJavaVersion : INCOMPATIBLE_JAVA_VERSIONS ) {
86
100
// compare major versions
@@ -104,7 +118,8 @@ static void checkForCompatibleJavaVersion(final Optional<String> checkJavaVersio
104
118
}
105
119
106
120
// version is NOT compatible!
107
- throw new StartException (ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED , String .format (INCOMPATIBLE_JAVA_VERSION_NOTICE , RUNTIME_JAVA_VERSION ));
121
+ throw new StartException (ERROR_CODE_INCOMPATIBLE_JAVA_DETECTED ,
122
+ String .format (INCOMPATIBLE_JAVA_VERSION_NOTICE , RUNTIME_JAVA_VERSION .orElse ("UKNOWN" )));
108
123
}
109
124
110
125
// version is compatible
@@ -131,22 +146,22 @@ static class IncompatibleJavaVersion {
131
146
/* @Nullable */ final Integer lessThanMinor ;
132
147
/* @Nullable */ final Integer lessThanPatch ;
133
148
134
- private IncompatibleJavaVersion (final int major , /* @Nullable */ Integer lessThanMinor , /* @Nullable */ Integer lessThanPatch ) {
149
+ private IncompatibleJavaVersion (final int major , /* @Nullable */ final Integer lessThanMinor , /* @Nullable */ final Integer lessThanPatch ) {
135
150
this .major = major ;
136
151
this .lessThanMinor = lessThanMinor ;
137
152
this .lessThanPatch = lessThanPatch ;
138
153
}
139
154
140
- public static IncompatibleJavaVersion IncompatibleJavaVersion (final int major , /* @Nullable */ Integer lessThanMinor , /* @Nullable */ Integer lessThanPatch ) {
155
+ public static IncompatibleJavaVersion create (final int major , /* @Nullable */ final Integer lessThanMinor , /* @Nullable */ final Integer lessThanPatch ) {
141
156
return new IncompatibleJavaVersion (major , lessThanMinor , lessThanPatch );
142
157
}
143
158
144
- public static IncompatibleJavaVersion IncompatibleJavaVersion (final int major , /* @Nullable */ Integer lessThanMinor ) {
145
- return IncompatibleJavaVersion (major , lessThanMinor , null );
159
+ public static IncompatibleJavaVersion create (final int major , /* @Nullable */ final Integer lessThanMinor ) {
160
+ return new IncompatibleJavaVersion (major , lessThanMinor , null );
146
161
}
147
162
148
- public static IncompatibleJavaVersion IncompatibleJavaVersion (final int major ) {
149
- return IncompatibleJavaVersion (major , null , null );
163
+ public static IncompatibleJavaVersion create (final int major ) {
164
+ return new IncompatibleJavaVersion (major , null , null );
150
165
}
151
166
}
152
167
}
0 commit comments