All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.helper.JavaVersion Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Tomas Kraus, Peter Benedikovic - initial API and implementation
package org.eclipse.persistence.internal.helper;

import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;

/**
 * Java version storage class. Used for version numbers retrieved from
 * Java specification version string. Stored version is in
 * <major>.<minor> format.
 * @author Tomas Kraus, Peter Benedikovic
 */
public final class JavaVersion {

    /** JavaEE platform version elements separator character. */
    public static final char SEPARATOR = '.';

    /** JavaEE platform patch version element separator character. */
    public static final char PATCH_SEPARATOR = '_';

    /** Java VM version system property name. */
    public static final String VM_VERSION_PROPERTY = "java.specification.version";

    /**
     * Compiled regular expression pattern to read individual version number components.
     * Expected input is string like java version "1.6" or 9.
     */
    private static final Pattern VM_VERSION_PATTERN = Pattern.compile(
            "[^0-9]*([0-9]+)(\\.([0-9]+))*"
    );

    /** Number of Matcher groups (REGEX tokens) expected in Java VM
     *  version output. */
    private static final int VM_MIN_VERSION_TOKENS = 1;

    /**
     * Retrieves Java specification version {@see String} from JDK system property.
     * @return Java specification version {@see String} from JDK system property.
     */
    public static String vmVersionString() {
        return PrivilegedAccessHelper.getSystemProperty(VM_VERSION_PROPERTY);
    }

    // EclipseLink still supports JDK <9 so using Runtime.Version to retrieve
    // current JDK version is optional and can only be done trough reflection calls.
    // TODO: Remove reflection after JDK <9 support is dropped.

    /** JDK 9+ java.lang.Runtime.Version class name. */
    private static final String VERSION_CLASS_NAME = "java.lang.Runtime$Version";

    /** JDK 9+ java.lang.Runtime static version() method name. */
    private static final String RUNTIME_VERSION_METHOD_NAME = "version";

    /**
     * Invoke {@code Runtime#version()} method to retrieve {@code Runtime.Version} instance.
     * @return {@code Runtime.Version} instance for JDK 9 and later or {@code null} otherwise.
     */
    private static Object runtimeVersionObject() {
        try {
            final Method m = Runtime.class.getMethod(RUNTIME_VERSION_METHOD_NAME);
            return m.invoke(null);
        // Do not log, because AbstractSessionLog.getLog() causes cyclic dependency on ClassConstants during class initialization.
        // NoSuchMethodException: JDK <9, can't use java.lang.Runtime.Version.
        } catch (NoSuchMethodException e) {
            return null;
        // Other ReflectiveOperationException should not happen here. Otherwise throw it as RuntimeException.
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Invoke {@code Runtime.Version} method with given name ({@code major} or {@code minor}) to retrieve version numbers.
     * @param vClass {@code Runtime.Version} class.
     * @param vObj {@code Runtime.Version} class instance containing JDK version information.
     * @param name name of {@code Runtime.Version} instance method to invoke.
     */
    private static Integer getRuntimeVersionNumber(final Object vObj, final String name) {
        try {
            final Method m = vObj.getClass().getMethod(name);
            return (Integer) m.invoke(vObj);
        // Do not log, because AbstractSessionLog.getLog() causes cyclic dependency on ClassConstants during class initialization.
        // ReflectiveOperationException should not happen here. Otherwise throw it as RuntimeException.
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Retrieve JDK version numbers from {@code Runtime.Version} instance returned by {@code Runtime#version()} method.
     * This works only for JDK 9 and later.
     * @return Current JDK version for JDK 9 and later or {@code null} otherwise or when any problem with version retrieval happened.
     */
    private static JavaVersion runtimeVersion() {
        final Object vObj = runtimeVersionObject();
        if (vObj == null) {
            return null;
        }
        final Integer major = getRuntimeVersionNumber(vObj, "major");
        final Integer minor = getRuntimeVersionNumber(vObj, "minor");
        if (major != null && minor != null) {
            return new JavaVersion(major, minor);
        }
        return null;
    }

    /**
     * Parse Java specification version from JDK system property provided as an argument.
     * Version string should look like:
    *
  • "MA.MI" *
* Where
    *
  • MA is major version number, *
  • MI is minor version number *
* Label java version is parsed as non case sensitive. * @return Current JDK version for any JDK from system property. */ private static JavaVersion propertyVersionParser(final String version) { final Matcher matcher = VM_VERSION_PATTERN.matcher(version); int major = 0, minor = 0; if (matcher.find()) { major = Integer.parseInt(matcher.group(1)); String min = matcher.group(VM_MIN_VERSION_TOKENS + 2); minor = min != null ? Integer.parseInt(min) : 0; } return new JavaVersion(major, minor); } /** * Retrieve Java specification version from JDK system property. * @return Current JDK version for any JDK from system property. */ private static JavaVersion propertyVersion() { return propertyVersionParser(vmVersionString()); } /** * Java specification version detector. */ public static JavaVersion vmVersion() { final JavaVersion version = runtimeVersion(); return version != null ? version : propertyVersion(); } /** Major version number. */ private final int major; /** Minor version number. */ private final int minor; /** * Constructs an instance of Java specification version number. * @param major Major version number. * @param minor Minor version number. */ public JavaVersion(final int major, final int minor) { this.major = major; this.minor = minor; } /** * Get major version number. * @return Major version number. */ public final int getMajor() { return major; } /** * Get minor version number. * @return Minor version number. */ public final int getMinor() { return minor; } /** * Compares this JavaVersion object against another one. * @param version JavaVersion object to compare with * this object. * @return Compare result:
    *
  • Value 1 if this value * is greater than supplied version value. *
  • Value -1 if this value * is lesser than supplied version value. *
  • Value 0 if both this value * and supplied version values are equal. *
*/ public final int comapreTo(final JavaVersion version) { return this.major > version.major ? 1 : this.major < version.major ? -1 : this.minor > version.minor ? 1 : this.minor < version.minor ? -1 : 0; } /** * Return String representation of Java VM version object. * @return Java VM version string. */ @Override public final String toString() { final StringBuilder sb = new StringBuilder(3); sb.append(major); sb.append(SEPARATOR); sb.append(minor); return sb.toString(); } /** * Return {@link JavaSEPlatform} matching this Java SE specification version. * @return {@link JavaSEPlatform} matching this Java SE specification version * or {@code JavaSEPlatform.DEFAULT} as default when platform matching fails. */ public final JavaSEPlatform toPlatform() { return JavaSEPlatform.toValue(major, minor); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy