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