8198253: ThreadInfo.from(CompositeData) incorrectly accepts CompositeData with missing JDK 6 attributes
authormchung
Wed, 28 Feb 2018 17:11:57 -0800
changeset 49077 b1c42b3cd19b
parent 49076 1d879babed52
child 49078 039e63e471e1
child 49106 d3185e98c411
child 56216 d8ea550b907a
8198253: ThreadInfo.from(CompositeData) incorrectly accepts CompositeData with missing JDK 6 attributes Reviewed-by: dfuchs, jmanson
src/java.management/share/classes/java/lang/management/MonitorInfo.java
src/java.management/share/classes/java/lang/management/ThreadInfo.java
src/java.management/share/classes/sun/management/LockInfoCompositeData.java
src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java
src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java
src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java
src/java.management/share/classes/sun/management/TypeVersionMapper.java
test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java
test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java
--- a/src/java.management/share/classes/java/lang/management/MonitorInfo.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/java/lang/management/MonitorInfo.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -116,11 +116,10 @@
      * <tbody style="text-align:left">
      * <tr>
      *   <th scope="row">lockedStackFrame</th>
-     *   <td><code>CompositeData as specified in the
-     *       <a href="ThreadInfo.html#StackTrace">stackTrace</a>
-     *       attribute defined in the {@link ThreadInfo#from
-     *       ThreadInfo.from} method.
-     *       </code></td>
+     *   <td><a href="ThreadInfo.html#stackTraceElement">
+     *       {@code CompositeData} for {@code StackTraceElement}</a> as specified
+     *       in {@link ThreadInfo#from(CompositeData)} method.
+     *   </td>
      * </tr>
      * <tr>
      *   <th scope="row">lockedStackDepth</th>
@@ -134,7 +133,7 @@
      * @throws IllegalArgumentException if {@code cd} does not
      *   represent a {@code MonitorInfo} with the attributes described
      *   above.
-
+     *
      * @return a {@code MonitorInfo} object represented
      *         by {@code cd} if {@code cd} is not {@code null};
      *         {@code null} otherwise.
--- a/src/java.management/share/classes/java/lang/management/ThreadInfo.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/java/lang/management/ThreadInfo.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 
 package java.lang.management;
 
+import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeData;
 import sun.management.ManagementFactoryHelper;
 import sun.management.ThreadInfoCompositeData;
@@ -110,7 +111,6 @@
     private StackTraceElement[] stackTrace;
     private MonitorInfo[]       lockedMonitors;
     private LockInfo[]          lockedSynchronizers;
-
     private static MonitorInfo[] EMPTY_MONITORS = new MonitorInfo[0];
     private static LockInfo[] EMPTY_SYNCS = new LockInfo[0];
 
@@ -264,6 +264,11 @@
     /*
      * Constructs a {@code ThreadInfo} object from a
      * {@link CompositeData CompositeData}.
+     *
+     * @throws IllegalArgumentException if the given CompositeData does not
+     * contain all of the attributes defined for ThreadInfo of version <= N.
+     *
+     * @see ThreadInfo#from
      */
     private ThreadInfo(CompositeData cd) {
         ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd);
@@ -281,41 +286,11 @@
         suspended = ticd.suspended();
         inNative = ticd.inNative();
         stackTrace = ticd.stackTrace();
-
-        // 6.0 attributes
-        if (ticd.hasV6()) {
-            lock = ticd.lockInfo();
-            lockedMonitors = ticd.lockedMonitors();
-            lockedSynchronizers = ticd.lockedSynchronizers();
-        } else {
-            // lockInfo is a new attribute added in 1.6 ThreadInfo
-            // If cd is a 5.0 version, construct the LockInfo object
-            //  from the lockName value.
-            if (lockName != null) {
-                String result[] = lockName.split("@");
-                if (result.length == 2) {
-                    int identityHashCode = Integer.parseInt(result[1], 16);
-                    lock = new LockInfo(result[0], identityHashCode);
-                } else {
-                    assert result.length == 2;
-                    lock = null;
-                }
-            } else {
-                lock = null;
-            }
-            lockedMonitors = EMPTY_MONITORS;
-            lockedSynchronizers = EMPTY_SYNCS;
-        }
-
-        // 9.0 attributes
-        if (ticd.isCurrentVersion()) {
-            daemon = ticd.isDaemon();
-            priority = ticd.getPriority();
-        } else {
-            // Not ideal, but unclear what else we can do.
-            daemon = false;
-            priority = Thread.NORM_PRIORITY;
-        }
+        lock = ticd.lockInfo();
+        lockedMonitors = ticd.lockedMonitors();
+        lockedSynchronizers = ticd.lockedSynchronizers();
+        daemon = ticd.isDaemon();
+        priority = ticd.getPriority();
     }
 
     /**
@@ -692,52 +667,105 @@
     /**
      * Returns a {@code ThreadInfo} object represented by the
      * given {@code CompositeData}.
-     * The given {@code CompositeData} must contain the following attributes
-     * unless otherwise specified below:
+     *
+     * <a id="attributes"></a>
+     * A {@code CompositeData} representing a {@code ThreadInfo} of
+     * version <em>N</em> must contain all of the attributes defined
+     * in version &le; <em>N</em> unless specified otherwise.
+     * The same rule applies the composite type of the given
+     * {@code CompositeData} and transitively to attributes whose
+     * {@linkplain CompositeData#getCompositeType() type} or
+     * {@linkplain ArrayType#getElementOpenType() component type} is
+     * {@code CompositeType}.
+     * <p>
+     * A {@code CompositeData} representing {@code ThreadInfo} of
+     * version <em>N</em> contains {@code "stackTrace"} attribute and
+     * {@code "lockedMonitors"} attribute representing
+     * an array of {@code StackTraceElement} and
+     * an array of {@link MonitorInfo} respectively
+     * and their types are of version <em>N</em>.
+     * The {@code "lockedStackFrame"} attribute in
+     * {@link MonitorInfo#from(CompositeData) MonitorInfo}'s composite type
+     * must represent {@code StackTraceElement} of the same version <em>N</em>.
+     * Otherwise, this method will throw {@code IllegalArgumentException}.
+     *
      * <table class="striped" style="margin-left:2em">
-     * <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
+     * <caption style="display:none">The attributes and their types for ThreadInfo's composite data</caption>
      * <thead>
      * <tr>
      *   <th scope="col">Attribute Name</th>
      *   <th scope="col">Type</th>
+     *   <th scope="col">Since</th>
      * </tr>
      * </thead>
      * <tbody style="text-align:left">
      * <tr>
      *   <th scope="row">threadId</th>
      *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">threadName</th>
      *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">threadState</th>
      *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">suspended</th>
      *   <td>{@code java.lang.Boolean}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">inNative</th>
      *   <td>{@code java.lang.Boolean}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">blockedCount</th>
      *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">blockedTime</th>
      *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">waitedCount</th>
      *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">waitedTime</th>
      *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">lockName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">lockOwnerId</th>
+     *   <td>{@code java.lang.Long}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">lockOwnerName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row"><a id="StackTrace">stackTrace</a></th>
+     *   <td>{@code javax.management.openmbean.CompositeData[]}, each element
+     *       is a {@code CompositeData} representing {@code StackTraceElement}
+     *       as specified <a href="#stackTraceElement">below</a>.
+     *   </td>
+     *   <td>5</td>
      * </tr>
      * <tr>
      *   <th scope="row">lockInfo</th>
@@ -745,78 +773,21 @@
      *       - the mapped type for {@link LockInfo} as specified in the
      *         {@link LockInfo#from} method.
      *       <p>
-     *       If {@code cd} does not contain this attribute,
+     *       If the given {@code CompositeData} does not contain this attribute,
      *       the {@code LockInfo} object will be constructed from
-     *       the value of the {@code lockName} attribute. </td>
-     * </tr>
-     * <tr>
-     *   <th scope="row">lockName</th>
-     *   <td>{@code java.lang.String}</td>
-     * </tr>
-     * <tr>
-     *   <th scope="row">lockOwnerId</th>
-     *   <td>{@code java.lang.Long}</td>
-     * </tr>
-     * <tr>
-     *   <th scope="row">lockOwnerName</th>
-     *   <td>{@code java.lang.String}</td>
-     * </tr>
-     * <tr>
-     *   <th scope="row"><a id="StackTrace">stackTrace</a></th>
-     *   <td>{@code javax.management.openmbean.CompositeData[]}
-     *       <p>
-     *       Each element is a {@code CompositeData} representing
-     *       StackTraceElement containing the following attributes:
-     *       <table class="striped" style="margin-left:2em">
-     *       <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
-     *       <thead style="text-align:center">
-     *       <tr>
-     *         <th scope="col">Attribute Name</th>
-     *         <th scope="col">Type</th>
-     *       </tr>
-     *       </thead>
-     *       <tbody style="text-align:left">
-     *       <tr>
-     *         <th scope="row">moduleName</th>
-     *         <td>{@code java.lang.String}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">moduleVersion</th>
-     *         <td>{@code java.lang.String}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">className</th>
-     *         <td>{@code java.lang.String}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">methodName</th>
-     *         <td>{@code java.lang.String}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">fileName</th>
-     *         <td>{@code java.lang.String}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">lineNumber</th>
-     *         <td>{@code java.lang.Integer}</td>
-     *       </tr>
-     *       <tr>
-     *         <th scope="row">nativeMethod</th>
-     *         <td>{@code java.lang.Boolean}</td>
-     *       </tr>
-     *       </tbody>
-     *       </table>
-     *   </td>
+     *       the value of the {@code lockName} attribute.</td>
+     *    <td>6</td>
      * </tr>
      * <tr>
      *   <th scope="row">lockedMonitors</th>
      *   <td>{@code javax.management.openmbean.CompositeData[]}
      *       whose element type is the mapped type for
      *       {@link MonitorInfo} as specified in the
-     *       {@link MonitorInfo#from Monitor.from} method.
+     *       {@link MonitorInfo#from MonitorInfo.from} method.
      *       <p>
-     *       If {@code cd} does not contain this attribute,
-     *       this attribute will be set to an empty array. </td>
+     *       If the given {@code CompositeData} does not contain this attribute,
+     *       this attribute will be set to an empty array.</td>
+     *    <td>6</td>
      * </tr>
      * <tr>
      *   <th scope="row">lockedSynchronizers</th>
@@ -824,25 +795,93 @@
      *       whose element type is the mapped type for
      *       {@link LockInfo} as specified in the {@link LockInfo#from} method.
      *       <p>
-     *       If {@code cd} does not contain this attribute,
-     *       this attribute will be set to an empty array. </td>
+     *       If the given {@code CompositeData} does not contain this attribute,
+     *       this attribute will be set to an empty array.</td>
+     *    <td>6</td>
      * </tr>
      * <tr>
      *   <th scope="row">daemon</th>
-     *   <td>{@code java.lang.Boolean}</td>
+     *   <td>{@code java.lang.Boolean}
+     *       <p>
+     *       If the given {@code CompositeData} does not contain this attribute,
+     *       this attribute will be set to {@code false}.</td>
+     *    <td>9</td>
      * </tr>
      * <tr>
      *   <th scope="row">priority</th>
+     *   <td>{@code java.lang.Integer}
+     *       <p>
+     *       If the given {@code CompositeData} does not contain this attribute,
+     *       This attribute will be set to {@link Thread#NORM_PRIORITY}.</td>
+     *    <td>9</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     *
+     * <a id="stackTraceElement">A {@code CompositeData} representing
+     * {@code StackTraceElement}</a> of version <em>N</em> must contain
+     * all of the attributes defined in version &le; <em>N</em>
+     * unless specified otherwise.
+     *
+     * <table class="striped" style="margin-left:2em">
+     * <caption style="display:none">The attributes and their types for StackTraceElement's composite data</caption>
+     * <thead style="text-align:center">
+     * <tr>
+     *   <th scope="col">Attribute Name</th>
+     *   <th scope="col">Type</th>
+     *   <th scope="col">Since</th>
+     * </tr>
+     * </thead>
+     * <tbody style="text-align:left">
+     * <tr>
+     *   <th scope="row">classLoaderName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>9</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">moduleName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>9</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">moduleVersion</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>9</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">className</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">methodName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">fileName</th>
+     *   <td>{@code java.lang.String}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">lineNumber</th>
      *   <td>{@code java.lang.Integer}</td>
+     *   <td>5</td>
+     * </tr>
+     * <tr>
+     *   <th scope="row">nativeMethod</th>
+     *   <td>{@code java.lang.Boolean}</td>
+     *   <td>5</td>
      * </tr>
      * </tbody>
      * </table>
      *
      * @param cd {@code CompositeData} representing a {@code ThreadInfo}
      *
-     * @throws IllegalArgumentException if {@code cd} does not
-     *   represent a {@code ThreadInfo} with the attributes described
-     *   above.
+     * @throws IllegalArgumentException if the given {@code cd} and
+     *         its composite type does not contain all of
+     *         <a href="#attributes">the attributes</a> defined for a
+     *         {@code ThreadInfo} of a specific runtime version.
      *
      * @return a {@code ThreadInfo} object represented
      *         by {@code cd} if {@code cd} is not {@code null};
--- a/src/java.management/share/classes/sun/management/LockInfoCompositeData.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/sun/management/LockInfoCompositeData.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,15 +58,15 @@
 
     protected CompositeData getCompositeData() {
         // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
-        // lockInfoItemNames!
+        // LOCK_INFO_ATTRIBUTES!
         final Object[] lockInfoItemValues = {
             new String(lock.getClassName()),
             lock.getIdentityHashCode(),
         };
 
         try {
-            return new CompositeDataSupport(lockInfoCompositeType,
-                                            lockInfoItemNames,
+            return new CompositeDataSupport(LOCK_INFO_COMPOSITE_TYPE,
+                                            LOCK_INFO_ATTRIBUTES,
                                             lockInfoItemValues);
         } catch (OpenDataException e) {
             // Should never reach here
@@ -74,10 +74,10 @@
         }
     }
 
-    private static final CompositeType lockInfoCompositeType;
+    private static final CompositeType LOCK_INFO_COMPOSITE_TYPE;
     static {
         try {
-            lockInfoCompositeType = (CompositeType)
+            LOCK_INFO_COMPOSITE_TYPE = (CompositeType)
                 MappedMXBeanType.toOpenType(LockInfo.class);
         } catch (OpenDataException e) {
             // Should never reach here
@@ -85,13 +85,13 @@
         }
     }
 
-    static CompositeType getLockInfoCompositeType() {
-        return lockInfoCompositeType;
+    static CompositeType compositeType() {
+        return LOCK_INFO_COMPOSITE_TYPE;
     }
 
     private static final String CLASS_NAME         = "className";
     private static final String IDENTITY_HASH_CODE = "identityHashCode";
-    private static final String[] lockInfoItemNames = {
+    private static final String[] LOCK_INFO_ATTRIBUTES = {
         CLASS_NAME,
         IDENTITY_HASH_CODE,
     };
@@ -104,7 +104,7 @@
             throw new NullPointerException("Null CompositeData");
         }
 
-        if (!isTypeMatched(lockInfoCompositeType, cd.getCompositeType())) {
+        if (!isTypeMatched(LOCK_INFO_COMPOSITE_TYPE, cd.getCompositeType())) {
             throw new IllegalArgumentException(
                 "Unexpected composite type for LockInfo");
         }
--- a/src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.CompositeDataSupport;
 import javax.management.openmbean.OpenDataException;
-import java.util.Set;
+import javax.management.openmbean.OpenType;
 
 /**
  * A CompositeData for MonitorInfo for the local management support.
@@ -55,14 +55,14 @@
 
     protected CompositeData getCompositeData() {
         // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
-        // monitorInfoItemNames!
+        // MONITOR_INFO_ATTRIBUTES!
 
-        int len = monitorInfoItemNames.length;
+        int len = MONITOR_INFO_ATTRIBUTES.length;
         Object[] values = new Object[len];
         CompositeData li = LockInfoCompositeData.toCompositeData(lock);
 
         for (int i = 0; i < len; i++) {
-            String item = monitorInfoItemNames[i];
+            String item = MONITOR_INFO_ATTRIBUTES[i];
             if (item.equals(LOCKED_STACK_FRAME)) {
                 StackTraceElement ste = lock.getLockedStackFrame();
                 values[i] = (ste != null ? StackTraceElementCompositeData.
@@ -76,8 +76,8 @@
         }
 
         try {
-            return new CompositeDataSupport(monitorInfoCompositeType,
-                                            monitorInfoItemNames,
+            return new CompositeDataSupport(MONITOR_INFO_COMPOSITE_TYPE,
+                                            MONITOR_INFO_ATTRIBUTES,
                                             values);
         } catch (OpenDataException e) {
             // Should never reach here
@@ -85,28 +85,50 @@
         }
     }
 
-    private static final CompositeType monitorInfoCompositeType;
-    private static final String[] monitorInfoItemNames;
+    private static final String CLASS_NAME         = "className";
+    private static final String IDENTITY_HASH_CODE = "identityHashCode";
+    private static final String LOCKED_STACK_FRAME = "lockedStackFrame";
+    private static final String LOCKED_STACK_DEPTH = "lockedStackDepth";
+
+    private static final String[] MONITOR_INFO_ATTRIBUTES = {
+        CLASS_NAME,
+        IDENTITY_HASH_CODE,
+        LOCKED_STACK_FRAME,
+        LOCKED_STACK_DEPTH
+    };
+
+    private static final CompositeType MONITOR_INFO_COMPOSITE_TYPE;
+    private static final CompositeType V6_COMPOSITE_TYPE;
     static {
         try {
-            monitorInfoCompositeType = (CompositeType)
+            MONITOR_INFO_COMPOSITE_TYPE = (CompositeType)
                 MappedMXBeanType.toOpenType(MonitorInfo.class);
-            Set<String> s = monitorInfoCompositeType.keySet();
-            monitorInfoItemNames =  s.toArray(new String[0]);
+
+            OpenType<?>[] types = new OpenType<?>[MONITOR_INFO_ATTRIBUTES.length];
+            for (int i = 0; i < MONITOR_INFO_ATTRIBUTES.length; i++) {
+                String name = MONITOR_INFO_ATTRIBUTES[i];
+                types[i] = name.equals(LOCKED_STACK_FRAME)
+                            ? StackTraceElementCompositeData.v5CompositeType()
+                            : MONITOR_INFO_COMPOSITE_TYPE.getType(name);
+            }
+            V6_COMPOSITE_TYPE = new CompositeType("MonitorInfo",
+                                                  "JDK 6 MonitorInfo",
+                                                  MONITOR_INFO_ATTRIBUTES,
+                                                  MONITOR_INFO_ATTRIBUTES,
+                                                  types);
         } catch (OpenDataException e) {
             // Should never reach here
             throw new AssertionError(e);
         }
     }
 
-    static CompositeType getMonitorInfoCompositeType() {
-        return monitorInfoCompositeType;
+    static CompositeType v6CompositeType() {
+        return V6_COMPOSITE_TYPE;
     }
 
-    private static final String CLASS_NAME         = "className";
-    private static final String IDENTITY_HASH_CODE = "identityHashCode";
-    private static final String LOCKED_STACK_FRAME = "lockedStackFrame";
-    private static final String LOCKED_STACK_DEPTH = "lockedStackDepth";
+    static CompositeType compositeType() {
+        return MONITOR_INFO_COMPOSITE_TYPE;
+    }
 
     public static String getClassName(CompositeData cd) {
         return getString(cd, CLASS_NAME);
@@ -138,7 +160,8 @@
             throw new NullPointerException("Null CompositeData");
         }
 
-        if (!isTypeMatched(monitorInfoCompositeType, cd.getCompositeType())) {
+        if (!isTypeMatched(MONITOR_INFO_COMPOSITE_TYPE, cd.getCompositeType()) &&
+            !isTypeMatched(V6_COMPOSITE_TYPE, cd.getCompositeType())) {
             throw new IllegalArgumentException(
                 "Unexpected composite type for MonitorInfo");
         }
--- a/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,13 @@
 
 package sun.management;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Predicate;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.CompositeDataSupport;
 import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.Arrays;
+import java.util.stream.Stream;
 
 /**
  * A CompositeData for StackTraceElement for the local management support.
@@ -52,12 +52,7 @@
     public static StackTraceElement from(CompositeData cd) {
         validateCompositeData(cd);
 
-        if (stackTraceElementV6CompositeType.equals(cd.getCompositeType())) {
-            return new StackTraceElement(getString(cd, CLASS_NAME),
-                                         getString(cd, METHOD_NAME),
-                                         getString(cd, FILE_NAME),
-                                         getInt(cd, LINE_NUMBER));
-        } else {
+        if (STACK_TRACE_ELEMENT_COMPOSITE_TYPE.equals(cd.getCompositeType())) {
             return new StackTraceElement(getString(cd, CLASS_LOADER_NAME),
                                          getString(cd, MODULE_NAME),
                                          getString(cd, MODULE_VERSION),
@@ -65,6 +60,12 @@
                                          getString(cd, METHOD_NAME),
                                          getString(cd, FILE_NAME),
                                          getInt(cd, LINE_NUMBER));
+        } else {
+            return new StackTraceElement(getString(cd, CLASS_NAME),
+                                         getString(cd, METHOD_NAME),
+                                         getString(cd, FILE_NAME),
+                                         getInt(cd, LINE_NUMBER));
+
         }
     }
 
@@ -75,7 +76,7 @@
 
     protected CompositeData getCompositeData() {
         // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
-        // stackTraceElementItemNames!
+        // STACK_TRACE_ELEMENT_ATTRIBUTES!
         final Object[] stackTraceElementItemValues = {
             ste.getClassLoaderName(),
             ste.getModuleName(),
@@ -87,8 +88,8 @@
             ste.isNativeMethod(),
         };
         try {
-            return new CompositeDataSupport(stackTraceElementCompositeType,
-                                            stackTraceElementItemNames,
+            return new CompositeDataSupport(STACK_TRACE_ELEMENT_COMPOSITE_TYPE,
+                                            STACK_TRACE_ELEMENT_ATTRIBUTES,
                                             stackTraceElementItemValues);
         } catch (OpenDataException e) {
             // Should never reach here
@@ -106,11 +107,7 @@
     private static final String LINE_NUMBER       = "lineNumber";
     private static final String NATIVE_METHOD     = "nativeMethod";
 
-
-    private static final String[] stackTraceElementItemNames = {
-        CLASS_LOADER_NAME,
-        MODULE_NAME,
-        MODULE_VERSION,
+    private static final String[] V5_ATTRIBUTES = {
         CLASS_NAME,
         METHOD_NAME,
         FILE_NAME,
@@ -118,30 +115,48 @@
         NATIVE_METHOD,
     };
 
-    private static final String[] stackTraceElementV9ItemNames = {
+    private static final String[] V9_ATTRIBUTES = {
         CLASS_LOADER_NAME,
         MODULE_NAME,
         MODULE_VERSION,
     };
 
-    private static final CompositeType stackTraceElementCompositeType;
-    private static final CompositeType stackTraceElementV6CompositeType;
+    private static final String[] STACK_TRACE_ELEMENT_ATTRIBUTES =
+        Stream.of(V5_ATTRIBUTES, V9_ATTRIBUTES).flatMap(Arrays::stream)
+              .toArray(String[]::new);
+
+    private static final CompositeType STACK_TRACE_ELEMENT_COMPOSITE_TYPE;
+    private static final CompositeType V5_COMPOSITE_TYPE;
     static {
         try {
-            stackTraceElementCompositeType = (CompositeType)
+            STACK_TRACE_ELEMENT_COMPOSITE_TYPE = (CompositeType)
                 MappedMXBeanType.toOpenType(StackTraceElement.class);
-            stackTraceElementV6CompositeType =
-                TypeVersionMapper.getInstance().getVersionedCompositeType(
-                    stackTraceElementCompositeType,
-                    TypeVersionMapper.V6
-                );
+
+            OpenType<?>[] types = new OpenType<?>[V5_ATTRIBUTES.length];
+            for (int i=0; i < V5_ATTRIBUTES.length; i++) {
+                String name = V5_ATTRIBUTES[i];
+                types[i] = STACK_TRACE_ELEMENT_COMPOSITE_TYPE.getType(name);
+            }
+            V5_COMPOSITE_TYPE = new CompositeType("StackTraceElement",
+                                                  "JDK 5 StackTraceElement",
+                                                  V5_ATTRIBUTES,
+                                                  V5_ATTRIBUTES,
+                                                  types);
         } catch (OpenDataException e) {
             // Should never reach here
             throw new AssertionError(e);
         }
     }
 
-    /** Validate if the input CompositeData has the expected
+    static CompositeType v5CompositeType() {
+        return V5_COMPOSITE_TYPE;
+    }
+    static CompositeType compositeType() {
+        return STACK_TRACE_ELEMENT_COMPOSITE_TYPE;
+    }
+
+    /**
+     * Validate if the input CompositeData has the expected
      * CompositeType (i.e. contain all attributes with expected
      * names and types).
      */
@@ -151,22 +166,11 @@
         }
 
         CompositeType ct = cd.getCompositeType();
-        if (!isTypeMatched(stackTraceElementCompositeType, ct)) {
-            if (!isTypeMatched(stackTraceElementV6CompositeType, ct)) {
-                throw new IllegalArgumentException(
-                    "Unexpected composite type for StackTraceElement");
-            }
+        if (!isTypeMatched(STACK_TRACE_ELEMENT_COMPOSITE_TYPE, ct) &&
+            !isTypeMatched(V5_COMPOSITE_TYPE, ct)) {
+            throw new IllegalArgumentException(
+                "Unexpected composite type for StackTraceElement");
         }
     }
-
-    static boolean isV6Attribute(String name) {
-        for(String attrName : stackTraceElementV9ItemNames) {
-            if (name.equals(attrName)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     private static final long serialVersionUID = -2704607706598396827L;
 }
--- a/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,16 @@
 import java.lang.management.ThreadInfo;
 import java.lang.management.MonitorInfo;
 import java.lang.management.LockInfo;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.CompositeDataSupport;
 import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
 
 /**
  * A CompositeData for ThreadInfo for the local management support.
@@ -41,35 +47,21 @@
 public class ThreadInfoCompositeData extends LazyCompositeData {
     private final ThreadInfo threadInfo;
     private final CompositeData cdata;
-    private final boolean currentVersion;
-    private final boolean hasV6;
 
     private ThreadInfoCompositeData(ThreadInfo ti) {
         this.threadInfo = ti;
-        this.currentVersion = true;
         this.cdata = null;
-        this.hasV6 = true;
     }
 
     private ThreadInfoCompositeData(CompositeData cd) {
         this.threadInfo = null;
-        this.currentVersion = ThreadInfoCompositeData.isCurrentVersion(cd);
         this.cdata = cd;
-        this.hasV6 = ThreadInfoCompositeData.hasV6(cd);
     }
 
     public ThreadInfo getThreadInfo() {
         return threadInfo;
     }
 
-    public boolean hasV6() {
-        return hasV6;
-    }
-
-    public boolean isCurrentVersion() {
-        return currentVersion;
-    }
-
     public static ThreadInfoCompositeData getInstance(CompositeData cd) {
         validateCompositeData(cd);
         return new ThreadInfoCompositeData(cd);
@@ -112,7 +104,7 @@
         }
 
         // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
-        // threadInfoItemNames!
+        // THREAD_INFO_ATTRIBUTES!
         final Object[] threadInfoItemValues = {
             threadInfo.getThreadId(),
             threadInfo.getThreadName(),
@@ -126,8 +118,8 @@
             threadInfo.getLockOwnerId(),
             threadInfo.getLockOwnerName(),
             stackTraceData,
-                threadInfo.isSuspended(),
-                threadInfo.isInNative(),
+            threadInfo.isSuspended(),
+            threadInfo.isInNative(),
             lockedMonitorsData,
             lockedSyncsData,
             threadInfo.isDaemon(),
@@ -135,8 +127,8 @@
         };
 
         try {
-            return new CompositeDataSupport(threadInfoCompositeType,
-                                            threadInfoItemNames,
+            return new CompositeDataSupport(compositeType(),
+                                            THREAD_INFO_ATTRIBTUES,
                                             threadInfoItemValues);
         } catch (OpenDataException e) {
             // Should never reach here
@@ -164,7 +156,7 @@
     private static final String LOCKED_MONITORS = "lockedMonitors";
     private static final String LOCKED_SYNCS    = "lockedSynchronizers";
 
-    private static final String[] threadInfoItemNames = {
+    private static final String[] V5_ATTRIBUTES = {
         THREAD_ID,
         THREAD_NAME,
         THREAD_STATE,
@@ -172,109 +164,28 @@
         BLOCKED_COUNT,
         WAITED_TIME,
         WAITED_COUNT,
-        LOCK_INFO,
         LOCK_NAME,
         LOCK_OWNER_ID,
         LOCK_OWNER_NAME,
         STACK_TRACE,
         SUSPENDED,
-        IN_NATIVE,
-        LOCKED_MONITORS,
-        LOCKED_SYNCS,
-        DAEMON,
-        PRIORITY,
+        IN_NATIVE
     };
 
-    // New attributes added in 6.0 ThreadInfo
-    private static final String[] threadInfoV6Attributes = {
+    private static final String[] V6_ATTRIBUTES = {
         LOCK_INFO,
         LOCKED_MONITORS,
         LOCKED_SYNCS,
     };
 
-    private static final String[] threadInfoV9Attributes = {
+    private static final String[] V9_ATTRIBUTES = {
         DAEMON,
         PRIORITY,
     };
 
-    // Current version of ThreadInfo
-    private static final CompositeType threadInfoCompositeType;
-    // Previous version of ThreadInfo
-    private static final CompositeType threadInfoV6CompositeType;
-    // Previous-previous version of ThreadInfo
-    private static final CompositeType threadInfoV5CompositeType;
-    private static final CompositeType lockInfoCompositeType;
-    static {
-        try {
-            threadInfoCompositeType = (CompositeType)
-                MappedMXBeanType.toOpenType(ThreadInfo.class);
-            // Form a CompositeType for JDK 5.0 ThreadInfo version
-
-            threadInfoV5CompositeType =
-                TypeVersionMapper.getInstance().getVersionedCompositeType(
-                    threadInfoCompositeType, TypeVersionMapper.V5
-                );
-
-            threadInfoV6CompositeType =
-                TypeVersionMapper.getInstance().getVersionedCompositeType(
-                    threadInfoCompositeType, TypeVersionMapper.V6
-                );
-        } catch (OpenDataException e) {
-            // Should never reach here
-            throw new AssertionError(e);
-        }
-
-        // Each CompositeData object has its CompositeType associated
-        // with it.  So we can get the CompositeType representing LockInfo
-        // from a mapped CompositeData for any LockInfo object.
-        // Thus we construct a random LockInfo object and pass it
-        // to LockInfoCompositeData to do the conversion.
-        Object o = new Object();
-        LockInfo li = new LockInfo(o.getClass().getName(),
-                                   System.identityHashCode(o));
-        CompositeData cd = LockInfoCompositeData.toCompositeData(li);
-        lockInfoCompositeType = cd.getCompositeType();
-    }
-
-    static boolean isV5Attribute(String itemName) {
-        for (String n : threadInfoV6Attributes) {
-            if (itemName.equals(n)) {
-                return false;
-            }
-        }
-        for (String n : threadInfoV9Attributes) {
-            if (itemName.equals(n)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    static boolean isV6Attribute(String itemName) {
-        for (String n : threadInfoV9Attributes) {
-            if (itemName.equals(n)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public static boolean isCurrentVersion(CompositeData cd) {
-        if (cd == null) {
-            throw new NullPointerException("Null CompositeData");
-        }
-
-        return isTypeMatched(threadInfoCompositeType, cd.getCompositeType());
-    }
-
-    private static boolean hasV6(CompositeData cd) {
-        if (cd == null) {
-            throw new NullPointerException("Null CompositeData");
-        }
-
-        return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()) ||
-               isTypeMatched(threadInfoV6CompositeType, cd.getCompositeType());
-     }
+    private static final String[] THREAD_INFO_ATTRIBTUES =
+        Stream.of(V5_ATTRIBUTES, V6_ATTRIBUTES, V9_ATTRIBUTES)
+              .flatMap(Arrays::stream).toArray(String[]::new);
 
     public long threadId() {
         return getLong(cdata, THREAD_ID);
@@ -333,12 +244,18 @@
         return getBoolean(cdata, IN_NATIVE);
     }
 
+    /*
+     * if daemon attribute is not present, default to false.
+     */
     public boolean isDaemon() {
-        return getBoolean(cdata, DAEMON);
+        return cdata.containsKey(DAEMON) ? getBoolean(cdata, DAEMON) : false;
     }
 
+    /*
+     * if priority attribute is not present, default to norm priority.
+     */
     public int getPriority(){
-        return getInt(cdata, PRIORITY);
+        return cdata.containsKey(PRIORITY) ? getInt(cdata, PRIORITY) : Thread.NORM_PRIORITY;
     }
 
     public StackTraceElement[] stackTrace() {
@@ -356,13 +273,37 @@
         return stackTrace;
     }
 
-    // 6.0 new attributes
+    /*
+     * lockInfo is a new attribute added in JDK 6 ThreadInfo
+     * If cd is a 5.0 version, construct the LockInfo object
+     * from the lockName value.
+     */
     public LockInfo lockInfo() {
-        CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO);
-        return LockInfo.from(lockInfoData);
+        if (cdata.containsKey(LOCK_INFO)) {
+            CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO);
+            return LockInfo.from(lockInfoData);
+        } else {
+            String lockName = lockName();
+            LockInfo lock = null;
+            if (lockName != null) {
+                String result[] = lockName.split("@");
+                if (result.length == 2) {
+                    int identityHashCode = Integer.parseInt(result[1], 16);
+                    lock = new LockInfo(result[0], identityHashCode);
+                }
+            }
+            return lock;
+        }
     }
 
+    /**
+     * Returns an empty array if locked_monitors attribute is not present.
+     */
     public MonitorInfo[] lockedMonitors() {
+        if (!cdata.containsKey(LOCKED_MONITORS)) {
+            return new MonitorInfo[0];
+        }
+
         CompositeData[] lockedMonitorsData =
             (CompositeData[]) cdata.get(LOCKED_MONITORS);
 
@@ -377,7 +318,14 @@
         return monitors;
     }
 
+    /**
+     * Returns an empty array if locked_monitors attribute is not present.
+     */
     public LockInfo[] lockedSynchronizers() {
+        if (!cdata.containsKey(LOCKED_SYNCS)) {
+            return new LockInfo[0];
+        }
+
         CompositeData[] lockedSyncsData =
             (CompositeData[]) cdata.get(LOCKED_SYNCS);
 
@@ -391,7 +339,8 @@
         return locks;
     }
 
-    /** Validate if the input CompositeData has the expected
+    /**
+     * Validate if the input CompositeData has the expected
      * CompositeType (i.e. contain all attributes with expected
      * names and types).
      */
@@ -401,62 +350,98 @@
         }
 
         CompositeType type = cd.getCompositeType();
-        boolean currentVersion = true;
-        if (!isTypeMatched(threadInfoCompositeType, type)) {
-            currentVersion = false;
-            // check if cd is an older version
-            if (!isTypeMatched(threadInfoV5CompositeType, type) &&
-                !isTypeMatched(threadInfoV6CompositeType, type)) {
-                throw new IllegalArgumentException(
-                    "Unexpected composite type for ThreadInfo");
+        int version;
+        if (Arrays.stream(V9_ATTRIBUTES).anyMatch(type::containsKey)) {
+            version = Runtime.version().feature();
+        } else if (Arrays.stream(V6_ATTRIBUTES).anyMatch(type::containsKey)) {
+            version = 6;
+        } else {
+            version = 5;
+        }
+
+        if (!isTypeMatched(ThreadInfoCompositeTypes.ofVersion(version), type)) {
+            throw new IllegalArgumentException(
+                "Unexpected composite type for ThreadInfo of version " + version);
+        }
+    }
+
+    public static CompositeType compositeType() {
+        return ThreadInfoCompositeTypes.compositeTypes.get(0);
+    }
+
+    static class ThreadInfoCompositeTypes {
+        static final int CURRENT =  Runtime.version().feature();
+        static final Map<Integer, CompositeType> compositeTypes = initCompositeTypes();
+        /*
+         * Returns CompositeType of the given runtime version
+         */
+        static CompositeType ofVersion(int version) {
+            return compositeTypes.get(version);
+        }
+
+        static Map<Integer, CompositeType> initCompositeTypes() {
+            Map<Integer, CompositeType> types = new HashMap<>();
+            CompositeType ctype = initCompositeType();
+            types.put(CURRENT, ctype);
+            types.put(5, initV5CompositeType(ctype));
+            types.put(6, initV6CompositeType(ctype));
+            return types;
+        }
+
+        static CompositeType initCompositeType() {
+            try {
+                return (CompositeType)MappedMXBeanType.toOpenType(ThreadInfo.class);
+            } catch (OpenDataException e) {
+                // Should never reach here
+                throw new AssertionError(e);
             }
         }
 
-        CompositeData[] stackTraceData =
-            (CompositeData[]) cd.get(STACK_TRACE);
-        if (stackTraceData == null) {
-            throw new IllegalArgumentException(
-                "StackTraceElement[] is missing");
-        }
-        if (stackTraceData.length > 0) {
-            StackTraceElementCompositeData.validateCompositeData(stackTraceData[0]);
+        static CompositeType initV5CompositeType(CompositeType threadInfoCompositeType) {
+            try {
+                OpenType<?>[] v5Types = new OpenType<?>[V5_ATTRIBUTES.length];
+                for (int i = 0; i < v5Types.length; i++) {
+                    String name = V5_ATTRIBUTES[i];
+                    v5Types[i] = name.equals(STACK_TRACE)
+                        ? new ArrayType<>(1, StackTraceElementCompositeData.v5CompositeType())
+                        : threadInfoCompositeType.getType(name);
+                }
+                return new CompositeType("ThreadInfo",
+                                         "JDK 5 ThreadInfo",
+                                         V5_ATTRIBUTES,
+                                         V5_ATTRIBUTES,
+                                         v5Types);
+            } catch (OpenDataException e) {
+                // Should never reach here
+                throw new AssertionError(e);
+            }
         }
 
-        // validate v6 attributes
-        if (currentVersion) {
-            CompositeData li = (CompositeData) cd.get(LOCK_INFO);
-            if (li != null) {
-                if (!isTypeMatched(lockInfoCompositeType,
-                                   li.getCompositeType())) {
-                    throw new IllegalArgumentException(
-                        "Unexpected composite type for \"" +
-                        LOCK_INFO + "\" attribute.");
+        static CompositeType initV6CompositeType(CompositeType threadInfoCompositeType) {
+            try {
+                String[] v6Names = Stream.of(V5_ATTRIBUTES, V6_ATTRIBUTES)
+                    .flatMap(Arrays::stream).toArray(String[]::new);
+                OpenType<?>[] v6Types = new OpenType<?>[v6Names.length];
+                for (int i = 0; i < v6Names.length; i++) {
+                    String name = v6Names[i];
+                    OpenType<?> ot = threadInfoCompositeType.getType(name);
+                    if (name.equals(STACK_TRACE)) {
+                        ot = new ArrayType<>(1, StackTraceElementCompositeData.v5CompositeType());
+                    } else if (name.equals(LOCKED_MONITORS)) {
+                        ot = new ArrayType<>(1, MonitorInfoCompositeData.v6CompositeType());
+                    }
+                    v6Types[i] = ot;
                 }
-            }
-
-            CompositeData[] lms = (CompositeData[]) cd.get(LOCKED_MONITORS);
-            if (lms == null) {
-                throw new IllegalArgumentException("MonitorInfo[] is null");
+                return new CompositeType("ThreadInfo",
+                                         "JDK 6 ThreadInfo",
+                                         v6Names,
+                                         v6Names,
+                                         v6Types);
+            } catch (OpenDataException e) {
+                // Should never reach here
+                throw new AssertionError(e);
             }
-            if (lms.length > 0) {
-                MonitorInfoCompositeData.validateCompositeData(lms[0]);
-            }
-
-            CompositeData[] lsyncs = (CompositeData[]) cd.get(LOCKED_SYNCS);
-            if (lsyncs == null) {
-                throw new IllegalArgumentException("LockInfo[] is null");
-            }
-            if (lsyncs.length > 0) {
-                if (!isTypeMatched(lockInfoCompositeType,
-                                   lsyncs[0].getCompositeType())) {
-                    throw new IllegalArgumentException(
-                        "Unexpected composite type for \"" +
-                        LOCKED_SYNCS + "\" attribute.");
-                }
-            }
-
         }
     }
-
     private static final long serialVersionUID = 2464378539119753175L;
 }
--- a/src/java.management/share/classes/sun/management/TypeVersionMapper.java	Wed Feb 28 18:36:25 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.management;
-
-import java.lang.management.ThreadInfo;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.TabularType;
-import static sun.management.Util.toStringArray;
-
-/**
- * Provides simplistic support for versioning of {@linkplain CompositeType} instances
- * based on the latest version and filtering out certain items.
- */
-final class TypeVersionMapper {
-    private static final class Singleton {
-        private final static TypeVersionMapper INSTANCE = new TypeVersionMapper();
-    }
-
-    final static String V5 = "J2SE 5.0";
-    final static String V6 = "Java SE 6";
-
-    private final Map<String, Map<String, Predicate<String>>> filterMap;
-
-    private TypeVersionMapper() {
-        filterMap = new HashMap<>();
-        setupStackTraceElement();
-        setupThreadInfo();
-    }
-
-    public static TypeVersionMapper getInstance() {
-        return Singleton.INSTANCE;
-    }
-
-    private void setupStackTraceElement() {
-        Map<String, Predicate<String>> filter = new HashMap<>();
-        filterMap.put(StackTraceElement.class.getName(), filter);
-        filter.put(V5, StackTraceElementCompositeData::isV6Attribute);
-        filter.put(V6, StackTraceElementCompositeData::isV6Attribute);
-    }
-
-    private void setupThreadInfo() {
-        Map<String, Predicate<String>> filter = new HashMap<>();
-        filterMap.put(ThreadInfo.class.getName(), filter);
-        filter.put(V5, ThreadInfoCompositeData::isV5Attribute);
-        filter.put(V6, ThreadInfoCompositeData::isV6Attribute);
-    }
-
-    /**
-     * Retrieves the specified version of a {@linkplain CompositeType} instance.
-     * @param type The current (latest) version of {@linkplain CompositeType}
-     * @param version The version identifier (eg. {@linkplain TypeVersionMapper#V5})
-     * @return Returns the {@linkplain CompositeType} corresponding to the requested
-     *         version.
-     * @throws OpenDataException
-     */
-    CompositeType getVersionedCompositeType(CompositeType type, String version)
-        throws OpenDataException
-    {
-        Predicate<String> filter = getFilter(type.getTypeName(), version);
-        if (filter == null) {
-            return type;
-        }
-
-        List<String> itemNames = new ArrayList<>();
-        List<String> itemDesc = new ArrayList<>();
-        List<OpenType<?>> itemTypes = new ArrayList<>();
-
-        for(String item : type.keySet()) {
-            if (filter.test(item)) {
-                itemNames.add(item);
-                itemDesc.add(type.getDescription(item));
-                itemTypes.add(getVersionedType(
-                    type.getType(item),
-                    version
-                ));
-            }
-        }
-        return new CompositeType(
-            type.getTypeName(),
-            version != null ? version + " " + type.getDescription() : type.getDescription(),
-            itemNames.toArray(new String[itemNames.size()]),
-            itemDesc.toArray(new String[itemDesc.size()]),
-            itemTypes.toArray(new OpenType<?>[itemTypes.size()])
-        );
-    }
-
-    private OpenType<?> getVersionedType(OpenType<?> type, String version)
-        throws OpenDataException
-    {
-        if (type instanceof ArrayType) {
-            return getVersionedArrayType((ArrayType)type, version);
-        }
-        if (type instanceof CompositeType) {
-            return getVersionedCompositeType((CompositeType)type, version);
-        }
-        if (type instanceof TabularType) {
-            return getVersionedTabularType((TabularType)type, version);
-        }
-        return type;
-    }
-
-    private ArrayType<?> getVersionedArrayType(ArrayType<?> type, String version)
-        throws OpenDataException
-    {
-        if (type.isPrimitiveArray()) {
-            return type;
-        }
-        OpenType<?> ot = getVersionedType(
-            type.getElementOpenType(),
-            version
-        );
-        if (ot instanceof SimpleType) {
-            return new ArrayType<>((SimpleType<?>)ot, type.isPrimitiveArray());
-        } else {
-            return new ArrayType<>(type.getDimension(), ot);
-        }
-    }
-
-    private TabularType getVersionedTabularType(TabularType type, String version)
-        throws OpenDataException
-    {
-        CompositeType ct = getVersionedCompositeType(
-            type.getRowType(),
-            version
-        );
-
-        if (ct != null) {
-            return new TabularType(
-                type.getTypeName(), type.getDescription(), ct,
-                toStringArray(type.getIndexNames()));
-        }
-        return null;
-    }
-
-    private Predicate<String> getFilter(String type, String version) {
-        Map<String, Predicate<String>> versionMap = filterMap.get(type);
-        if (versionMap == null) {
-            return null;
-        }
-
-        return versionMap.get(version);
-    }
-}
--- a/test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,26 +23,26 @@
 
 /*
  * @test
- * @bug     4982289
+ * @bug     4982289 8198253
  * @summary Test ThreadInfo.from to return a valid
  *          ThreadInfo object. Or throw exception if
  *          the input CompositeData is invalid.
  * @author  Mandy Chung
  *
- * @compile OpenTypeConverter.java
- * @build ThreadInfoCompositeData
+ * @build ThreadInfoCompositeData OpenTypeConverter
  * @run main ThreadInfoCompositeData
  */
 
+
 import javax.management.openmbean.*;
 import java.lang.management.LockInfo;
 import java.lang.management.MonitorInfo;
 import java.lang.management.ThreadInfo;
+import java.util.Arrays;
 import java.util.Objects;
+import java.util.stream.Stream;
 
 public class ThreadInfoCompositeData {
-    private static StackTraceElement[] ste = new StackTraceElement[1];
-    private static CompositeData[] steCD = new CompositeData[1];
     private static String lockClassName = "myClass";
     private static int lockIdentityHashCode = 123456;
     private static String lockName = lockClassName + '@' +
@@ -53,55 +53,100 @@
     public static void main(String[] argv) throws Exception {
         // A valid CompositeData is passed to ThreadInfo
         createGoodCompositeData();
-        // A valid CompositeData for JDK 5.0 ThreadInfo
+        // A valid CompositeData for JDK 5 ThreadInfo
         // is passed to ThreadInfo
         createV5ThreadInfo();
+        // ThreadInfo of version N can accept lockedMonitors of version >= N
+        withNewMonitorInfoCompositeData();
+
         // An invalid CompositeData is passed to ThreadInfo.from()
         badNameCompositeData();
         badTypeCompositeData();
+        badMissingCompositeData();
+        withV5StackTraceCompositeData();
+        withInvalidMonitorInfoCompositeData();
         System.out.println("Test passed");
     }
 
     public static void createGoodCompositeData() throws Exception {
-        CompositeType ct =
-            new CompositeType("MyCompositeType",
-                              "CompositeType for ThreadInfo",
-                              validItemNames,
-                              validItemNames,
-                              validItemTypes);
-        CompositeData cd =
-            new CompositeDataSupport(ct,
-                                     validItemNames,
-                                     values);
+        CompositeData cd = Factory.makeThreadInfoCompositeData();
         ThreadInfo info = ThreadInfo.from(cd);
         checkThreadInfo(info);
+    }
+
+    /*
+     * An invalid CompositeData with JDK 9 attributes but missing JDK 6 attributes
+     */
+    public static void badMissingCompositeData() throws Exception {
+        CompositeData cd = Factory.makeCompositeDataMissingV6();
+        try {
+            ThreadInfo info = ThreadInfo.from(cd);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) {}
+    }
+
+    static final StackTraceElement STE =
+        new StackTraceElement("FooClass", "getFoo", "Foo.java", 100);
+
+
+    /*
+     * Current version of ThreadInfo but an older version of StackTraceElement
+     */
+    public static void withV5StackTraceCompositeData() throws Exception {
+        CompositeData cd = Factory.makeThreadInfoWithV5StackTrace();
+        try {
+            ThreadInfo info = ThreadInfo.from(cd);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) {}
+    }
+
+    /*
+     * Current version of ThreadInfo but an older version of MonitorInfo
+     * and the value of "lockedStackFrame" attribute is null.
+     */
+    public static void withInvalidMonitorInfoCompositeData() throws Exception {
+        CompositeData cd = Factory.makeThreadInfoWithIncompatibleMonitorInfo();
+
+        // verify MonitorInfo is valid
+        CompositeData[] monitors = (CompositeData[])cd.get("lockedMonitors");
+        CompositeData ste = (CompositeData)monitors[0].get("lockedStackFrame");
+        if (((Integer)monitors[0].get("lockedStackDepth")) >= 0 || ste != null) {
+            throw new RuntimeException("Expected negative stack depth and null stack frame");
+        }
+        MonitorInfo minfo = MonitorInfo.from(monitors[0]);
+        checkLockInfo(minfo);
+        if (minfo.getLockedStackFrame() != null) {
+            throw new RuntimeException("Expected null stack frame");
+        }
+
+        try {
+            ThreadInfo info = ThreadInfo.from(cd);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) {}
+    }
+
+    /*
+     * ThreadInfo of version N can accept lockedMonitors of version >= N
+     */
+    public static void withNewMonitorInfoCompositeData() throws Exception {
+        CompositeData cd = Factory.makeThreadInfoWithNewMonitorInfo();
+        ThreadInfo info = ThreadInfo.from(cd);
+        checkThreadInfo(info);
+    }
+
+    /*
+     * Test CompositeData representing JDK 5 ThreadInfo
+     */
+    public static void createV5ThreadInfo() throws Exception {
+        CompositeData cd = Factory.makeThreadInfoV5CompositeData();
+        ThreadInfo info = ThreadInfo.from(cd);
+        checkThreadInfoV5(info);
    }
 
-    public static void createV5ThreadInfo() throws Exception {
-        String[] v5ItemNames = new String[NUM_V5_ATTS];
-        OpenType[] v5ItemTypes = new OpenType[NUM_V5_ATTS];
-        Object[] v5ItemValues = new Object[NUM_V5_ATTS];
-        for (int i = 0; i < NUM_V5_ATTS; i++) {
-            v5ItemNames[i] = validItemNames[i];
-            v5ItemTypes[i] = validItemTypes[i];
-            v5ItemValues[i] = values[i];
-        }
-        CompositeType ct =
-            new CompositeType("MyCompositeType",
-                              "CompositeType for JDK 5.0 ThreadInfo",
-                              v5ItemNames,
-                              v5ItemNames,
-                              v5ItemTypes);
-        CompositeData cd =
-            new CompositeDataSupport(ct,
-                                     v5ItemNames,
-                                     v5ItemValues);
-        ThreadInfo info = ThreadInfo.from(cd);
-        checkThreadInfo(info);
-   }
+   static void checkThreadInfoV5(ThreadInfo info) {
+       Object[] values = Factory.VALUES;
 
-   static void checkThreadInfo(ThreadInfo info) throws Exception {
-        if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
+       if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
             throw new RuntimeException("Thread Id = " + info.getThreadId() +
                " expected = " + values[THREAD_ID]);
         }
@@ -148,30 +193,35 @@
                info.getLockOwnerName() + " expected = " +
                values[LOCK_OWNER_NAME]);
         }
+
+        checkStackTrace(info.getStackTrace());
+        checkLockInfo(info.getLockInfo());
+   }
+
+    static void checkThreadInfo(ThreadInfo info) {
+        Object[] values = Factory.VALUES;
+
+        checkThreadInfoV5(info);
+
         if (!values[DAEMON].equals(info.isDaemon())) {
             throw new RuntimeException("Daemon = " +
-               info.isDaemon() + " expected = " +
-               values[DAEMON]);
+               info.isDaemon() + " expected = " + values[DAEMON]);
         }
-
-        checkStackTrace(info.getStackTrace());
-
-        checkLockInfo(info.getLockInfo());
     }
 
-    private static void checkStackTrace(StackTraceElement[] s)
-        throws Exception {
-        if (ste.length != s.length) {
+    private static void checkStackTrace(StackTraceElement[] s) {
+        if (s.length != 1) {
             throw new RuntimeException("Stack Trace length = " +
-                s.length + " expected = " + ste.length);
+                s.length + " expected = 1");
         }
 
-        StackTraceElement s1 = ste[0];
+        StackTraceElement s1 = STE;
         StackTraceElement s2 = s[0];
 
-        if (!s1.getClassName().equals(s2.getClassName())) {
-            throw new RuntimeException("Class name = " +
-                s2.getClassName() + " expected = " + s1.getClassName());
+        // these attributes may be null
+        if (!Objects.equals(s1.getClassLoaderName(), s2.getClassLoaderName())) {
+            throw new RuntimeException("Class loader name = " +
+                s2.getClassLoaderName() + " expected = " + s1.getClassLoaderName());
         }
         if (!Objects.equals(s1.getModuleName(), s2.getModuleName())) {
             throw new RuntimeException("Module name = " +
@@ -181,6 +231,11 @@
             throw new RuntimeException("Module version = " +
                 s2.getModuleVersion() + " expected = " + s1.getModuleVersion());
         }
+
+        if (!s1.getClassName().equals(s2.getClassName())) {
+            throw new RuntimeException("Class name = " +
+                s2.getClassName() + " expected = " + s1.getClassName());
+        }
         if (!s1.getMethodName().equals(s2.getMethodName())) {
             throw new RuntimeException("Method name = " +
                 s2.getMethodName() + " expected = " + s1.getMethodName());
@@ -195,8 +250,7 @@
         }
     }
 
-    private static void checkLockInfo(LockInfo li)
-        throws Exception {
+    private static void checkLockInfo(LockInfo li) {
         if (!li.getClassName().equals(lockInfo.getClassName())) {
             throw new RuntimeException("Class Name = " +
                 li.getClassName() + " expected = " + lockInfo.getClassName());
@@ -209,227 +263,493 @@
     }
 
     public static void badNameCompositeData() throws Exception {
-        CompositeType ct =
-            new CompositeType("MyCompositeType",
-                              "CompositeType for ThreadInfo",
-                              badItemNames,
-                              badItemNames,
-                              validItemTypes);
-        CompositeData cd =
-            new CompositeDataSupport(ct,
-                                     badItemNames,
-                                     values);
-
+        CompositeData cd = Factory.makeCompositeDataWithBadNames();
         try {
             ThreadInfo info = ThreadInfo.from(cd);
-        } catch (IllegalArgumentException e) {
-            System.out.println("Expected exception: " +
-                e.getMessage());
-            return;
-        }
-        throw new RuntimeException(
-            "IllegalArgumentException not thrown");
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) { }
     }
 
     public static void badTypeCompositeData() throws Exception {
-        CompositeType ct =
-            new CompositeType("MyCompositeType",
-                              "CompositeType for ThreadInfo",
-                              validItemNames,
-                              validItemNames,
-                              badItemTypes);
-
-        // patch values[STACK_TRACE] to Long
-        values[STACK_TRACE] = new Long(1000);
-        values[LOCK_INFO] = new Long(1000);
-        CompositeData cd =
-            new CompositeDataSupport(ct,
-                                     validItemNames,
-                                     values);
+        CompositeData cd = Factory.makeCompositeDataWithBadTypes();
 
         try {
             ThreadInfo info = ThreadInfo.from(cd);
-        } catch (IllegalArgumentException e) {
-            System.out.println("Expected exception: " +
-                e.getMessage());
-            return;
-        }
-        throw new RuntimeException(
-            "IllegalArgumentException not thrown");
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException e) { }
     }
 
-    private static final int THREAD_ID       = 0;
-    private static final int THREAD_NAME     = 1;
-    private static final int THREAD_STATE    = 2;
-    private static final int BLOCKED_TIME    = 3;
-    private static final int BLOCKED_COUNT   = 4;
-    private static final int WAITED_TIME     = 5;
-    private static final int WAITED_COUNT    = 6;
-    private static final int LOCK_NAME       = 7;
-    private static final int LOCK_OWNER_ID   = 8;
+    private static final int THREAD_ID = 0;
+    private static final int THREAD_NAME = 1;
+    private static final int THREAD_STATE = 2;
+    private static final int BLOCKED_TIME = 3;
+    private static final int BLOCKED_COUNT = 4;
+    private static final int WAITED_TIME = 5;
+    private static final int WAITED_COUNT = 6;
+    private static final int LOCK_NAME = 7;
+    private static final int LOCK_OWNER_ID = 8;
     private static final int LOCK_OWNER_NAME = 9;
-    private static final int STACK_TRACE     = 10;
-    private static final int SUSPENDED       = 11;
-    private static final int IN_NATIVE       = 12;
-    private static final int NUM_V5_ATTS     = 13;
-    // JDK 6.0 ThreadInfo attributes
-    private static final int LOCK_INFO       = 13;
-    // JDK 9.0 ThreadInfo attributes
-    private static final int DAEMON          = 14;
-    private static final int PRIORITY        = 15;
+    private static final int STACK_TRACE = 10;
+    private static final int SUSPENDED = 11;
+    private static final int IN_NATIVE = 12;
+    // JDK 6 ThreadInfo attributes
+    private static final int LOCK_INFO = 13;
+    private static final int LOCKED_MONITORS = 14;
+    private static final int LOCKED_SYNCS = 15;
+    // JDK 9 ThreadInfo attributes
+    private static final int DAEMON = 16;
+    private static final int PRIORITY = 17;
+
+    static class Factory {
 
-    private static final String[] validItemNames = {
-        "threadId",
-        "threadName",
-        "threadState",
-        "blockedTime",
-        "blockedCount",
-        "waitedTime",
-        "waitedCount",
-        "lockName",
-        "lockOwnerId",
-        "lockOwnerName",
-        "stackTrace",
-        "suspended",
-        "inNative",
-        "lockInfo",
-        "daemon",
-        "priority",
-    };
+        static final CompositeType STE_COMPOSITE_TYPE;
+        static final CompositeType LOCK_INFO_COMPOSITE_TYPE;
+        static final CompositeType MONITOR_INFO_COMPOSITE_TYPE;
+        static final ArrayType STE_ARRAY_COMPOSITE_TYPE;
+        static final ArrayType LOCK_INFO_ARRAY_COMPOSITE_TYPE;
+        static final ArrayType MONITOR_INFO_ARRAY_COMPOSITE_TYPE;
+
+        static {
+            CompositeType steCType = null;
+            CompositeType lockInfoCType = null;
+            CompositeType monitorInfoCType = null;
+            ArrayType steArrayType = null;
+            ArrayType lockInfoArrayType = null;
+            ArrayType monitorInfoArrayType = null;
 
-    private static OpenType[] validItemTypes = {
-        SimpleType.LONG,
-        SimpleType.STRING,
-        SimpleType.STRING,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.STRING,
-        SimpleType.LONG,
-        SimpleType.STRING,
-        null,  // ArrayType for StackTraceElement[]
-        SimpleType.BOOLEAN,
-        SimpleType.BOOLEAN,
-        null,  // CompositeType for LockInfo
-        SimpleType.BOOLEAN,
-        SimpleType.INTEGER,
-    };
+            try {
+                steCType = (CompositeType) OpenTypeConverter.toOpenType(StackTraceElement.class);
+                lockInfoCType = (CompositeType) OpenTypeConverter.toOpenType(LockInfo.class);
+                monitorInfoCType = (CompositeType) OpenTypeConverter.toOpenType(MonitorInfo.class);
+                steArrayType = new ArrayType(1, steCType);
+                lockInfoArrayType = new ArrayType(1, lockInfoCType);
+                monitorInfoArrayType = new ArrayType(1, monitorInfoCType);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            STE_COMPOSITE_TYPE = steCType;
+            LOCK_INFO_COMPOSITE_TYPE = lockInfoCType;
+            MONITOR_INFO_COMPOSITE_TYPE = monitorInfoCType;
+            STE_ARRAY_COMPOSITE_TYPE = steArrayType;
+            LOCK_INFO_ARRAY_COMPOSITE_TYPE = lockInfoArrayType;
+            MONITOR_INFO_ARRAY_COMPOSITE_TYPE = monitorInfoArrayType;
+        }
+
+        static CompositeData makeThreadInfoCompositeData() throws OpenDataException {
+            CompositeType ct = new CompositeType("MyCompositeType",
+                "CompositeType for ThreadInfo",
+                ITEM_NAMES,
+                ITEM_NAMES,
+                ITEM_TYPES);
+            return new CompositeDataSupport(ct, ITEM_NAMES, VALUES);
+        }
 
-    private static Object[] values = {
-        new Long(100),
-        "FooThread",
-        "RUNNABLE",
-        new Long(200),
-        new Long(10),
-        new Long(300),
-        new Long(20),
-        lockName,
-        new Long(99),
-        "BarThread",
-        steCD,
-        new Boolean(false),
-        new Boolean(false),
-        null, // To be initialized to lockInfoCD
-        new Boolean(false),
-        Thread.NORM_PRIORITY,
-    };
+        static CompositeData makeThreadInfoV5CompositeData() throws OpenDataException {
+            CompositeType ct = new CompositeType("MyCompositeType",
+                "CompositeType for JDK 5 ThreadInfo",
+                V5_ITEM_NAMES,
+                V5_ITEM_NAMES,
+                V5_ITEM_TYPES);
+            return new CompositeDataSupport(ct, V5_ITEM_NAMES, V5_VALUES);
+        }
 
-    private static final String[] steItemNames = {
-        "classLoaderName",
-        "moduleName",
-        "moduleVersion",
-        "className",
-        "methodName",
-        "fileName",
-        "lineNumber",
-        "nativeMethod",
-    };
-
-    private static final String[] lockInfoItemNames = {
-        "className",
-        "identityHashCode",
-    };
-
-    static {
-        // create stack trace element
-        ste[0] = new StackTraceElement("FooClass", "getFoo", "Foo.java", 100);
-
-        // initialize the ste[0] and values and validItemTypes
-        try {
-            CompositeType steCType = (CompositeType)
-                OpenTypeConverter.toOpenType(StackTraceElement.class);
-            validItemTypes[STACK_TRACE] = new ArrayType(1, steCType);
-
-            final Object[] steValue = {
-                ste[0].getClassLoaderName(),
-                ste[0].getModuleName(),
-                ste[0].getModuleVersion(),
-                ste[0].getClassName(),
-                ste[0].getMethodName(),
-                ste[0].getFileName(),
-                new Integer(ste[0].getLineNumber()),
-                new Boolean(ste[0].isNativeMethod()),
+        static CompositeData makeCompositeDataWithBadTypes() throws OpenDataException {
+            OpenType[] badItemTypes = {
+                SimpleType.LONG,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.LONG,
+                SimpleType.LONG,
+                SimpleType.LONG,
+                SimpleType.LONG,
+                SimpleType.STRING,
+                SimpleType.LONG,
+                SimpleType.STRING,
+                SimpleType.LONG,  // bad type
+                SimpleType.BOOLEAN,
+                SimpleType.BOOLEAN,
+                SimpleType.LONG,  // bad type
+                SimpleType.LONG,  // bad type
+                SimpleType.LONG,  // bad type
+                SimpleType.BOOLEAN,
+                SimpleType.INTEGER,
             };
 
-            steCD[0] =
-                new CompositeDataSupport(steCType,
-                                         steItemNames,
-                                         steValue);
+            CompositeType ct =
+                new CompositeType("Bad item types",
+                    "CompositeType for ThreadInfo",
+                    ITEM_NAMES,
+                    ITEM_NAMES,
+                    badItemTypes);
+
+            // Copy before mutating to avoid affecting other tests.
+            Object[] localValues = VALUES.clone();
+
+            // patch values[STACK_TRACE] to Long
+            localValues[STACK_TRACE] = Long.valueOf(1000);
+            localValues[LOCK_INFO] = Long.valueOf(1000);
+            localValues[LOCKED_MONITORS] = Long.valueOf(1000);
+            localValues[LOCKED_SYNCS] = Long.valueOf(1000);
+            return new CompositeDataSupport(ct, ITEM_NAMES, localValues);
+        }
+
+        static CompositeData makeCompositeDataWithBadNames() throws OpenDataException {
+            String[] badItemNames = ITEM_NAMES.clone();
+            badItemNames[STACK_TRACE] = "BadStackTrace"; // bad item name
+
+            CompositeType ct = new CompositeType("Bad item names",
+                "CompositeType for ThreadInfo",
+                badItemNames,
+                badItemNames,
+                ITEM_TYPES);
+            return new CompositeDataSupport(ct,
+                badItemNames,
+                VALUES);
+        }
+
+        /*
+         * Create a CompositeData of ThreadInfo without JDK 6 attributes
+         */
+        static CompositeData makeCompositeDataMissingV6() throws OpenDataException {
+            String[] itemNames = concat(V5_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new);
+            OpenType[] itemTypes = concat(V5_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new);
+            Object[] values = concat(V5_VALUES, V9_VALUES).toArray(Object[]::new);
+
+            CompositeType ct =
+                new CompositeType("InvalidCompositeType",
+                    "CompositeType for ThreadInfo",
+                    itemNames,
+                    itemNames,
+                    itemTypes);
+            return new CompositeDataSupport(ct, itemNames, values);
+        }
+
+        static CompositeData makeStackTraceElement() {
+            Object[] steValue = {
+                STE.getClassLoaderName(),
+                STE.getModuleName(),
+                STE.getModuleVersion(),
+                STE.getClassName(),
+                STE.getMethodName(),
+                STE.getFileName(),
+                Integer.valueOf(STE.getLineNumber()),
+                Boolean.valueOf(STE.isNativeMethod()),
+            };
+
+            try {
+                return new CompositeDataSupport(STE_COMPOSITE_TYPE,
+                                                STE_ITEM_NAMES,
+                                                steValue);
+            } catch (OpenDataException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        static CompositeData makeStackTraceElementV5() throws OpenDataException {
+            CompositeType steV5CType =
+                new CompositeType("JDK 5 StackTraceElement",
+                    "CompositeType for JDK 5 StackTraceElement",
+                    STE_V5_ITEM_NAMES,
+                    STE_V5_ITEM_NAMES,
+                    STE_V5_ITEM_TYPES);
+
+            Object[] steV5Value = {
+                STE.getClassName(),
+                STE.getMethodName(),
+                STE.getFileName(),
+                Integer.valueOf(STE.getLineNumber()),
+                Boolean.valueOf(STE.isNativeMethod()),
+            };
+
+            return new CompositeDataSupport(steV5CType, STE_V5_ITEM_NAMES, steV5Value);
+        }
+
+        /*
+         * Create a CompositeData of ThreadInfo without JDK 5 StackTraceElement
+         */
+        static CompositeData makeThreadInfoWithV5StackTrace() throws OpenDataException {
+            OpenType[] badTypes = ITEM_TYPES.clone();
+            Object[] badValues = VALUES.clone();
 
-            CompositeType lockInfoCType = (CompositeType)
-                OpenTypeConverter.toOpenType(LockInfo.class);
-            validItemTypes[LOCK_INFO] = lockInfoCType;
+            CompositeData[] stackTrace = new CompositeData[1];
+            stackTrace[0] = makeStackTraceElementV5();
+            badTypes[STACK_TRACE] = new ArrayType(1, stackTrace[0].getCompositeType());
+            badValues[STACK_TRACE] = stackTrace;
+            CompositeType ct = new CompositeType("CompositeType",
+                "ThreadInfo with JDK 5 StackTraceElement",
+                ITEM_NAMES,
+                ITEM_NAMES,
+                badTypes);
+            return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
+        }
+
+        /*
+         * Create MonitorInfo with JDK 5 StackTraceElement (i.e. JDK 6 MonitorInfo)
+         * The value of "lockedStackFrame" attribute is null to ensure that
+         * the validation is done.
+         */
+        static CompositeData makeV6MonitorInfo() throws OpenDataException {
+            CompositeData steV5 = makeStackTraceElementV5();
+
+            String[] names = MONITOR_INFO_COMPOSITE_TYPE.keySet().toArray(new String[0]);
+            OpenType[] types = new OpenType[names.length];
+            for (int i=0; i < names.length; i++) {
+                String n = names[i];
+                types[i] = "lockedStackFrame".equals(n)
+                                ? steV5.getCompositeType()
+                                : MONITOR_INFO_COMPOSITE_TYPE.getType(n);
+            }
+
+            CompositeType ctype =
+                new CompositeType("JDK 6 MonitorInfo",
+                    "CompositeType for JDK 6 MonitorInfo",
+                    names,
+                    names,
+                    types);
+
+            Object[] values = {
+                lockClassName,
+                lockIdentityHashCode,
+                -1,
+                null
+            };
+
+            return new CompositeDataSupport(ctype, names, values);
+        }
+
+        /*
+         * Create a CompositeData of ThreadInfo with incompatible MonitorInfo
+         */
+        static CompositeData makeThreadInfoWithIncompatibleMonitorInfo() throws OpenDataException {
+            OpenType[] badTypes = ITEM_TYPES.clone();
+            Object[] badValues = VALUES.clone();
 
-            final Object[] lockInfoValue = {
+            CompositeData[] lockedMonitors = new CompositeData[1];
+            lockedMonitors[0] = makeV6MonitorInfo();
+            badTypes[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType());
+            badValues[LOCKED_MONITORS] = lockedMonitors;
+            CompositeType ct = new CompositeType("CompositeType",
+                "ThreadInfo with incompatible MonitorInfo",
+                ITEM_NAMES,
+                ITEM_NAMES,
+                badTypes);
+            return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
+        }
+
+        static CompositeData makeNewMonitorInfo() throws OpenDataException {
+            String[] names = Stream.concat(MONITOR_INFO_COMPOSITE_TYPE.keySet().stream(),
+                                           Stream.of("extra")).toArray(String[]::new);
+            OpenType[] types = new OpenType[names.length];
+            for (int i=0; i < names.length; i++) {
+                String n = names[i];
+                types[i] = "extra".equals(n)
+                                ? SimpleType.STRING
+                                : MONITOR_INFO_COMPOSITE_TYPE.getType(n);
+            }
+
+            CompositeType compositeType =
+                new CompositeType("JDK X MonitorInfo",
+                    "CompositeType for JDK X MonitorInfo",
+                    names,
+                    names,
+                    types);
+
+            Object[] values = {
+                lockClassName,
+                lockIdentityHashCode,
+                Integer.valueOf(1),
+                makeStackTraceElement(),
+                "extra"
+            };
+
+            return new CompositeDataSupport(compositeType, names, values);
+        }
+
+        /*
+         * Create a CompositeData of ThreadInfo with a newer version of MonitorInfo
+         */
+        static CompositeData makeThreadInfoWithNewMonitorInfo() throws OpenDataException {
+            OpenType[] types = ITEM_TYPES.clone();
+            Object[] badValues = VALUES.clone();
+
+            CompositeData[] lockedMonitors = new CompositeData[1];
+            lockedMonitors[0] = makeNewMonitorInfo();
+            types[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType());
+            badValues[LOCKED_MONITORS] = lockedMonitors;
+            CompositeType ct = new CompositeType("CompositeType",
+                            "ThreadInfo with JDK 5 MonitorInfo",
+                            ITEM_NAMES,
+                            ITEM_NAMES,
+                            types);
+            return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
+        }
+
+        static CompositeData makeLockInfo() {
+            Object[] lockInfoValue = {
                 lockInfo.getClassName(),
                 lockInfo.getIdentityHashCode(),
             };
 
-            values[LOCK_INFO] =
-                new CompositeDataSupport(lockInfoCType,
-                                         lockInfoItemNames,
-                                         lockInfoValue);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+            try {
+                return new CompositeDataSupport(LOCK_INFO_COMPOSITE_TYPE,
+                    LOCK_INFO_ITEM_NAMES,
+                    lockInfoValue);
+            } catch (OpenDataException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        static CompositeData[] makeLockedSynchronizers() {
+            CompositeData[] lockedSyncs = new CompositeData[1];
+            lockedSyncs[0] = makeLockInfo();
+            return lockedSyncs;
+        }
+
+        static CompositeData[] makeLockedMonitors() {
+            CompositeData[] lockedMonitorsCD = new CompositeData[1];
+
+            Object[] lockedMonitorsValue = {
+                lockInfo.getClassName(),
+                lockInfo.getIdentityHashCode(),
+                makeStackTraceElement(),
+                Integer.valueOf(1),
+            };
+            try {
+                lockedMonitorsCD[0] =
+                    new CompositeDataSupport(MONITOR_INFO_COMPOSITE_TYPE,
+                        LOCKED_MONITORS_ITEM_NAMES,
+                        lockedMonitorsValue);
+            } catch (OpenDataException e) {
+                throw new RuntimeException(e);
+            }
+            return lockedMonitorsCD;
+        }
+
+        static final String[] V5_ITEM_NAMES = {
+            "threadId",
+            "threadName",
+            "threadState",
+            "blockedTime",
+            "blockedCount",
+            "waitedTime",
+            "waitedCount",
+            "lockName",
+            "lockOwnerId",
+            "lockOwnerName",
+            "stackTrace",
+            "suspended",
+            "inNative",
+        };
+
+        static final String[] V6_ITEM_NAMES = {
+            "lockInfo",
+            "lockedMonitors",
+            "lockedSynchronizers",
+        };
+
+        static final String[] V9_ITEM_NAMES = {
+            "daemon",
+            "priority",
+        };
+
+        static final OpenType[] V5_ITEM_TYPES = {
+            SimpleType.LONG,
+            SimpleType.STRING,
+            SimpleType.STRING,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.LONG,
+            SimpleType.STRING,
+            SimpleType.LONG,
+            SimpleType.STRING,
+            STE_ARRAY_COMPOSITE_TYPE,
+            SimpleType.BOOLEAN,
+            SimpleType.BOOLEAN,
+        };
+
+        static final OpenType[] V6_ITEM_TYPES = {
+            LOCK_INFO_COMPOSITE_TYPE,
+            MONITOR_INFO_ARRAY_COMPOSITE_TYPE,
+            LOCK_INFO_ARRAY_COMPOSITE_TYPE,
+        };
+
+        static final OpenType[] V9_ITEM_TYPES = {
+            SimpleType.BOOLEAN,
+            SimpleType.INTEGER,
+        };
+
+        static final String[] STE_ITEM_NAMES = {
+            "classLoaderName",
+            "moduleName",
+            "moduleVersion",
+            "className",
+            "methodName",
+            "fileName",
+            "lineNumber",
+            "nativeMethod",
+        };
+
+        static final String[] STE_V5_ITEM_NAMES = Arrays.copyOfRange(STE_ITEM_NAMES, 3, 8);
+
+        static final OpenType[] STE_V5_ITEM_TYPES = {
+            SimpleType.STRING,
+            SimpleType.STRING,
+            SimpleType.STRING,
+            SimpleType.INTEGER,
+            SimpleType.BOOLEAN
+        };
+
+        static final String[] LOCK_INFO_ITEM_NAMES = {
+            "className",
+            "identityHashCode",
+        };
+
+        static final String[] LOCKED_MONITORS_ITEM_NAMES = {
+            LOCK_INFO_ITEM_NAMES[0],
+            LOCK_INFO_ITEM_NAMES[1],
+            "lockedStackFrame",
+            "lockedStackDepth",
+        };
+
+        static final Object[] V5_VALUES = {
+            Long.valueOf(100),
+            "FooThread",
+            "RUNNABLE",
+            Long.valueOf(200),
+            Long.valueOf(10),
+            Long.valueOf(300),
+            Long.valueOf(20),
+            lockName,
+            Long.valueOf(99),
+            "BarThread",
+            new CompositeData[] { makeStackTraceElement() },
+            Boolean.valueOf(false),
+            Boolean.valueOf(false),
+        };
+
+        static final Object[] V6_VALUES = {
+            makeLockInfo(),
+            makeLockedMonitors(),
+            makeLockedSynchronizers(),
+        };
+
+        static final Object[] V9_VALUES = {
+            Boolean.valueOf(true),
+            Thread.NORM_PRIORITY,
+        };
+
+        static final String[] ITEM_NAMES =
+            concat(V5_ITEM_NAMES, V6_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new);
+
+        static final OpenType[] ITEM_TYPES =
+            concat(V5_ITEM_TYPES, V6_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new);
+
+        static final Object[] VALUES =
+            concat(V5_VALUES, V6_VALUES, V9_VALUES).toArray(Object[]::new);
+
+        static <T> Stream<T> concat(T[]... streams) {
+            return Stream.of(streams).flatMap(a -> Arrays.stream(a));
         }
     }
-
-    private static final String[] badItemNames = {
-        "threadId",
-        "threadName",
-        "threadState",
-        "blockedTime",
-        "blockedCount",
-        "waitedTime",
-        "waitedCount",
-        "lockName",
-        "lockOwnerId",
-        "lockOwnerName",
-        "BadStackTrace", // bad item name
-        "suspended",
-        "inNative",
-        "lockInfo",
-        "daemon",
-        "priority",
-    };
-    private static final OpenType[] badItemTypes = {
-        SimpleType.LONG,
-        SimpleType.STRING,
-        SimpleType.STRING,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.LONG,
-        SimpleType.STRING,
-        SimpleType.LONG,
-        SimpleType.STRING,
-        SimpleType.LONG,  // bad type
-        SimpleType.BOOLEAN,
-        SimpleType.BOOLEAN,
-        SimpleType.LONG,  // bad type
-        SimpleType.BOOLEAN,
-        SimpleType.INTEGER,
-    };
-
 }
--- a/test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java	Wed Feb 28 18:36:25 2018 -0500
+++ b/test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java	Wed Feb 28 17:11:57 2018 -0800
@@ -1,3 +1,25 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
 
 import java.util.HashMap;
 import java.util.Map;
@@ -6,6 +28,7 @@
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
+
 import sun.management.StackTraceElementCompositeData;
 
 import org.testng.annotations.*;
@@ -14,6 +37,7 @@
 /*
  * @test
  * @bug     8139587
+ * @modules java.management/sun.management
  * @summary Check backward compatibility of StackTraceElementCompositeData
  * @author  Jaroslav Bachorik
  *
@@ -22,21 +46,33 @@
 
 public class CompatibilityTest {
     private static CompositeType compositeTypeV6;
-    private static Map<String, Object> itemsV6;
-    private static CompositeData compositeDataV6;
+    private static CompositeType compositeType;
+
+    // Attribute names
+    private static final String CLASS_LOADER_NAME = "classLoaderName";
+    private static final String MODULE_NAME       = "moduleName";
+    private static final String MODULE_VERSION    = "moduleVersion";
+    private static final String CLASS_NAME        = "className";
+    private static final String METHOD_NAME       = "methodName";
+    private static final String FILE_NAME         = "fileName";
+    private static final String LINE_NUMBER       = "lineNumber";
+    private static final String NATIVE_METHOD     = "nativeMethod";
 
     @BeforeClass
     public static void setup() throws Exception {
+        String[] v6Names = {
+            CLASS_NAME, METHOD_NAME, FILE_NAME, NATIVE_METHOD, LINE_NUMBER
+        };
+        String[] names = {
+            CLASS_LOADER_NAME, MODULE_NAME, MODULE_VERSION,
+            CLASS_NAME, METHOD_NAME, FILE_NAME, NATIVE_METHOD, LINE_NUMBER
+        };
         compositeTypeV6 = new CompositeType(
             StackTraceElement.class.getName(),
             "StackTraceElement",
-            new String[]{
-                "className", "methodName", "fileName", "nativeMethod", "lineNumber"
-            },
-            new String[]{
-                "className", "methodName", "fileName", "nativeMethod", "lineNumber"
-            },
-            new OpenType[]{
+            v6Names,
+            v6Names,
+            new OpenType[] {
                 SimpleType.STRING,
                 SimpleType.STRING,
                 SimpleType.STRING,
@@ -44,20 +80,52 @@
                 SimpleType.INTEGER
             }
         );
+        compositeType = new CompositeType(
+            StackTraceElement.class.getName(),
+            "StackTraceElement",
+            names,
+            names,
+            new OpenType[] {
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.STRING,
+                SimpleType.BOOLEAN,
+                SimpleType.INTEGER
+            }
+        );
+    }
 
-        itemsV6 = new HashMap<>();
-        itemsV6.put("className", "MyClass");
-        itemsV6.put("methodName", "myMethod");
-        itemsV6.put("fileName", "MyClass.java");
-        itemsV6.put("nativeMethod", false);
-        itemsV6.put("lineNumber", 123);
+    private static CompositeData makeCompositeDataV6() throws Exception {
+        Map<String, Object> itemsV6 = new HashMap<>();
+        itemsV6.put(CLASS_NAME, "MyClass");
+        itemsV6.put(METHOD_NAME, "myMethod");
+        itemsV6.put(FILE_NAME, "MyClass.java");
+        itemsV6.put(NATIVE_METHOD, false);
+        itemsV6.put(LINE_NUMBER, 123);
+
+        return new CompositeDataSupport(compositeTypeV6, itemsV6);
+    }
 
-        compositeDataV6 = new CompositeDataSupport(compositeTypeV6, itemsV6);
+    private static CompositeData makeCompositeData() throws Exception {
+        Map<String, Object> items = new HashMap<>();
+        items.put(CLASS_LOADER_NAME, "app");
+        items.put(MODULE_NAME, "m");
+        items.put(MODULE_VERSION, "1.0");
+        items.put(CLASS_NAME, "MyClass");
+        items.put(METHOD_NAME, "myMethod");
+        items.put(FILE_NAME, "MyClass.java");
+        items.put(NATIVE_METHOD, false);
+        items.put(LINE_NUMBER, 123);
+
+        return new CompositeDataSupport(compositeType, items);
     }
 
     @Test
     public void testV6Compatibility() throws Exception {
-        StackTraceElement ste = StackTraceElementCompositeData.from(compositeDataV6);
+        StackTraceElement ste = StackTraceElementCompositeData.from(makeCompositeDataV6());
 
         assertNotNull(ste);
         assertEquals(ste.getClassName(), "MyClass");
@@ -69,5 +137,22 @@
         assertNull(ste.getModuleName());
         assertNull(ste.getModuleVersion());
     }
+
+    @Test
+    public void test() throws Exception {
+        StackTraceElement ste = StackTraceElementCompositeData.from(makeCompositeData());
+
+        assertNotNull(ste);
+
+        assertEquals(ste.getModuleName(), "m");
+        assertEquals(ste.getModuleVersion(), "1.0");
+        assertEquals(ste.getClassLoaderName(), "app");
+
+        assertEquals(ste.getClassName(), "MyClass");
+        assertEquals(ste.getMethodName(), "myMethod");
+        assertEquals(ste.getFileName(), "MyClass.java");
+        assertEquals(ste.isNativeMethod(), false);
+        assertEquals(ste.getLineNumber(), 123);
+    }
 }