Bug 525854 - Fix Java SE platform detection and clean up platform code

Signed-off-by: Tomas Kraus <tomas.kraus@oracle.com>
Reviewed-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/framework/ReflectionHelper.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/framework/ReflectionHelper.java
index 1a17232..4d1c9c4 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/framework/ReflectionHelper.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/framework/ReflectionHelper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2017 Oracle and/or its affiliates.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -145,6 +145,25 @@ public static final Object invokeMethod(
     }
 
     /**
+     * Invoke a method of the specified class instance.
+     * @param name Method name.
+     * @param obj Class instance containing method to invoke.
+     * @param parameterTypes Method parameter array.
+     * @param returnType Class to be returned.
+     * @param args An array of objects to be passed as arguments to the method call
+     * @throws InvocationTargetException If the underlying constructor throws an exception.
+     * @throws IllegalArgumentException  If an unwrapping conversion fails.
+     * @throws IllegalAccessException    If the underlying field is either inaccessible or final.
+     * @throws SecurityException         If a security manager is present and access to the field was denied.
+     * @throws NoSuchMethodException     If a field with the specified name is not found.
+     */
+    public static final <T> T invokeMethod(
+            final String name, final Object obj, final Class<?>[] parameterTypes, final Class<T> returnType, final Object... args)
+            throws ReflectiveOperationException {
+        return returnType.cast(invokeMethod(name, obj, parameterTypes, args));
+    }
+
+    /**
      * Invoke static method of the specified class.
      * @param name Method name.
      * @param c Class containing method to invoke.
@@ -171,4 +190,23 @@ public static final Object invokeStaticMethod(
         return result;
     }
 
+    /**
+     * Invoke static method of the specified class.
+     * @param name Method name.
+     * @param c Class containing method to invoke.
+     * @param parameterTypes Method parameter array.
+     * @param returnType Class to be returned.
+     * @param args An array of objects to be passed as arguments to the method call
+     * @throws InvocationTargetException If the underlying constructor throws an exception.
+     * @throws IllegalArgumentException  If an unwrapping conversion fails.
+     * @throws IllegalAccessException    If the underlying field is either inaccessible or final.
+     * @throws SecurityException         If a security manager is present and access to the field was denied.
+     * @throws NoSuchMethodException     If a field with the specified name is not found.
+     */
+    public static final <T> T invokeStaticMethod(
+            final String name, final Class c, final Class<?>[] parameterTypes, final Class<T> returnType, final Object... args)
+            throws ReflectiveOperationException {
+        return returnType.cast(invokeStaticMethod(name, c, parameterTypes, args));
+    }
+
 }
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/HelperTestModel.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/HelperTestModel.java
index 749c894..0df39e3 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/HelperTestModel.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/HelperTestModel.java
@@ -31,6 +31,7 @@ public static TestSuite getDataTypeComparisonTestSuite() {
         suite.setDescription("This suite tests common helper methods and methods which compare data types");
 
         suite.addTestSuite(org.eclipse.persistence.testing.tests.helper.JavaUtilTest.class);
+        suite.addTestSuite(org.eclipse.persistence.testing.tests.helper.JavaVersionTest.class);
 
         suite.addTest(new CompareArrayContentTest());
         suite.addTest(new CompareArrayLengthTest());
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaUtilTest.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaUtilTest.java
index c513c3d..035c3fd 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaUtilTest.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaUtilTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 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 v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -14,6 +14,7 @@
 
 import org.eclipse.persistence.internal.helper.JavaSEPlatform;
 import org.eclipse.persistence.internal.helper.JavaVersion;
+import org.eclipse.persistence.testing.framework.ReflectionHelper;
 import org.junit.Test;
 
 /**
@@ -22,6 +23,51 @@
  */
 public class JavaUtilTest extends junit.framework.TestCase {
 
+    // Valid version number pairs.
+    static final int[][] VALID = {
+            {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9},
+            {9, 0}, {10, 0}, {18, 3}, {18, 9}
+    };
+
+    // Invalid version number pairs.
+    static final int[][] INVALID = {
+            {0, 0}, {0, 1}, {0, 3}, {0, 5}, {0, 7}, {0, 9},
+            {1, 0}, {2, 0}, {2, 1}, {2, 2}, {3, 0}, {4, 0}, {1, 10},
+            {18, 1}, {18, 2}, {18, 4}, {18, 5}, {18, 6}, {18, 7}, {18, 8}, {18, 10}, {18, 11}, {18, 12}
+    };
+
+    // DEFAULT platform value.
+    static final JavaSEPlatform LATEST = initDefault();
+
+    /** Version numbers result mapping. Covers exceptions.
+     * See also {@code JavaSEPlatform.stringValuesMap} initialization code
+     * and {@link JavaSEPlatform#toValue(int, int)}.
+     * 1.9 -> 9.0
+     * @param version source version numbers
+     * @return result version numbers
+     */
+    static int[] resultMapping(int[] version) {
+        switch (version[0]) {
+            case 1:
+                switch (version[1]) {
+                    case 9: return new int[] {9, 0};
+                    default: return version;
+                }
+            default: return version;
+        }
+    }
+
+    /**
+     * Initialize value of JavaSEPlatform.DEFAULT.
+     * @return value of JavaSEPlatform.DEFAULT.
+     */
+    private static final JavaSEPlatform initDefault() {
+        try {
+            return ReflectionHelper.getPrivateStatic(JavaSEPlatform.class, "LATEST");
+        } catch (ReflectiveOperationException e) {
+            return null;
+        }
+    }
     /**
      * Constructs an instance of Java utilities.
      * @param name java.lang.String
@@ -62,31 +108,28 @@ public void testJavaVersion() {
      */
     @Test
     public void testStringToPlatform() {
-        // Valid version number pairs.
-        int[][] valid = {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7},
-                {1, 8}, {1, 9}, {9, 0}};
-        int[][] invalid = {{0, 0}, {0, 1}, {0, 3}, {0, 5}, {0, 7}, {0, 9},
-                {1, 0}, {2, 0}, {2, 1}, {2, 2}, {3, 0}, {4, 0}, {1, 10}};
         // Verify valid pairs.
-        for (int [] version : valid) {
+        for (int [] version : VALID) {
             int major = version[0];
             int minor = version[1];
             String versionString = JavaSEPlatform.versionString(major, minor);
             JavaSEPlatform platform = JavaSEPlatform.toValue(versionString);
             assertNotNull("There should exist platform for valid platform"
-                    +" version numbers.", platform);
+                    +" version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", platform);
+            int[] result = resultMapping(version);
             assertTrue("Returned platform version numbers do not match provided"
-                    + " version numbers", major == platform.getMajor()
-                    && minor == platform.getMinor());
+                    + " version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]",
+                    result[0] == platform.getMajor() && result[1] == platform.getMinor());
         }
         // Invalid version number pairs.
-        for (int [] version : invalid) {
+        for (int [] version : INVALID) {
             int major = version[0];
             int minor = version[1];
             String versionString = JavaSEPlatform.versionString(major, minor);
             JavaSEPlatform platform = JavaSEPlatform.toValue(major, minor);
-            assertNull("Returned platform shall be null for invalid version "
-                    + "number", platform);
+            assertTrue("Returned platform shall be JavaSEPlatform.DEFAULT for invalid version "
+                    + "number ["+Integer.toString(major)+","+Integer.toString(minor)+"]",
+                    LATEST.getMajor() == platform.getMajor() && LATEST.getMinor() == platform.getMinor());
         }
     }
 
@@ -96,29 +139,26 @@ public void testStringToPlatform() {
      */
     @Test
     public void testMajorMinorToPlatform() {
-        // Valid version number pairs.
-        int[][] valid = {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7},
-                {1, 8}, {1, 9}, {9, 0}};
-        int[][] invalid = {{0, 0}, {0, 1}, {0, 3}, {0, 5}, {0, 7}, {0, 9},
-                {1, 0}, {2, 0}, {2, 1}, {2, 2}, {3, 0}, {4, 0}, {1, 10}};
         // Verify valid pairs.
-        for (int [] version : valid) {
+        for (int [] version : VALID) {
             int major = version[0];
             int minor = version[1];
             JavaSEPlatform platform = JavaSEPlatform.toValue(major, minor);
             assertNotNull("There should exist platform for valid platform"
-                    +" version numbers.", platform);
+                    +" version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", platform);
+            int[] result = resultMapping(version);
             assertTrue("Returned platform version numbers do not match provided"
-                    + " version numbers", major == platform.getMajor()
-                    && minor == platform.getMinor());
+                    + " version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]",
+                    result[0] == platform.getMajor() && result[1] == platform.getMinor());
         }
         // Invalid version number pairs.
-        for (int [] version : invalid) {
+        for (int [] version : INVALID) {
             int major = version[0];
             int minor = version[1];
             JavaSEPlatform platform = JavaSEPlatform.toValue(major, minor);
-            assertNull("Returned platform shall be null for invalid version "
-                    + "number", platform);
+            assertTrue("Returned platform shall be JavaSEPlatform.DEFAULT for invalid version "
+                    + "number ["+Integer.toString(major)+","+Integer.toString(minor)+"]",
+                    LATEST.getMajor() == platform.getMajor() && LATEST.getMinor() == platform.getMinor());
         }
     }
 
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaVersionTest.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaVersionTest.java
new file mode 100644
index 0000000..3625beb
--- /dev/null
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/helper/JavaVersionTest.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2017 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 v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Tomas Kraus - 2017/10/11
+ *          Bug 525854 - Fix Java SE platform detection and clean up platform code
+ ******************************************************************************/
+package org.eclipse.persistence.testing.tests.helper;
+
+import java.lang.reflect.Method;
+
+import org.eclipse.persistence.internal.helper.JavaSEPlatform;
+import org.eclipse.persistence.internal.helper.JavaVersion;
+import org.eclipse.persistence.testing.framework.ReflectionHelper;
+import org.junit.Test;
+
+import junit.framework.TestCase;
+
+public class JavaVersionTest extends TestCase {
+
+    /**
+     * Check whether current Java has {@code Runtime.Version} class.
+     * @return Value of {@code true} when current Java has {@code Runtime.Version} class or {@code false} otherwise.
+     */
+    private static boolean hasRuntimeVersion() {
+        final Method[] methods = Runtime.class.getDeclaredMethods();
+        for (final Method method : methods) {
+            if ("version".equals(method.getName()) && method.getParameterCount() == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test Java version retrieval from {@code Runtime.Version}. It just calls {@code JavaVersion#runtimeVersion()} method
+     * on current Java SE when >9 and checks that no exception is thrown.
+     */
+    @Test
+    public void testRuntimeVersion() {
+        if (!hasRuntimeVersion()) {
+            return;
+        }
+        try {
+            final JavaVersion version =  ReflectionHelper.<JavaVersion>invokeStaticMethod("runtimeVersion", JavaVersion.class, null, JavaVersion.class);
+            assertTrue("Minimal Java 9 required", version.getMajor() >= 9);
+        } catch (ReflectiveOperationException e) {
+            fail("Exception: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Test Java version retrieval from {@code java.specification.version} system property. It just calls
+     * {@code JavaVersion#propertyVersionParser(String)} method with current Java SE {@code java.specification.version}
+     * system property value and checks that no exception is thrown.
+     */
+    @Test
+    public void testPropertyVersion() {
+        try {
+            final String versionString = ReflectionHelper.<String>invokeStaticMethod(
+                    "vmVersionString", JavaVersion.class, null, String.class);
+            final JavaVersion version =  ReflectionHelper.<JavaVersion>invokeStaticMethod(
+                    "propertyVersionParser", JavaVersion.class, new Class[] {String.class}, JavaVersion.class, versionString);
+        } catch (ReflectiveOperationException e) {
+            fail("Exception: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Verify Java version parser on set of valid and invalid {@code java.specification.version} system property values.
+     * Because all version strings are in {@code [0-9]+'.'[0-9]+} format, parser shall always return {@code JavaVersion}
+     * instance containing provided version numbers.
+     */
+    @Test
+    public void testPropertyVersionParser() {
+        // Verify valid pairs.
+        for (final int [] version : JavaUtilTest.VALID) {
+            final int major = version[0];
+            final int minor = version[1];
+            final String versionString = JavaSEPlatform.versionString(major, minor);
+            try {
+                final JavaVersion javaVersion =  ReflectionHelper.<JavaVersion>invokeStaticMethod(
+                        "propertyVersionParser", JavaVersion.class, new Class[] {String.class}, JavaVersion.class, versionString);
+                assertNotNull("JavaVersion instance must be returned for valid platform"
+                        +" version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", javaVersion);
+                assertTrue("Returned JavaVersion instance numbers do not match provided"
+                        + " version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", major == javaVersion.getMajor()
+                        && minor == javaVersion.getMinor());
+            } catch (ReflectiveOperationException e) {
+                fail("Exception: " + e.getMessage());
+            }
+        }
+        // Verify invalid pairs.
+        for (final int [] version : JavaUtilTest.INVALID) {
+            final int major = version[0];
+            final int minor = version[1];
+            final String versionString = JavaSEPlatform.versionString(major, minor);
+            try {
+                final JavaVersion javaVersion =  ReflectionHelper.<JavaVersion>invokeStaticMethod(
+                        "propertyVersionParser", JavaVersion.class, new Class[] {String.class}, JavaVersion.class, versionString);
+                assertNotNull("JavaVersion instance must be returned for invalid platform"
+                        +" version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", javaVersion);
+                assertTrue("Returned JavaVersion instance numbers do not match provided"
+                        + " version number ["+Integer.toString(major)+","+Integer.toString(minor)+"]", major == javaVersion.getMajor()
+                        && minor == javaVersion.getMinor());
+            } catch (ReflectiveOperationException e) {
+                fail("Exception: " + e.getMessage());
+            }
+        }
+    }
+
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/Version.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/Version.java
index 9c4b6bb..4339695 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/Version.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/Version.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 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 v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -15,8 +15,6 @@
  ******************************************************************************/
 package org.eclipse.persistence;
 
-import org.eclipse.persistence.internal.helper.JavaSEPlatform;
-
 /**
  * This class stores variables for the version and build numbers that are used
  * in printouts and exceptions.
@@ -44,40 +42,13 @@ public class Version {
     /** Version numbers separator. */
     private static final char SEPARATOR = '.';
 
-    // This is replaced by JavaSEPlatform. It's here just because of backward compatibility.
-    /**
-     * Keep track of JDK version in order to make some decisions about data structures.
-     * @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7.
-     */
-    @Deprecated
-    public static final int JDK_VERSION_NOT_SET = 0;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static final int JDK_1_5 = 1;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static final int JDK_1_6 = 2;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static final int JDK_1_7 = 3;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static final int JDK_1_8 = 4;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static final int JDK_1_9 = 5;
-    /** @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7. */
-    @Deprecated
-    public static int JDK_VERSION = JDK_VERSION_NOT_SET;
-
     /**
      * Returns version {@link String} containing three part version number
      * and build qualifier.
      * @return Version {@link String}.
      */
-    public static String getVersionString ( ) {
-        StringBuilder sb = new StringBuilder(
-                version.length() + 1 + qualifier.length());
+    public static String getVersionString() {
+        StringBuilder sb = new StringBuilder(version.length() + 1 + qualifier.length());
         sb.append(version);
         sb.append(SEPARATOR);
         sb.append(qualifier);
@@ -120,127 +91,17 @@ public static String getBuildType() {
         return buildType;
     }
 
-    /**
-     * INTERNAL:
-     * Return the JDK version we are using.
-     * @deprecated Use {@code JavaSEPlatform.CURRENT} instead.
-     *             Will be removed in 2.7.
-     */
-    @Deprecated
-    public static int getJDKVersion() {
-        switch(JavaSEPlatform.CURRENT) {
-            case v1_7:
-                JDK_VERSION = JDK_1_7;
-                break;
-            case v1_8:
-                JDK_VERSION = JDK_1_8;
-                break;
-            case v1_9:
-            case v9_0:
-                JDK_VERSION = JDK_1_9;
-                break;
-            default:
-                throw new IllegalStateException("Running on unsupported Java SE: "
-                        + JavaSEPlatform.CURRENT.toString());
-        }
-        return JDK_VERSION;
+    public static void printVersion() {
+        System.out.println(getVersionString());
     }
 
-    /**
-     * Set 1.5 as current Java SE version.
-     * @throws UnsupportedOperationException when invoked because Java SE 1.5
-     *         is not supported by current EclipseLink.
-     * @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7.
-     */
-    @Deprecated
-    public static void useJDK15() {
-        throw new UnsupportedOperationException(
-                "Java SE 1.5 is not supported by current EclipseLink.");
-    }
-
-    /**
-     * Set 1.6 as current Java SE version.
-     * @throws UnsupportedOperationException when invoked because Java SE 1.6
-     *         is not supported by current EclipseLink.
-     * @deprecated Use {@link JavaSEPlatform} instead. Will be removed in 2.7.
-     */
-    @Deprecated
-    public static void useJDK16() {
-        throw new UnsupportedOperationException(
-                "Java SE 1.6 is not supported by current EclipseLink.");
-    }
-
-    // Public API wrapper, use JavaSEPlatform.is(JavaSEPlatform.v1_5)
-    // internally.
-    /**
-     * Check whether we are running on Java SE 1.5.
-     * This will always return {@code false} because Java SE 1.5 is not
-     * supported by current EclipseLink.
-     * @return Value of {@code true} when we do and value of {@code false}
-     *         when we do not run on Java SE 1.5.
-     */
-    public static boolean isJDK15() {
-        return JavaSEPlatform.is(JavaSEPlatform.v1_5);
-    }
-
-    // Public API wrapper, use JavaSEPlatform.is(JavaSEPlatform.v1_6)
-    // internally.
-    /**
-     * Check whether we are running on Java SE 1.6.
-     * This will always return {@code false} because Java SE 1.6 is not
-     * supported by current EclipseLink.
-     * @return Value of {@code true} when we do and value of {@code false}
-     *         when we do not run on Java SE 1.6.
-     */
-    public static boolean isJDK16() {
-        return JavaSEPlatform.is(JavaSEPlatform.v1_6);
-    }
-
-    // Public API wrapper, use JavaSEPlatform.is(JavaSEPlatform.v1_7)
-    // internally.
-    /**
-     * Check whether we are running on Java SE 1.7.
-     * @return Value of {@code true} when we do and value of {@code false}
-     *         when we do not run on Java SE 1.7.
-     */
-    public static boolean isJDK17() {
-        return JavaSEPlatform.is(JavaSEPlatform.v1_7);
-    }
-
-    // Public API wrapper, use JavaSEPlatform.is(JavaSEPlatform.v1_8)
-    // internally.
-    /**
-     * Check whether we are running on Java SE 1.8.
-     * @return Value of {@code true} when we do and value of {@code false}
-     *         when we do not run on Java SE 1.8.
-     */
-    public static boolean isJDK18() {
-        return JavaSEPlatform.is(JavaSEPlatform.v1_8);
-    }
-
-    // Public API wrapper, use JavaSEPlatform.is(JavaSEPlatform.v1_9)
-    // internally.
-    /**
-     * Check whether we are running on Java SE 1.9.
-     * @return Value of {@code true} when we do and value of {@code false}
-     *         when we do not run on Java SE 1.9.
-     */
-    public static boolean isJDK19() {
-        return JavaSEPlatform.is(JavaSEPlatform.v9_0) || JavaSEPlatform.is(JavaSEPlatform.v1_9);
-    }
-
-    public static void printVersion ( ) {
-        System.out.println( getVersionString() );
-    }
-
-    public static void main ( String[] args ) {
-        System.out.println(
-             "\n" + getProduct() + " (EclipseLink)"
-             + "\n   Build Version:   " + getVersionString()
-             + "\n   Build Qualifier: " + getQualifier()
-             + "\n   Build Date:      " + getBuildDate()
-             + "\n   Build Time:      " + getBuildTime()
-             + "\n   SVN Revision:    " + getBuildRevision()
-        );
+    public static void main(String[] args) {
+        System.out.println();
+        System.out.print(getProduct()); System.out.println(" (EclipseLink)");
+        System.out.print("   Build Version:   "); System.out.println(getVersionString());
+        System.out.print("   Build Qualifier: "); System.out.println(getQualifier());
+        System.out.print("   Build Date:      "); System.out.println(getBuildDate());
+        System.out.print("   Build Time:      "); System.out.println(getBuildTime());
+        System.out.print("   Build Revision:  "); System.out.println(getBuildRevision());
     }
 }
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK15Platform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK15Platform.java
deleted file mode 100644
index 5f468c2..0000000
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK15Platform.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0
- * which accompanies this distribution.
- * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *     Oracle - initial API and implementation from Oracle TopLink
- ******************************************************************************/
-package org.eclipse.persistence.internal.helper;
-
-import java.sql.SQLException;
-import java.util.regex.Pattern;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- *  INTERNAL:
- *  Implements operations specific to JDK 1.5
- */
-public class JDK15Platform implements JDKPlatform {
-
-    /**
-     * PERF: The like expression compiled Pattern objects are cached
-     * to avoid re-compilation on every usage.
-     */
-    protected static final ConcurrentHashMap patternCache = new ConcurrentHashMap();
-
-    /**
-     * PERF: The regular expression compiled Pattern objects are cached
-     * to avoid re-compilation on every usage.
-     */
-    protected static final ConcurrentHashMap regexpPatternCache = new ConcurrentHashMap();
-
-    /**
-     * INTERNAL:
-     * An implementation of in memory queries with Like which uses the
-     * regular expression framework.
-     */
-    public Boolean conformLike(Object left, Object right) {
-        if ((left == null) && (right == null)) {
-            return Boolean.TRUE;
-        } else if ((left == null) || (right == null)) {
-            return Boolean.FALSE;
-        }
-        left = String.valueOf(left);
-        right = String.valueOf(right);
-        // PERF: First check the pattern cache for the pattern.
-        // Note that the original string is the key, to avoid having to translate it first.
-        Pattern pattern = (Pattern)patternCache.get(right);
-        if (pattern == null) {
-            // Bug 3936427 - Replace regular expression reserved characters with escaped version of those characters
-            // For instance replace ? with \?
-            String convertedRight = Helper.convertLikeToRegex((String)right);
-
-            pattern = Pattern.compile(convertedRight);
-            // Ensure cache does not grow beyond 100.
-            if (patternCache.size() > 100) {
-                patternCache.remove(patternCache.keySet().iterator().next());
-            }
-            patternCache.put(right, pattern);
-        }
-        boolean match = pattern.matcher((String)left).matches();
-        if (match) {
-            return Boolean.TRUE;
-        } else {
-            return Boolean.FALSE;
-        }
-    }
-
-    /**
-     * INTERNAL:
-     * An implementation of in memory queries with Regexp which uses the
-     * regular expression framework.
-     */
-    public Boolean conformRegexp(Object left, Object right) {
-        if ((left == null) && (right == null)) {
-            return Boolean.TRUE;
-        } else if ((left == null) || (right == null)) {
-            return Boolean.FALSE;
-        }
-        left = String.valueOf(left);
-        right = String.valueOf(right);
-        // PERF: First check the pattern cache for the pattern.
-        // Note that the original string is the key, to avoid having to translate it first.
-        Pattern pattern = (Pattern)regexpPatternCache.get(right);
-        if (pattern == null) {
-            pattern = Pattern.compile((String)right);
-            // Ensure cache does not grow beyond 100.
-            if (regexpPatternCache.size() > 100) {
-                regexpPatternCache.remove(regexpPatternCache.keySet().iterator().next());
-            }
-            regexpPatternCache.put(right, pattern);
-        }
-        boolean match = pattern.matcher((String)left).matches();
-        if (match) {
-            return Boolean.TRUE;
-        } else {
-            return Boolean.FALSE;
-        }
-    }
-
-    /**
-     * Indicates whether the passed object implements java.sql.SQLXML introduced in jdk 1.6
-     */
-    public boolean isSQLXML(Object object) {
-        return false;
-    }
-
-    /**
-     * Casts the passed object to SQLXML and calls getString and free methods
-     */
-    public String getStringAndFreeSQLXML(Object sqlXml) throws SQLException {
-        return null;
-    }
-}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK16Platform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK16Platform.java
deleted file mode 100644
index 813c36b..0000000
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDK16Platform.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2011, 2015 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 v1.0 and Eclipse Distribution License v. 1.0
- * which accompanies this distribution.
- * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *     ailitchev - 2010/08/19
- *          Bug 322960 - TWO TESTS IN CUSTOMFEATURESJUNITTESTSUITE FAILED WITH 11.2.0.2 DRIVER
- ******************************************************************************/
-package org.eclipse.persistence.internal.helper;
-
-import java.sql.SQLException;
-import java.sql.SQLXML;
-
-/**
- *  INTERNAL:
- *  Implements operations specific to JDK 1.6
- */
-public class JDK16Platform extends JDK15Platform {
-
-    /**
-     * Indicates whether the passed object implements java.sql.SQLXML introduced in jdk 1.6
-     */
-    public boolean isSQLXML(Object object) {
-        return (object instanceof SQLXML);
-    }
-
-    /**
-     * Casts the passed object to SQLXML and calls getString and free methods
-     */
-    public String getStringAndFreeSQLXML(Object sqlXml) throws SQLException {
-        String str = ((SQLXML)sqlXml).getString();
-        ((SQLXML)sqlXml).free();
-        return str;
-    }
-}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDKPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDKPlatform.java
deleted file mode 100644
index 7b7ded6..0000000
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JDKPlatform.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0
- * which accompanies this distribution.
- * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * Contributors:
- *     Oracle - initial API and implementation from Oracle TopLink
- ******************************************************************************/
-package org.eclipse.persistence.internal.helper;
-
-import java.sql.SQLException;
-
-/**
- *  INTERNAL:
- *  Interface which abstracts the version of the JDK we are on.
- *  This should only implement methods that are dependent on JDK version
- *  The implementers should implement the minimum amount of functionality required to
- *  allow support of multiple versions of the JDK.
- *  @see JDK15Platform
- *  @see JavaPlatform
- *  @author Tom Ware
- */
-public interface JDKPlatform {
-
-    /**
-     * Conforming queries with LIKE will act differently in different JDKs.
-     */
-    Boolean conformLike(Object left, Object right);
-
-    /**
-     * Conforming queries with REGEXP will act differently in different JDKs.
-     */
-    Boolean conformRegexp(Object left, Object right);
-
-    /**
-     * Indicates whether the passed object implements java.sql.SQLXML introduced in jdk 1.6
-     */
-    boolean isSQLXML(Object object);
-
-    /**
-     * Casts the passed object to SQLXML and calls getString and free methods
-     */
-    String getStringAndFreeSQLXML(Object sqlXml) throws SQLException;
-}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaPlatform.java
index 9e2eb13..9cf4f9a 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaPlatform.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaPlatform.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 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 v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -9,16 +9,17 @@
  *
  * Contributors:
  *     Oracle - initial API and implementation from Oracle TopLink
+ *     ailitchev - 2010/08/19
+ *          Bug 322960 - TWO TESTS IN CUSTOMFEATURESJUNITTESTSUITE FAILED WITH 11.2.0.2 DRIVER
+ *     Tomas Kraus - 2017/10/11
+ *          Bug 525854 - Fix Java SE platform detection and clean up platform code
  ******************************************************************************/
 package org.eclipse.persistence.internal.helper;
 
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
 import java.sql.SQLException;
-
-import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
-import org.eclipse.persistence.internal.security.PrivilegedClassForName;
-import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
+import java.sql.SQLXML;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
 
 /**
  *  INTERNAL:
@@ -29,61 +30,75 @@
  *  @author Tom Ware
  */
 public class JavaPlatform {
-    protected static JDKPlatform platform = null;
 
     /**
-     *  INTERNAL:
-     *  Get the version of JDK being used from the Version class.
-     *  @return JDKPlatform a platform appropriate for the version of JDK being used.
+     * PERF: The like expression compiled Pattern objects are cached
+     * to avoid re-compilation on every usage.
      */
-    protected static JDKPlatform getPlatform() {
-        if (platform == null) {
-            if (JavaSEPlatform.CURRENT.atLeast(JavaSEPlatform.v1_6)) {
-                try {
-                    Class platformClass = null;
-                    // use class.forName() to avoid loading the JDK 1.6 class unless it is needed.
-                    if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
-                        try {
-                            platformClass = AccessController.doPrivileged(new PrivilegedClassForName("org.eclipse.persistence.internal.helper.JDK16Platform"));
-                        } catch (PrivilegedActionException exception) {
-                        }
-                    } else {
-                        platformClass = org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName("org.eclipse.persistence.internal.helper.JDK16Platform");
-                    }
-                    if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
-                        try {
-                            platform = (JDKPlatform)AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(platformClass));
-                        } catch (PrivilegedActionException exception) {
-                        }
-                    } else {
-                        platform = (JDKPlatform)PrivilegedAccessHelper.newInstanceFromClass(platformClass);
-                    }
-                } catch (Exception exception) {
-                }
-            }
-            if (platform == null) {
-                platform = new JDK15Platform();
-            }
-        }
-        return platform;
-    }
+    private static final ConcurrentHashMap patternCache = new ConcurrentHashMap();
 
     /**
-     *  INTERNAL:
-     *  Conform an expression which uses the operator "like" for an in-memory query
-     *  @return Boolean (TRUE, FALSE, null == unknown)
+     * PERF: The regular expression compiled Pattern objects are cached
+     * to avoid re-compilation on every usage.
+     */
+    private static final ConcurrentHashMap regexpPatternCache = new ConcurrentHashMap();
+
+    /**
+     * INTERNAL:
+     * An implementation of in memory queries with Like which uses the
+     * regular expression framework.
      */
     public static Boolean conformLike(Object left, Object right) {
-        return getPlatform().conformLike(left, right);
+        if ((left == null) && (right == null)) {
+            return Boolean.TRUE;
+        } else if ((left == null) || (right == null)) {
+            return Boolean.FALSE;
+        }
+        left = String.valueOf(left);
+        right = String.valueOf(right);
+        // PERF: First check the pattern cache for the pattern.
+        // Note that the original string is the key, to avoid having to translate it first.
+        Pattern pattern = (Pattern)patternCache.get(right);
+        if (pattern == null) {
+            // Bug 3936427 - Replace regular expression reserved characters with escaped version of those characters
+            // For instance replace ? with \?
+            String convertedRight = Helper.convertLikeToRegex((String)right);
+
+            pattern = Pattern.compile(convertedRight);
+            // Ensure cache does not grow beyond 100.
+            if (patternCache.size() > 100) {
+                patternCache.remove(patternCache.keySet().iterator().next());
+            }
+            patternCache.put(right, pattern);
+        }
+        return pattern.matcher((String)left).matches();
     }
 
     /**
-     *  INTERNAL:
-     *  Conform an expression which uses the operator "regexp" for an in-memory query
-     *  @return Boolean (TRUE, FALSE, null == unknown)
+     * INTERNAL:
+     * An implementation of in memory queries with Regexp which uses the
+     * regular expression framework.
      */
     public static Boolean conformRegexp(Object left, Object right) {
-        return getPlatform().conformRegexp(left, right);
+        if ((left == null) && (right == null)) {
+            return Boolean.TRUE;
+        } else if ((left == null) || (right == null)) {
+            return Boolean.FALSE;
+        }
+        left = String.valueOf(left);
+        right = String.valueOf(right);
+        // PERF: First check the pattern cache for the pattern.
+        // Note that the original string is the key, to avoid having to translate it first.
+        Pattern pattern = (Pattern)regexpPatternCache.get(right);
+        if (pattern == null) {
+            pattern = Pattern.compile((String)right);
+            // Ensure cache does not grow beyond 100.
+            if (regexpPatternCache.size() > 100) {
+                regexpPatternCache.remove(regexpPatternCache.keySet().iterator().next());
+            }
+            regexpPatternCache.put(right, pattern);
+        }
+        return pattern.matcher((String)left).matches();
     }
 
     /**
@@ -91,7 +106,7 @@ public static Boolean conformRegexp(Object left, Object right) {
      * Indicates whether the passed object implements java.sql.SQLXML introduced in jdk 1.6
      */
     public static boolean isSQLXML(Object object) {
-        return getPlatform().isSQLXML(object);
+        return (object instanceof SQLXML);
     }
 
     /**
@@ -99,6 +114,9 @@ public static boolean isSQLXML(Object object) {
      * Casts the passed object to SQLXML and calls getString and free methods
      */
     public static String getStringAndFreeSQLXML(Object sqlXml) throws SQLException {
-        return getPlatform().getStringAndFreeSQLXML(sqlXml);
+        String str = ((SQLXML)sqlXml).getString();
+        ((SQLXML)sqlXml).free();
+        return str;
     }
+
 }
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaSEPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaSEPlatform.java
index 0eb5ab5..0f69ca6 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaSEPlatform.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaSEPlatform.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 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 v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -37,10 +37,67 @@ public enum JavaSEPlatform implements Comparable<JavaSEPlatform> {
     v1_7(1,7),
     /** Java SE 1.8. */
     v1_8(1,8),
-    /** Java SE 9. */
-    v1_9(1,9),
-    /** Java SE 9. */
-    v9_0(9, 0);
+    /** Java SE 9. Version alias 1.9 is added too.*/
+    v9_0(9,0, new Version(1,9)),
+    /** Java SE 10. */
+    v10_0(10,0),
+    /** Java SE 18.3. */
+    v18_3(18,3),
+    /** Java SE 18.9. */
+    v18_9(18,9);
+
+    public static final class Version {
+        /**
+         * Creates an instance of Java SE version numbers.
+         * @param major major version number
+         * @param minor minor version number
+         */
+        private Version(final int major, final int minor) {
+            this.major = major;
+            this.minor = minor;
+        }
+
+        /** Major version number. */
+        private final int major;
+
+        /** Minor version number. */
+        private final int 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;
+        }
+
+        /**
+         * Return computer readable {@code String} containing version numbers in {@code <major> '.' <minor>} format.
+         * @return computer readable {@code String} containing version numbers
+         */
+        public String versionString() {
+            return JavaSEPlatform.versionString(major, minor);
+        }
+
+        // Currently this is identical with versionString() method.
+        /**
+         * Return version as human readable {@code String}.
+         * @return version as human readable {@code String}.
+         */
+        @Override
+        public String toString() {
+            return JavaSEPlatform.versionString(major, minor);
+        }
+
+    }
 
     /**
      * Stored <code>String</code> values for backward <code>String</code>
@@ -52,7 +109,15 @@ public enum JavaSEPlatform implements Comparable<JavaSEPlatform> {
     // Initialize backward String conversion Map.
     static {
         for (JavaSEPlatform platform : JavaSEPlatform.values()) {
+            // Primary version numbers mapping.
             stringValuesMap.put(platform.versionString(), platform);
+            // Additional version numbers mapping.
+            Version[] additional = platform.getAdditionalVersions();
+            if (additional != null) {
+                for (Version version : additional) {
+                    stringValuesMap.put(version.versionString(), platform);
+                }
+            }
         }
     }
 
@@ -63,8 +128,11 @@ public enum JavaSEPlatform implements Comparable<JavaSEPlatform> {
     public static final JavaSEPlatform CURRENT
             = JavaVersion.vmVersion().toPlatform();
 
-    /** Lowest supported Java SE platform. Currently it's Java SE 1.7. */
-    public static final JavaSEPlatform MIN_SUPPORTED = v1_7;
+    /** Lowest supported Java SE platform. Currently it's Java SE 1.8. */
+    public static final JavaSEPlatform MIN_SUPPORTED = v1_8;
+
+    /** Latest Java SE platform. This value is used when Java SE platform detection fails. */
+    static final JavaSEPlatform LATEST = JavaSEPlatform.v18_9;
 
     /**
      * Check whether current Java SE is exactly matching provided platform.
@@ -75,6 +143,14 @@ public static boolean is(JavaSEPlatform platform) {
     }
 
     /**
+     * Check whether current Java SE is at least (greater or equal) provided platform.
+     * @param platform Java SE platform to compare with.
+     */
+    public static boolean atLeast(JavaSEPlatform platform) {
+        return CURRENT.atLeast(platform);
+    }
+
+    /**
      * Returns a <code>JavaSEPlatform</code> with a value represented by the
      * specified <code>String</code>. The <code>JavaSEPlatform</code> returned
      * represents existing value only if specified <code>String</code>
@@ -96,14 +172,16 @@ public static JavaSEPlatform toValue(final String platformName) {
     }
 
     // There are not too many versions yet so direct mapping in code is simple.
+    // Version 1.9 is considered as valid version for 9.0.
     /**
      * Returns a <code>JavaSEPlatform</code> matching provided
      * <code>major</code> and <code>minor</code> version numbers.
      * @param major Major version number.
      * @param minor Minor version number.
      * @return <code>JavaSEPlatform</code> value matching provided
-     *         <code>major</code> and <code>minor</code> version numbers
-     *         or <code>null</code> when such a value does not exist.
+     *         <code>major</code> and <code>minor</code> version numbers.
+     *         {@code JavaSEPlatform.DEFAULT} value is returned for unknown
+     *         Java SE version numbers.
      */
     public static JavaSEPlatform toValue(final int major, final int minor) {
         switch (major) {
@@ -117,12 +195,20 @@ public static JavaSEPlatform toValue(final int major, final int minor) {
                 case 6: return v1_6;
                 case 7: return v1_7;
                 case 8: return v1_8;
-                case 9: return v1_9;
-                default: return null;
+                case 9: return v9_0;
+                default: return LATEST;
             }
         case 9:
             return v9_0;
-        default: return null;
+        case 10:
+            return v10_0;
+        case 18:
+            switch (minor) {
+                case 3: return v18_3;
+                case 9: return v18_9;
+                default: return LATEST;
+            }
+        default: return LATEST;
         }
     }
 
@@ -143,26 +229,27 @@ public static final String versionString(final int major, final int minor) {
 
     /**
      * Constructs an instance of Java SE platform.
-     * @param major Major version number.
-     * @param minor Minor version number.
+     * @param major major version number
+     * @param minor minor version number
+     * @param addVersions additional version  numbers if defined
      */
-    JavaSEPlatform(final int major, final int minor) {
-        this.major = major;
-        this.minor = minor;
+    JavaSEPlatform(final int major, final int minor, Version ...addVersions) {
+        this.version = new Version(major, minor);
+        this.addVersions = addVersions;
     }
 
-    /** Major version number. */
-    private final int major;
+    /** Java SE version numbers. */
+    private final Version version;
 
-    /** Minor version number. */
-    private final int minor;
+    /** Additional version numbers. */
+    private final Version[] addVersions;
 
     /**
      * Get major version number.
      * @return Major version number.
      */
     public final int getMajor() {
-        return major;
+        return version.major;
     }
 
     /**
@@ -170,7 +257,16 @@ public final int getMajor() {
      * @return Minor version number.
      */
     public final int getMinor() {
-        return minor;
+        return version.minor;
+    }
+
+    /**
+     * Get additional version numbers.
+     * @return an array of additional version numbers if exist or {@code null} if no additional
+     *         version numbers are defined.
+     */
+    public final Version[] getAdditionalVersions() {
+        return addVersions;
     }
 
     /**
@@ -179,7 +275,7 @@ public final int getMinor() {
      * @return Value of <code>true</code> if this platform is equal
      *         or greater to specified platform or <code>false</code> otherwise.
      */
-    public boolean atLeast(final JavaSEPlatform platform) {
+    public boolean gte(final JavaSEPlatform platform) {
         return compareTo(platform) >= 0;
     }
 
@@ -193,23 +289,21 @@ public boolean isSupported() {
     }
 
     /**
-     * Generate {@link String} containing minor and major version numbers
-     * in {@code <major> '.' <minor>} format.
-     * @return Generated {@link String}
+     * Return computer readable {@code String} containing version numbers in {@code <major> '.' <minor>} format.
+     * @return computer readable {@code String} containing version numbers
      */
     public String versionString() {
-        return versionString(major, minor);
+        return versionString(version.major, version.minor);
     }
 
     // Currently this is identical with versionString() method.
     /**
-     * Convert Java SE platform version value to human readable
-     * <code>String</code>.
-     * @return A <code>String</code> representation of the value of this object.
+     * Return Java SE platform version as human readable {@code String}.
+     * @return Java SE platform version as human readable {@code String}.
      */
     @Override
     public String toString() {
-        return versionString(major, minor);
+        return versionString(version.major, version.minor);
     }
 
 }
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaVersion.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaVersion.java
index 23ac0cf..c555d67 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaVersion.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/JavaVersion.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 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 v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -12,10 +12,13 @@
  ******************************************************************************/
 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;
+import org.eclipse.persistence.logging.AbstractSessionLog;
+import org.eclipse.persistence.logging.SessionLog;
 
 /**
  * Java version storage class. Used for version numbers retrieved from
@@ -35,13 +38,12 @@ public final class JavaVersion {
     public static final String VM_VERSION_PROPERTY = "java.specification.version";
 
     /**
-     * Java specification version output regular expression pattern.
-     * Regular expression contains tokens to read individual version number
-     * components. Expected input is string like
-     * <code>java version "1.6"</code> or <code>9</code>.
+     * Compiled regular expression pattern to read individual version number components.
+     * Expected input is string like <code>java version "1.6"</code> or <code>9</code>.
      */
-    private static final String VM_VERSION_PATTERN =
-            "[^0-9]*([0-9]+)(\\.([0-9]+))*";
+    private static final Pattern VM_VERSION_PATTERN = Pattern.compile(
+            "[^0-9]*([0-9]+)(\\.([0-9]+))*"
+    );
 
     /** Number of <code>Matcher</code> groups (REGEX tokens) expected in Java VM
      *  version output. */
@@ -55,10 +57,72 @@ 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";
+
     /**
-     * Java specification version detector.
-     * Retrieves Java specification version from JDK system property. Version string should
-     * look like:<ul>
+     * 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);
+        // JDK <9, can't use java.lang.Runtime.Version. Just log with FINEST level and return null.
+        } catch (NoSuchMethodException e) {
+            AbstractSessionLog.getLog().log(SessionLog.FINEST, "javase_version_ex_method_not_found", new String[] {RUNTIME_VERSION_METHOD_NAME, Runtime.class.getName()});
+        // Shall never be thrown. Shall be logged as warning.
+        } catch (ReflectiveOperationException e) {
+            AbstractSessionLog.getLog().log(SessionLog.WARNING, "javase_version_ex_method_call", new String[] {RUNTIME_VERSION_METHOD_NAME, e.getClass().getName()});
+        }
+        return null;
+    }
+
+    /**
+     * 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);
+        // Shall never be thrown. Shall be logged as warning.
+        } catch (ReflectiveOperationException e) {
+            AbstractSessionLog.getLog().log(SessionLog.WARNING, "javase_version_ex_method_call", new String[] {RUNTIME_VERSION_METHOD_NAME, e.getClass().getName()});
+        }
+        return null;
+    }
+
+    /**
+     * 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:<ul>
      * <li/><code>"MA.MI"</code>
      * </ul>
      * Where<ul>
@@ -66,11 +130,10 @@ public static String vmVersionString() {
      * <li/>MI is minor version number
      * </ul>
      * Label <code>java version</code> is parsed as non case sensitive.
+     * @return Current JDK version for any JDK from system property.
      */
-    public static JavaVersion vmVersion() {
-        final String version = vmVersionString();
-        final Pattern pattern = Pattern.compile(VM_VERSION_PATTERN);
-        final Matcher matcher = pattern.matcher(version);
+    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));
@@ -80,6 +143,22 @@ public static JavaVersion vmVersion() {
         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;
 
@@ -147,7 +226,8 @@ public final String toString() {
 
     /**
      * Return {@link JavaSEPlatform} matching this Java SE specification version.
-     * @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);
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java
index d85edf8..32f8828 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle, IBM Corporation and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 Oracle, IBM Corporation and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -827,7 +827,9 @@ public class LoggingLocalizationResource extends ListResourceBundle {
         { "jaxp_sec_disabled", "Xml Security disabled, no JAXP {0} external access configuration necessary." },
         { "jaxp_sec_explicit", "Detected explicitly JAXP configuration, no JAXP {0} external access configuration necessary." },
         { "jaxp_sec_prop_supported", "Property {0} is supported and has been successfully set by used JAXP implementation." },
-        { "jaxp_sec_prop_not_supported", "Property {0} is not supported by used JAXP implementation." }
+        { "jaxp_sec_prop_not_supported", "Property {0} is not supported by used JAXP implementation." },
+        { "javase_version_ex_method_not_found", "Method {0} was not found in {1}" },
+        { "javase_version_ex_method_call", "Exception when calling method {0}: {1}" }
     };
 
     /**