1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3;
18
19 import org.apache.commons.lang3.math.NumberUtils;
20
21 /**
22 * Enumerates all known versions of the Java specification. This is intended to mirror available values from the <em>java.specification.version</em> System
23 * property.
24 *
25 * @since 3.0
26 */
27 public enum JavaVersion {
28
29 /**
30 * The Java version reported by Android. This is not an official Java version number.
31 */
32 JAVA_0_9(1.5f, "0.9"),
33
34 /**
35 * Java 1.1.
36 */
37 JAVA_1_1(1.1f, "1.1"),
38
39 /**
40 * Java 1.2.
41 */
42 JAVA_1_2(1.2f, "1.2"),
43
44 /**
45 * Java 1.3.
46 */
47 JAVA_1_3(1.3f, "1.3"),
48
49 /**
50 * Java 1.4.
51 */
52 JAVA_1_4(1.4f, "1.4"),
53
54 /**
55 * Java 1.5.
56 */
57 JAVA_1_5(1.5f, "1.5"),
58
59 /**
60 * Java 1.6.
61 */
62 JAVA_1_6(1.6f, "1.6"),
63
64 /**
65 * Java 1.7.
66 */
67 JAVA_1_7(1.7f, "1.7"),
68
69 /**
70 * Java 1.8.
71 */
72 JAVA_1_8(1.8f, "1.8"),
73
74 /**
75 * Java 1.9.
76 *
77 * @deprecated As of release 3.5, replaced by {@link #JAVA_9}.
78 */
79 @Deprecated
80 JAVA_1_9(9.0f, "9"),
81
82 /**
83 * Java 9.
84 *
85 * @since 3.5
86 */
87 JAVA_9(9.0f, "9"),
88
89 /**
90 * Java 10.
91 *
92 * @since 3.7
93 */
94 JAVA_10(10.0f, "10"),
95
96 /**
97 * Java 11.
98 *
99 * @since 3.8
100 */
101 JAVA_11(11.0f, "11"),
102
103 /**
104 * Java 12.
105 *
106 * @since 3.9
107 */
108 JAVA_12(12.0f, "12"),
109
110 /**
111 * Java 13.
112 *
113 * @since 3.9
114 */
115 JAVA_13(13.0f, "13"),
116
117 /**
118 * Java 14.
119 *
120 * @since 3.11
121 */
122 JAVA_14(14.0f, "14"),
123
124 /**
125 * Java 15.
126 *
127 * @since 3.11
128 */
129 JAVA_15(15.0f, "15"),
130
131 /**
132 * Java 16.
133 *
134 * @since 3.11
135 */
136 JAVA_16(16.0f, "16"),
137
138 /**
139 * Java 17.
140 *
141 * @since 3.12.0
142 */
143 JAVA_17(17.0f, "17"),
144
145 /**
146 * Java 18.
147 *
148 * @since 3.13.0
149 */
150 JAVA_18(18.0f, "18"),
151
152 /**
153 * Java 19.
154 *
155 * @since 3.13.0
156 */
157 JAVA_19(19.0f, "19"),
158
159 /**
160 * Java 20.
161 *
162 * @since 3.13.0
163 */
164 JAVA_20(20, "20"),
165
166 /**
167 * Java 21.
168 *
169 * @since 3.13.0
170 */
171 JAVA_21(21, "21"),
172
173 /**
174 * Java 22.
175 *
176 * @since 3.15.0
177 */
178 JAVA_22(22, "22"),
179
180 /**
181 * Java 23.
182 *
183 * @since 3.18.0
184 */
185 JAVA_23(23, "23"),
186
187 /**
188 * Java 24.
189 *
190 * @since 3.18.0
191 */
192 JAVA_24(24, "24"),
193
194 /**
195 * Java 25.
196 *
197 * @since 3.20.0
198 */
199 JAVA_25(25, "25"),
200
201 /**
202 * Java 26.
203 *
204 * @since 3.20.0
205 */
206 JAVA_26(26, "26"),
207
208 /**
209 * The most recent Java version. Mainly introduced to avoid to break when a new version of Java is used.
210 */
211 JAVA_RECENT(maxVersion(), Float.toString(maxVersion()));
212
213 /**
214 * Transforms the given string with a Java version number to the corresponding constant of this enumeration class. This method is used internally.
215 *
216 * @param versionStr the Java version as string
217 * @return the corresponding enumeration constant or <strong>null</strong> if the version is unknown
218 */
219 static JavaVersion get(final String versionStr) {
220 if (versionStr == null) {
221 return null;
222 }
223 switch (versionStr) {
224 case "0.9":
225 return JAVA_0_9;
226 case "1.1":
227 return JAVA_1_1;
228 case "1.2":
229 return JAVA_1_2;
230 case "1.3":
231 return JAVA_1_3;
232 case "1.4":
233 return JAVA_1_4;
234 case "1.5":
235 return JAVA_1_5;
236 case "1.6":
237 return JAVA_1_6;
238 case "1.7":
239 return JAVA_1_7;
240 case "1.8":
241 return JAVA_1_8;
242 case "9":
243 return JAVA_9;
244 case "10":
245 return JAVA_10;
246 case "11":
247 return JAVA_11;
248 case "12":
249 return JAVA_12;
250 case "13":
251 return JAVA_13;
252 case "14":
253 return JAVA_14;
254 case "15":
255 return JAVA_15;
256 case "16":
257 return JAVA_16;
258 case "17":
259 return JAVA_17;
260 case "18":
261 return JAVA_18;
262 case "19":
263 return JAVA_19;
264 case "20":
265 return JAVA_20;
266 case "21":
267 return JAVA_21;
268 case "22":
269 return JAVA_22;
270 case "23":
271 return JAVA_23;
272 case "24":
273 return JAVA_24;
274 case "25":
275 return JAVA_25;
276 default:
277 final float v = toFloatVersion(versionStr);
278 if (v - 1. < 1.) { // then we need to check decimals > .9
279 final int firstComma = Math.max(versionStr.indexOf('.'), versionStr.indexOf(','));
280 final int end = Math.max(versionStr.length(), versionStr.indexOf(',', firstComma));
281 if (Float.parseFloat(versionStr.substring(firstComma + 1, end)) > .9f) {
282 return JAVA_RECENT;
283 }
284 } else if (v > 10) {
285 return JAVA_RECENT;
286 }
287 return null;
288 }
289 }
290
291 /**
292 * Transforms the given string with a Java version number to the corresponding constant of this enumeration class. This method is used internally.
293 *
294 * @param versionStr the Java version as string
295 * @return the corresponding enumeration constant or <strong>null</strong> if the version is unknown
296 */
297 static JavaVersion getJavaVersion(final String versionStr) {
298 return get(versionStr);
299 }
300
301 /**
302 * Gets the Java Version from the system or 99.0 if the {@code java.specification.version} system property is not set.
303 *
304 * @return the value of {@code java.specification.version} system property or 99.0 if it is not set.
305 */
306 private static float maxVersion() {
307 final float v = toFloatVersion(SystemProperties.getJavaSpecificationVersion("99.0"));
308 return v > 0 ? v : 99f;
309 }
310
311 static String[] split(final String value) {
312 return RegExUtils.VERSION_SPLIT_PATTERN.split(value);
313 }
314
315 /**
316 * Parses a float value from a String.
317 *
318 * @param value the String to parse.
319 * @return the float value represented by the string or -1 if the given String cannot be parsed.
320 */
321 private static float toFloatVersion(final String value) {
322 final int defaultReturnValue = -1;
323 if (!value.contains(".")) {
324 return NumberUtils.toFloat(value, defaultReturnValue);
325 }
326 final String[] toParse = split(value);
327 if (toParse.length >= 2) {
328 return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue);
329 }
330 return defaultReturnValue;
331 }
332
333 /**
334 * The float value.
335 */
336 private final float value;
337
338 /**
339 * The standard name.
340 */
341 private final String name;
342
343 /**
344 * Constructs a new instance.
345 *
346 * @param value the float value
347 * @param name the standard name, not null
348 */
349 JavaVersion(final float value, final String name) {
350 this.value = value;
351 this.name = name;
352 }
353
354 /**
355 * Tests whether this version of Java is at least the version of Java passed in.
356 *
357 * <p>
358 * For example:
359 * </p>
360 *
361 * <pre>
362 * {@code
363 * myVersion.atLeast(JavaVersion.JAVA_1_8)
364 * }</pre>
365 *
366 * @param requiredVersion the version to check against, not null
367 * @return true if this version is equal to or greater than the specified version
368 */
369 public boolean atLeast(final JavaVersion requiredVersion) {
370 return this.value >= requiredVersion.value;
371 }
372
373 /**
374 * Tests whether this version of Java is at most the version of Java passed in.
375 *
376 * <p>
377 * For example:
378 * </p>
379 *
380 * <pre>
381 * {@code
382 * myVersion.atMost(JavaVersion.JAVA_1_4)
383 * }</pre>
384 *
385 * @param requiredVersion the version to check against, not null
386 * @return true if this version is equal to or greater than the specified version
387 * @since 3.9
388 */
389 public boolean atMost(final JavaVersion requiredVersion) {
390 return this.value <= requiredVersion.value;
391 }
392
393 /**
394 * The string value is overridden to return the standard name.
395 *
396 * <p>
397 * For example, {@code "1.5"}.
398 * </p>
399 *
400 * @return the name, not null
401 */
402 @Override
403 public String toString() {
404 return name;
405 }
406 }