001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import org.apache.commons.lang3.math.NumberUtils; 020 021/** 022 * Enumerates all known versions of the Java specification. This is intended to mirror available values from the <em>java.specification.version</em> System 023 * property. 024 * 025 * @since 3.0 026 */ 027public enum JavaVersion { 028 029 /** 030 * The Java version reported by Android. This is not an official Java version number. 031 */ 032 JAVA_0_9(1.5f, "0.9"), 033 034 /** 035 * Java 1.1. 036 */ 037 JAVA_1_1(1.1f, "1.1"), 038 039 /** 040 * Java 1.2. 041 */ 042 JAVA_1_2(1.2f, "1.2"), 043 044 /** 045 * Java 1.3. 046 */ 047 JAVA_1_3(1.3f, "1.3"), 048 049 /** 050 * Java 1.4. 051 */ 052 JAVA_1_4(1.4f, "1.4"), 053 054 /** 055 * Java 1.5. 056 */ 057 JAVA_1_5(1.5f, "1.5"), 058 059 /** 060 * Java 1.6. 061 */ 062 JAVA_1_6(1.6f, "1.6"), 063 064 /** 065 * Java 1.7. 066 */ 067 JAVA_1_7(1.7f, "1.7"), 068 069 /** 070 * Java 1.8. 071 */ 072 JAVA_1_8(1.8f, "1.8"), 073 074 /** 075 * Java 1.9. 076 * 077 * @deprecated As of release 3.5, replaced by {@link #JAVA_9}. 078 */ 079 @Deprecated 080 JAVA_1_9(9.0f, "9"), 081 082 /** 083 * Java 9. 084 * 085 * @since 3.5 086 */ 087 JAVA_9(9.0f, "9"), 088 089 /** 090 * Java 10. 091 * 092 * @since 3.7 093 */ 094 JAVA_10(10.0f, "10"), 095 096 /** 097 * Java 11. 098 * 099 * @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 * Java 27. 210 * 211 * @since 3.21.0 212 */ 213 JAVA_27(27, "27"), 214 215 /** 216 * Java 28. 217 * 218 * @since 3.21.0 219 */ 220 JAVA_28(28, "28"), 221 222 /** 223 * The most recent Java version. Mainly introduced to avoid to break when a new version of Java is used. 224 */ 225 JAVA_RECENT(maxVersion(), Float.toString(maxVersion())); 226 227 /** 228 * Gets the enumeration constant corresponding to the given Java version string. This method is used internally. 229 * 230 * @param versionStr The Java version as string. 231 * @return The corresponding enumeration constant or {@code null} if the version is unknown. 232 */ 233 static JavaVersion get(final String versionStr) { 234 if (versionStr == null) { 235 return null; 236 } 237 switch (versionStr) { 238 case "0.9": 239 return JAVA_0_9; 240 case "1.1": 241 return JAVA_1_1; 242 case "1.2": 243 return JAVA_1_2; 244 case "1.3": 245 return JAVA_1_3; 246 case "1.4": 247 return JAVA_1_4; 248 case "1.5": 249 return JAVA_1_5; 250 case "1.6": 251 return JAVA_1_6; 252 case "1.7": 253 return JAVA_1_7; 254 case "1.8": 255 return JAVA_1_8; 256 case "9": 257 return JAVA_9; 258 case "10": 259 return JAVA_10; 260 case "11": 261 return JAVA_11; 262 case "12": 263 return JAVA_12; 264 case "13": 265 return JAVA_13; 266 case "14": 267 return JAVA_14; 268 case "15": 269 return JAVA_15; 270 case "16": 271 return JAVA_16; 272 case "17": 273 return JAVA_17; 274 case "18": 275 return JAVA_18; 276 case "19": 277 return JAVA_19; 278 case "20": 279 return JAVA_20; 280 case "21": 281 return JAVA_21; 282 case "22": 283 return JAVA_22; 284 case "23": 285 return JAVA_23; 286 case "24": 287 return JAVA_24; 288 case "25": 289 return JAVA_25; 290 case "26": 291 return JAVA_26; 292 case "27": 293 return JAVA_27; 294 case "28": 295 return JAVA_28; 296 default: 297 final float v = toFloatVersion(versionStr); 298 if (v - 1. < 1.) { // then we need to check decimals > .9 299 final int firstComma = Math.max(versionStr.indexOf('.'), versionStr.indexOf(',')); 300 // read up to the next separator if present, otherwise to the end of the string 301 // (this was previously an inverted Math.max that always selected the full string) 302 int end = versionStr.indexOf(',', firstComma + 1); 303 if (end == -1) { 304 end = versionStr.length(); 305 } 306 try { 307 if (Float.parseFloat(versionStr.substring(firstComma + 1, end)) > .9f) { 308 return JAVA_RECENT; 309 } 310 } catch (final NumberFormatException e) { 311 // malformed version string ("1.", "bogus"): the documented contract is to return null 312 // for unknown versions rather than propagate an exception, which would otherwise poison 313 // SystemUtils' static initializer for the class loader lifetime. 314 return null; 315 } 316 } else if (v > 10) { 317 return JAVA_RECENT; 318 } 319 return null; 320 } 321 } 322 323 /** 324 * Gets the enumeration constant corresponding to the given Java version string. This method is used internally. 325 * 326 * @param versionStr The Java version as string. 327 * @return The corresponding enumeration constant or {@code null} if the version is unknown. 328 */ 329 static JavaVersion getJavaVersion(final String versionStr) { 330 return get(versionStr); 331 } 332 333 /** 334 * Gets the Java Version from the system or 99.0 if the {@code java.specification.version} system property is not set. 335 * 336 * @return The value of {@code java.specification.version} system property or 99.0 if it is not set. 337 */ 338 private static float maxVersion() { 339 final float v = toFloatVersion(SystemProperties.getJavaSpecificationVersion("99.0")); 340 return v > 0 ? v : 99f; 341 } 342 343 static String[] split(final String value) { 344 return RegExUtils.VERSION_SPLIT_PATTERN.split(value); 345 } 346 347 /** 348 * Parses a float value from a String. 349 * 350 * @param value The String to parse. 351 * @return The float value represented by the string or -1 if the given String cannot be parsed. 352 */ 353 private static float toFloatVersion(final String value) { 354 final int defaultReturnValue = -1; 355 if (!value.contains(".")) { 356 return NumberUtils.toFloat(value, defaultReturnValue); 357 } 358 final String[] toParse = split(value); 359 if (toParse.length >= 2) { 360 return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue); 361 } 362 return defaultReturnValue; 363 } 364 365 /** 366 * The float value. 367 */ 368 private final float value; 369 370 /** 371 * The standard name. 372 */ 373 private final String name; 374 375 /** 376 * Constructs a new instance. 377 * 378 * @param value The float value. 379 * @param name The standard name, not null. 380 */ 381 JavaVersion(final float value, final String name) { 382 this.value = value; 383 this.name = name; 384 } 385 386 /** 387 * Tests whether this version of Java is at least the version of Java passed in. 388 * 389 * <p> 390 * For example: 391 * </p> 392 * 393 * <pre> 394 * {@code 395 * myVersion.atLeast(JavaVersion.JAVA_1_8) 396 * }</pre> 397 * 398 * @param requiredVersion The version to check against, not null. 399 * @return true if this version is equal to or greater than the specified version. 400 */ 401 public boolean atLeast(final JavaVersion requiredVersion) { 402 return this.value >= requiredVersion.value; 403 } 404 405 /** 406 * Tests whether this version of Java is at most the version of Java passed in. 407 * 408 * <p> 409 * For example: 410 * </p> 411 * 412 * <pre> 413 * {@code 414 * myVersion.atMost(JavaVersion.JAVA_1_4) 415 * }</pre> 416 * 417 * @param requiredVersion The version to check against, not null. 418 * @return true if this version is equal to or less than the specified version. 419 * @since 3.9 420 */ 421 public boolean atMost(final JavaVersion requiredVersion) { 422 return this.value <= requiredVersion.value; 423 } 424 425 /** 426 * The string value is overridden to return the standard name. 427 * 428 * <p> 429 * For example, {@code "1.5"}. 430 * </p> 431 * 432 * @return The name, not null. 433 */ 434 @Override 435 public String toString() { 436 return name; 437 } 438}