    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}