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 *      http://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 * <p>An enum representing all the versions of the Java specification.
023 * This is intended to mirror available values from the
024 * <em>java.specification.version</em> System property. </p>
025 *
026 * @since 3.0
027 */
028public enum JavaVersion {
029
030    /**
031     * The Java version reported by Android. This is not an official Java version number.
032     */
033    JAVA_0_9(1.5f, "0.9"),
034
035    /**
036     * Java 1.1.
037     */
038    JAVA_1_1(1.1f, "1.1"),
039
040    /**
041     * Java 1.2.
042     */
043    JAVA_1_2(1.2f, "1.2"),
044
045    /**
046     * Java 1.3.
047     */
048    JAVA_1_3(1.3f, "1.3"),
049
050    /**
051     * Java 1.4.
052     */
053    JAVA_1_4(1.4f, "1.4"),
054
055    /**
056     * Java 1.5.
057     */
058    JAVA_1_5(1.5f, "1.5"),
059
060    /**
061     * Java 1.6.
062     */
063    JAVA_1_6(1.6f, "1.6"),
064
065    /**
066     * Java 1.7.
067     */
068    JAVA_1_7(1.7f, "1.7"),
069
070    /**
071     * Java 1.8.
072     */
073    JAVA_1_8(1.8f, "1.8"),
074
075    /**
076     * Java 1.9.
077     *
078     * @deprecated As of release 3.5, replaced by {@link #JAVA_9}
079     */
080    @Deprecated
081    JAVA_1_9(9.0f, "9"),
082
083    /**
084     * Java 9
085     *
086     * @since 3.5
087     */
088    JAVA_9(9.0f, "9"),
089
090    /**
091     * Java 10
092     *
093     * @since 3.7
094     */
095    JAVA_10(10.0f, "10"),
096
097    /**
098     * Java 11
099     *
100     * @since 3.8
101     */
102    JAVA_11(11.0f, "11"),
103
104    /**
105     * The most recent java version. Mainly introduced to avoid to break when a new version of Java is used.
106     */
107    JAVA_RECENT(maxVersion(), Float.toString(maxVersion()));
108
109    /**
110     * The float value.
111     */
112    private final float value;
113
114    /**
115     * The standard name.
116     */
117    private final String name;
118
119    /**
120     * Constructor.
121     *
122     * @param value  the float value
123     * @param name  the standard name, not null
124     */
125    JavaVersion(final float value, final String name) {
126        this.value = value;
127        this.name = name;
128    }
129
130    //-----------------------------------------------------------------------
131    /**
132     * <p>Whether this version of Java is at least the version of Java passed in.</p>
133     *
134     * <p>For example:<br>
135     *  {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}<p>
136     *
137     * @param requiredVersion  the version to check against, not null
138     * @return true if this version is equal to or greater than the specified version
139     */
140    public boolean atLeast(final JavaVersion requiredVersion) {
141        return this.value >= requiredVersion.value;
142    }
143
144    /**
145     * Transforms the given string with a Java version number to the
146     * corresponding constant of this enumeration class. This method is used
147     * internally.
148     *
149     * @param nom the Java version as string
150     * @return the corresponding enumeration constant or <b>null</b> if the
151     * version is unknown
152     */
153    // helper for static importing
154    static JavaVersion getJavaVersion(final String nom) {
155        return get(nom);
156    }
157
158    /**
159     * Transforms the given string with a Java version number to the
160     * corresponding constant of this enumeration class. This method is used
161     * internally.
162     *
163     * @param nom the Java version as string
164     * @return the corresponding enumeration constant or <b>null</b> if the
165     * version is unknown
166     */
167    static JavaVersion get(final String nom) {
168        if ("0.9".equals(nom)) {
169            return JAVA_0_9;
170        } else if ("1.1".equals(nom)) {
171            return JAVA_1_1;
172        } else if ("1.2".equals(nom)) {
173            return JAVA_1_2;
174        } else if ("1.3".equals(nom)) {
175            return JAVA_1_3;
176        } else if ("1.4".equals(nom)) {
177            return JAVA_1_4;
178        } else if ("1.5".equals(nom)) {
179            return JAVA_1_5;
180        } else if ("1.6".equals(nom)) {
181            return JAVA_1_6;
182        } else if ("1.7".equals(nom)) {
183            return JAVA_1_7;
184        } else if ("1.8".equals(nom)) {
185            return JAVA_1_8;
186        } else if ("9".equals(nom)) {
187            return JAVA_9;
188        } else if ("10".equals(nom)) {
189            return JAVA_10;
190        } else if ("11".equals(nom)) {
191            return JAVA_11;
192        }
193        if (nom == null) {
194            return null;
195        }
196        final float v = toFloatVersion(nom);
197        if ((v - 1.) < 1.) { // then we need to check decimals > .9
198            final int firstComma = Math.max(nom.indexOf('.'), nom.indexOf(','));
199            final int end = Math.max(nom.length(), nom.indexOf(',', firstComma));
200            if (Float.parseFloat(nom.substring(firstComma + 1, end)) > .9f) {
201                return JAVA_RECENT;
202            }
203        } else if (v > 10) {
204            return JAVA_RECENT;
205        }
206        return null;
207    }
208
209    //-----------------------------------------------------------------------
210    /**
211     * <p>The string value is overridden to return the standard name.</p>
212     *
213     * <p>For example, <code>"1.5"</code>.</p>
214     *
215     * @return the name, not null
216     */
217    @Override
218    public String toString() {
219        return name;
220    }
221
222    /**
223     * Gets the Java Version from the system or 99.0 if the {@code java.specification.version} system property is not set.
224     *
225     * @return the value of {@code java.specification.version} system property or 99.0 if it is not set.
226     */
227    private static float maxVersion() {
228        final float v = toFloatVersion(System.getProperty("java.specification.version", "99.0"));
229        if (v > 0) {
230            return v;
231        }
232        return 99f;
233    }
234
235    /**
236     * Parses a float value from a String.
237     *
238     * @param value the String to parse.
239     * @return the float value represented by the string or -1 if the given String can not be parsed.
240     */
241    private static float toFloatVersion(final String value) {
242        final int defaultReturnValue = -1;
243        if (value.contains(".")) {
244            final String[] toParse = value.split("\\.");
245            if (toParse.length >= 2) {
246                return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue);
247            }
248        } else {
249            return NumberUtils.toFloat(value, defaultReturnValue);
250        }
251        return defaultReturnValue;
252    }
253}