[ASTERIXDB-2397][*DB] Enable execution on Java 9/10

(cherry picked from commit 5c28118b5341306f4774d32937770f107f3a015b)

Change-Id: I221dfba1b2d15e33b312feb3fb50e70d536027fd
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2700
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/ApplicationConfigurator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/ApplicationConfigurator.java
index adb3c18..c76d9b8 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/ApplicationConfigurator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/ApplicationConfigurator.java
@@ -24,14 +24,21 @@
 import java.util.Properties;
 
 import org.apache.asterix.common.config.AsterixProperties;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.exceptions.RuntimeDataException;
 import org.apache.hyracks.api.config.IConfigManager;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.control.common.controllers.CCConfig;
 import org.apache.hyracks.control.common.controllers.ControllerConfig;
 import org.apache.hyracks.control.common.controllers.NCConfig;
 import org.apache.hyracks.control.common.utils.ConfigurationUtil;
 import org.apache.hyracks.util.file.FileUtil;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 class ApplicationConfigurator {
+    private static final Logger LOGGER = LogManager.getLogger();
+
     private ApplicationConfigurator() {
     }
 
@@ -56,4 +63,24 @@
         }
 
     }
+
+    public static void validateJavaRuntime() throws HyracksDataException {
+        final String javaVersion = System.getProperty("java.version");
+        LOGGER.info("Found JRE version " + javaVersion);
+        String[] splits = javaVersion.split("\\.");
+        if ("1".equals(splits[0])) {
+            switch (splits[1]) {
+                case "9":
+                    LOGGER.warn("JRE version \"" + javaVersion + "\" is untested");
+                    //fall-through
+                case "8":
+                    return;
+                default:
+                    throw RuntimeDataException.create(ErrorCode.UNSUPPORTED_JRE,
+                            "a minimum version of JRE of 1.8 is required, but is currently: \"" + javaVersion + "\"");
+            }
+        } else {
+            LOGGER.warn("JRE version \"" + javaVersion + "\" is untested");
+        }
+    }
 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
index 7224526..2ed30e1 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
@@ -88,6 +88,7 @@
 import org.apache.hyracks.api.client.HyracksConnection;
 import org.apache.hyracks.api.client.IHyracksClientConnection;
 import org.apache.hyracks.api.config.IConfigManager;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.job.resource.IJobCapacityController;
 import org.apache.hyracks.api.lifecycle.LifeCycleComponentManager;
 import org.apache.hyracks.control.cc.BaseCCApplication;
@@ -119,6 +120,7 @@
         ccServiceCtx = (ICCServiceContext) serviceCtx;
         ccServiceCtx.setThreadFactory(
                 new AsterixThreadFactory(ccServiceCtx.getThreadFactory(), new LifeCycleComponentManager()));
+        validateEnvironment();
     }
 
     @Override
@@ -372,4 +374,13 @@
     public IHyracksClientConnection getHcc() {
         return hcc;
     }
+
+    protected void validateEnvironment() throws HyracksDataException {
+        validateJavaVersion();
+    }
+
+    protected void validateJavaVersion() throws HyracksDataException {
+        ApplicationConfigurator.validateJavaRuntime();
+    }
+
 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
index 494198b..453d9b8 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
@@ -93,6 +93,7 @@
         ((NodeControllerService) serviceCtx.getControllerService()).setNodeStatus(NodeStatus.IDLE);
         ncServiceCtx.setThreadFactory(
                 new AsterixThreadFactory(ncServiceCtx.getThreadFactory(), ncServiceCtx.getLifeCycleComponentManager()));
+        validateEnvironment();
     }
 
     @Override
@@ -269,4 +270,13 @@
         }
         return state;
     }
+
+    protected void validateEnvironment() throws HyracksDataException {
+        validateJavaRuntime();
+    }
+
+    protected void validateJavaRuntime() throws HyracksDataException {
+        ApplicationConfigurator.validateJavaRuntime();
+    }
+
 }
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index bd84832..75c5402 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -76,7 +76,7 @@
     public static final int REJECT_NODE_UNREGISTERED = 33;
     public static final int DIVISION_BY_ZERO = 34;
 
-    public static final int INSTANTIATION_ERROR = 100;
+    public static final int UNSUPPORTED_JRE = 100;
 
     public static final int EXTERNAL_UDF_RESULT_TYPE_ERROR = 200;
 
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index a0cebea..f116ebf 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -69,7 +69,7 @@
 33 = Node is not registered with the CC
 34 = Division by Zero.
 
-100 = Unable to instantiate class %1$s
+100 = Unsupported JRE: %1$s
 
 200 = External UDF cannot produce expected result. Please check the UDF configuration
 
diff --git a/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/pom.xml b/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/pom.xml
index 16b09cb..5b680b2 100644
--- a/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/pom.xml
+++ b/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/pom.xml
@@ -78,8 +78,13 @@
     </dependency>
     <dependency>
       <groupId>org.ow2.asm</groupId>
-      <artifactId>asm-all</artifactId>
-      <version>5.1</version>
+      <artifactId>asm</artifactId>
+      <version>6.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm-tree</artifactId>
+      <version>6.2</version>
     </dependency>
   </dependencies>
 </project>
diff --git a/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/src/main/java/org/apache/asterix/runtime/evaluators/staticcodegen/EvaluatorMissingCheckVisitor.java b/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/src/main/java/org/apache/asterix/runtime/evaluators/staticcodegen/EvaluatorMissingCheckVisitor.java
index 9339e8b..38b9751 100644
--- a/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/src/main/java/org/apache/asterix/runtime/evaluators/staticcodegen/EvaluatorMissingCheckVisitor.java
+++ b/asterixdb/asterix-maven-plugins/asterix-evaluator-generator-maven-plugin/src/main/java/org/apache/asterix/runtime/evaluators/staticcodegen/EvaluatorMissingCheckVisitor.java
@@ -109,7 +109,7 @@
             // Duplicate the top operand.
             mv.visitInsn(Opcodes.DUP);
             // Invoke the constructor of TypeChecker.
-            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, TYPE_CHECKER_CLASS, CONSTRUCTOR, "()V", true);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, TYPE_CHECKER_CLASS, CONSTRUCTOR, "()V", false);
             // Putfield for the field typeChecker.
             mv.visitFieldInsn(Opcodes.PUTFIELD, className, TYPE_CHECKER_NAME, TYPE_CHECKER_DESC);
             // RETURN.
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetNodeDetailsJSONWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetNodeDetailsJSONWork.java
index 517f56f..aa7dca1 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetNodeDetailsJSONWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GetNodeDetailsJSONWork.java
@@ -19,7 +19,8 @@
 
 package org.apache.hyracks.control.cc.work;
 
-import java.io.File;
+import static org.apache.hyracks.control.common.utils.ConfigurationUtil.toPathElements;
+
 import java.lang.management.GarbageCollectorMXBean;
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
@@ -31,19 +32,22 @@
 import java.util.Date;
 import java.util.List;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.hyracks.api.config.Section;
 import org.apache.hyracks.control.cc.NodeControllerState;
 import org.apache.hyracks.control.cc.cluster.INodeManager;
 import org.apache.hyracks.control.common.config.ConfigUtils;
 import org.apache.hyracks.control.common.controllers.CCConfig;
 import org.apache.hyracks.control.common.controllers.NCConfig;
-import org.apache.hyracks.util.PidHelper;
 import org.apache.hyracks.control.common.work.IPCResponder;
 import org.apache.hyracks.control.common.work.SynchronizableWork;
+import org.apache.hyracks.util.MXHelper;
+import org.apache.hyracks.util.PidHelper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public class GetNodeDetailsJSONWork extends SynchronizableWork {
+
     private static final Section[] CC_SECTIONS = { Section.CC, Section.COMMON };
     private static final Section[] NC_SECTIONS = { Section.NC, Section.COMMON };
 
@@ -114,9 +118,9 @@
             o.put("vm_name", runtimeMXBean.getVmName());
             o.put("vm_version", runtimeMXBean.getVmVersion());
             o.put("vm_vendor", runtimeMXBean.getVmVendor());
-            o.putPOJO("classpath", runtimeMXBean.getClassPath().split(File.pathSeparator));
-            o.putPOJO("library_path", runtimeMXBean.getLibraryPath().split(File.pathSeparator));
-            o.putPOJO("boot_classpath", runtimeMXBean.getBootClassPath().split(File.pathSeparator));
+            o.putPOJO("classpath", toPathElements(runtimeMXBean.getClassPath()));
+            o.putPOJO("library_path", toPathElements(runtimeMXBean.getLibraryPath()));
+            o.putPOJO("boot_classpath", toPathElements(MXHelper.getBootClassPath()));
             o.putPOJO("input_arguments", runtimeMXBean.getInputArguments());
             o.putPOJO("system_properties", runtimeMXBean.getSystemProperties());
             o.put("pid", PidHelper.getPid());
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/NodeControllerData.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/NodeControllerData.java
index 8dfc729..ddab504 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/NodeControllerData.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/NodeControllerData.java
@@ -18,16 +18,15 @@
  */
 package org.apache.hyracks.control.common;
 
+import static org.apache.hyracks.control.common.utils.ConfigurationUtil.toPathElements;
 import static org.apache.hyracks.util.JSONUtil.put;
 
-import java.io.File;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.hyracks.api.comm.NetworkAddress;
 import org.apache.hyracks.api.job.JobId;
 import org.apache.hyracks.api.job.resource.NodeCapacity;
@@ -301,9 +300,9 @@
             put(o, "vm-name", vmName);
             put(o, "vm-version", vmVersion);
             put(o, "vm-vendor", vmVendor);
-            put(o, "classpath", StringUtils.split(classpath, File.pathSeparatorChar));
-            put(o, "library-path", StringUtils.split(libraryPath, File.pathSeparatorChar));
-            put(o, "boot-classpath", StringUtils.split(bootClasspath, File.pathSeparatorChar));
+            put(o, "classpath", toPathElements(classpath));
+            put(o, "library-path", toPathElements(libraryPath));
+            put(o, "boot-classpath", toPathElements(bootClasspath));
             put(o, "input-arguments", inputArguments);
             put(o, "input-arguments", inputArguments);
             put(o, "system-properties", systemProperties);
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java
index 8dd95e1..b49dc20 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java
@@ -103,7 +103,6 @@
 
     public ConfigManager(String[] args) {
         this.args = args;
-        checkJavaVersion();
         for (Section section : Section.values()) {
             allSections.add(section.sectionName());
         }
@@ -113,14 +112,6 @@
         addConfigurator(ConfiguratorMetric.APPLY_DEFAULTS, this::applyDefaults);
     }
 
-    static void checkJavaVersion() {
-        final String javaVersion = System.getProperty("java.version");
-        LOGGER.info("Found JRE version " + javaVersion);
-        if (!javaVersion.startsWith("1.8")) {
-            throw new IllegalStateException("JRE version 1.8 is required");
-        }
-    }
-
     @Override
     public void addConfigurator(int metric, IConfigurator configurator) {
         configurators.computeIfAbsent(metric, metric1 -> new ArrayList<>()).add(configurator);
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NodeRegistration.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NodeRegistration.java
index 76f5ad8..c2f2e1a 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NodeRegistration.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NodeRegistration.java
@@ -18,6 +18,9 @@
  */
 package org.apache.hyracks.control.common.controllers;
 
+import static org.apache.hyracks.util.MXHelper.osMXBean;
+import static org.apache.hyracks.util.MXHelper.runtimeMXBean;
+
 import java.io.Serializable;
 import java.net.InetSocketAddress;
 import java.util.List;
@@ -26,6 +29,8 @@
 import org.apache.hyracks.api.comm.NetworkAddress;
 import org.apache.hyracks.api.job.resource.NodeCapacity;
 import org.apache.hyracks.control.common.heartbeat.HeartbeatSchema;
+import org.apache.hyracks.util.MXHelper;
+import org.apache.hyracks.util.PidHelper;
 
 public final class NodeRegistration implements Serializable {
     private static final long serialVersionUID = 1L;
@@ -73,31 +78,28 @@
     private final NodeCapacity capacity;
 
     public NodeRegistration(InetSocketAddress ncAddress, String nodeId, NCConfig ncConfig, NetworkAddress dataPort,
-            NetworkAddress datasetPort, String osName, String arch, String osVersion, int nProcessors, String vmName,
-            String vmVersion, String vmVendor, String classpath, String libraryPath, String bootClasspath,
-            List<String> inputArguments, Map<String, String> systemProperties, HeartbeatSchema hbSchema,
-            NetworkAddress messagingPort, NodeCapacity capacity, int pid) {
+            NetworkAddress datasetPort, HeartbeatSchema hbSchema, NetworkAddress messagingPort, NodeCapacity capacity) {
         this.ncAddress = ncAddress;
         this.nodeId = nodeId;
         this.ncConfig = ncConfig;
         this.dataPort = dataPort;
         this.datasetPort = datasetPort;
-        this.osName = osName;
-        this.arch = arch;
-        this.osVersion = osVersion;
-        this.nProcessors = nProcessors;
-        this.vmName = vmName;
-        this.vmVersion = vmVersion;
-        this.vmVendor = vmVendor;
-        this.classpath = classpath;
-        this.libraryPath = libraryPath;
-        this.bootClasspath = bootClasspath;
-        this.inputArguments = inputArguments;
-        this.systemProperties = systemProperties;
         this.hbSchema = hbSchema;
         this.messagingPort = messagingPort;
         this.capacity = capacity;
-        this.pid = pid;
+        this.osName = osMXBean.getName();
+        this.arch = osMXBean.getArch();
+        this.osVersion = osMXBean.getVersion();
+        this.nProcessors = osMXBean.getAvailableProcessors();
+        this.vmName = runtimeMXBean.getVmName();
+        this.vmVersion = runtimeMXBean.getVmVersion();
+        this.vmVendor = runtimeMXBean.getVmVendor();
+        this.classpath = runtimeMXBean.getClassPath();
+        this.libraryPath = runtimeMXBean.getLibraryPath();
+        this.bootClasspath = MXHelper.getBootClassPath();
+        this.inputArguments = runtimeMXBean.getInputArguments();
+        this.systemProperties = runtimeMXBean.getSystemProperties();
+        this.pid = PidHelper.getPid();
     }
 
     public InetSocketAddress getNodeControllerAddress() {
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ConfigurationUtil.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ConfigurationUtil.java
index d7cef4e..45d4787 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ConfigurationUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/utils/ConfigurationUtil.java
@@ -18,10 +18,18 @@
  */
 package org.apache.hyracks.control.common.utils;
 
+import java.io.File;
+
+import org.apache.commons.lang3.StringUtils;
+
 public class ConfigurationUtil {
     public static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
+    private static final String[] EMPTY_STRING_ARR = new String[0];
 
     private ConfigurationUtil() {
     }
 
+    public static String[] toPathElements(String path) {
+        return path == null ? EMPTY_STRING_ARR : StringUtils.split(path, File.pathSeparatorChar);
+    }
 }
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
index 6a7d645..47ed342 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
@@ -20,8 +20,6 @@
 
 import static org.apache.hyracks.util.MXHelper.gcMXBeans;
 import static org.apache.hyracks.util.MXHelper.memoryMXBean;
-import static org.apache.hyracks.util.MXHelper.osMXBean;
-import static org.apache.hyracks.util.MXHelper.runtimeMXBean;
 
 import java.io.File;
 import java.io.IOException;
@@ -94,7 +92,6 @@
 import org.apache.hyracks.net.protocols.muxdemux.FullFrameChannelInterfaceFactory;
 import org.apache.hyracks.util.ExitUtil;
 import org.apache.hyracks.util.MaintainedThreadNameExecutorService;
-import org.apache.hyracks.util.PidHelper;
 import org.apache.hyracks.util.trace.ITracer;
 import org.apache.hyracks.util.trace.TraceUtils;
 import org.apache.hyracks.util.trace.Tracer;
@@ -330,12 +327,8 @@
         NetworkAddress netAddress = netManager.getPublicNetworkAddress();
         NetworkAddress messagingAddress =
                 messagingNetManager != null ? messagingNetManager.getPublicNetworkAddress() : null;
-        nodeRegistration = new NodeRegistration(ncAddress, id, ncConfig, netAddress, datasetAddress, osMXBean.getName(),
-                osMXBean.getArch(), osMXBean.getVersion(), osMXBean.getAvailableProcessors(), runtimeMXBean.getVmName(),
-                runtimeMXBean.getVmVersion(), runtimeMXBean.getVmVendor(), runtimeMXBean.getClassPath(),
-                runtimeMXBean.getLibraryPath(), runtimeMXBean.getBootClassPath(), runtimeMXBean.getInputArguments(),
-                runtimeMXBean.getSystemProperties(), hbSchema, messagingAddress, application.getCapacity(),
-                PidHelper.getPid());
+        nodeRegistration = new NodeRegistration(ncAddress, id, ncConfig, netAddress, datasetAddress, hbSchema,
+                messagingAddress, application.getCapacity());
 
         ncData = new NodeControllerData(nodeRegistration);
     }
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
index 4c6ff57..247c001 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
@@ -106,4 +106,13 @@
         }
     }
 
+    public static String getBootClassPath() {
+        try {
+            return runtimeMXBean.getBootClassPath();
+        } catch (UnsupportedOperationException e) {
+            // boot classpath is not supported in Java 9 and later
+            LOGGER.debug("ignoring exception calling RuntimeMXBean.getBootClassPath; returning null", e);
+            return null;
+        }
+    }
 }