View Javadoc
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      * The regex to split version strings.
202      */
203     private static final String VERSION_SPLIT_REGEX = "\\.";
204 
205     /**
206      * Transforms the given string with a Java version number to the
207      * corresponding constant of this enumeration class. This method is used
208      * internally.
209      *
210      * @param versionStr the Java version as string
211      * @return the corresponding enumeration constant or <strong>null</strong> if the
212      * version is unknown
213      */
214     static JavaVersion get(final String versionStr) {
215         if (versionStr == null) {
216             return null;
217         }
218         switch (versionStr) {
219         case "0.9":
220             return JAVA_0_9;
221         case "1.1":
222             return JAVA_1_1;
223         case "1.2":
224             return JAVA_1_2;
225         case "1.3":
226             return JAVA_1_3;
227         case "1.4":
228             return JAVA_1_4;
229         case "1.5":
230             return JAVA_1_5;
231         case "1.6":
232             return JAVA_1_6;
233         case "1.7":
234             return JAVA_1_7;
235         case "1.8":
236             return JAVA_1_8;
237         case "9":
238             return JAVA_9;
239         case "10":
240             return JAVA_10;
241         case "11":
242             return JAVA_11;
243         case "12":
244             return JAVA_12;
245         case "13":
246             return JAVA_13;
247         case "14":
248             return JAVA_14;
249         case "15":
250             return JAVA_15;
251         case "16":
252             return JAVA_16;
253         case "17":
254             return JAVA_17;
255         case "18":
256             return JAVA_18;
257         case "19":
258             return JAVA_19;
259         case "20":
260             return JAVA_20;
261         case "21":
262             return JAVA_21;
263         case "22":
264             return JAVA_22;
265         case "23":
266             return JAVA_23;
267         case "24":
268             return JAVA_24;
269         default:
270             final float v = toFloatVersion(versionStr);
271             if (v - 1. < 1.) { // then we need to check decimals > .9
272                 final int firstComma = Math.max(versionStr.indexOf('.'), versionStr.indexOf(','));
273                 final int end = Math.max(versionStr.length(), versionStr.indexOf(',', firstComma));
274                 if (Float.parseFloat(versionStr.substring(firstComma + 1, end)) > .9f) {
275                     return JAVA_RECENT;
276                 }
277             } else if (v > 10) {
278                 return JAVA_RECENT;
279             }
280             return null;
281         }
282     }
283 
284     /**
285      * Transforms the given string with a Java version number to the
286      * corresponding constant of this enumeration class. This method is used
287      * internally.
288      *
289      * @param versionStr the Java version as string
290      * @return the corresponding enumeration constant or <strong>null</strong> if the
291      * version is unknown
292      */
293     static JavaVersion getJavaVersion(final String versionStr) {
294         return get(versionStr);
295     }
296 
297     /**
298      * Gets the Java Version from the system or 99.0 if the {@code java.specification.version} system property is not set.
299      *
300      * @return the value of {@code java.specification.version} system property or 99.0 if it is not set.
301      */
302     private static float maxVersion() {
303         final float v = toFloatVersion(SystemProperties.getJavaSpecificationVersion("99.0"));
304         return v > 0 ? v : 99f;
305     }
306 
307     static String[] split(final String value) {
308         return value.split(VERSION_SPLIT_REGEX);
309     }
310 
311     /**
312      * Parses a float value from a String.
313      *
314      * @param value the String to parse.
315      * @return the float value represented by the string or -1 if the given String cannot be parsed.
316      */
317     private static float toFloatVersion(final String value) {
318         final int defaultReturnValue = -1;
319         if (!value.contains(".")) {
320             return NumberUtils.toFloat(value, defaultReturnValue);
321         }
322         final String[] toParse = split(value);
323         if (toParse.length >= 2) {
324             return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue);
325         }
326         return defaultReturnValue;
327     }
328 
329     /**
330      * The float value.
331      */
332     private final float value;
333 
334     /**
335      * The standard name.
336      */
337     private final String name;
338 
339     /**
340      * Constructs a new instance.
341      *
342      * @param value  the float value
343      * @param name  the standard name, not null
344      */
345     JavaVersion(final float value, final String name) {
346         this.value = value;
347         this.name = name;
348     }
349 
350     /**
351      * Tests whether this version of Java is at least the version of Java passed in.
352      *
353      * <p>For example:<br>
354      *  {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}</p>
355      *
356      * @param requiredVersion  the version to check against, not null
357      * @return true if this version is equal to or greater than the specified version
358      */
359     public boolean atLeast(final JavaVersion requiredVersion) {
360         return this.value >= requiredVersion.value;
361     }
362 
363     /**
364      * Tests whether this version of Java is at most the version of Java passed in.
365      *
366      * <p>For example:<br>
367      *  {@code myVersion.atMost(JavaVersion.JAVA_1_4)}</p>
368      *
369      * @param requiredVersion  the version to check against, not null
370      * @return true if this version is equal to or greater than the specified version
371      * @since 3.9
372      */
373     public boolean atMost(final JavaVersion requiredVersion) {
374         return this.value <= requiredVersion.value;
375     }
376 
377     /**
378      * The string value is overridden to return the standard name.
379      *
380      * <p>For example, {@code "1.5"}.</p>
381      *
382      * @return the name, not null
383      */
384     @Override
385     public String toString() {
386         return name;
387     }
388 }