1 /* 2 * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @summary Test of diagnostic command VM.class_hierarchy 27 * @library /test/lib 28 * @modules java.base/jdk.internal.misc 29 * java.compiler 30 * java.management 31 * jdk.internal.jvmstat/sun.jvmstat.monitor 32 * @compile -XDnoTopInterfaceInjection ClassHierarchyTest.java 33 * @run testng ClassHierarchyTest 34 */ 35 36 import org.testng.annotations.Test; 37 import org.testng.Assert; 38 39 import jdk.test.lib.process.OutputAnalyzer; 40 import jdk.test.lib.dcmd.CommandExecutor; 41 import jdk.test.lib.dcmd.JMXExecutor; 42 43 import java.io.File; 44 import java.io.FileInputStream; 45 import java.io.IOException; 46 import java.nio.ByteBuffer; 47 import java.nio.channels.FileChannel; 48 import java.util.Iterator; 49 import java.util.regex.Matcher; 50 import java.util.regex.Pattern; 51 52 public class ClassHierarchyTest { 53 54 // $> jcmd DcmdTestClass VM.class_hierarchy DcmdTestClass | grep DcmdTestClass\$\$Lambda 55 // |--DcmdTestClass$$Lambda$1/4081552/0xa529fbb0 56 57 // > VM.class_hierarchy DcmdBaseClass 58 // java.lang.Object/null 59 // |--DcmdBaseClass/0xa4abcd48 60 61 // > VM.class_hierarchy DcmdBaseClass -s 62 // java.lang.Object/null 63 // |--DcmdBaseClass/0xa4abcd48 64 // | |--DcmdTestClass/0xa4abcd48 65 66 // > VM.class_hierarchy DcmdBaseClass -i -s 67 // java.lang.Object/null 68 // |--DcmdBaseClass/0xa4abcd48 69 // | implements Intf2/0xa4abcd48 (declared intf) 70 // | implements java.lang.IdentityObject/null (declared intf) 71 // | implements Intf1/0xa4abcd48 (inherited intf) 72 // | |--DcmdTestClass/0xa4abcd48 73 // | | implements Intf1/0xa4abcd48 (inherited intf) 74 // | | implements Intf2/0xa4abcd48 (inherited intf) 75 // | | implements java.lang.IdentityObject/null (inherited intf) 76 77 static Pattern expected_lambda_line = 78 Pattern.compile("\\|--DcmdTestClass\\$\\$Lambda.*"); 79 80 static Pattern expected_lines[] = { 81 Pattern.compile("java.lang.Object/null"), 82 Pattern.compile("\\|--DcmdBaseClass/0x(\\p{XDigit}*)"), 83 Pattern.compile("\\| implements Intf2/0x(\\p{XDigit}*) \\(declared intf\\)"), 84 Pattern.compile("\\| implements java.lang.IdentityObject/null \\(declared intf\\)"), 85 Pattern.compile("\\| implements Intf1/0x(\\p{XDigit}*) \\(inherited intf\\)"), 86 Pattern.compile("\\| \\|--DcmdTestClass/0x(\\p{XDigit}*)"), 87 Pattern.compile("\\| \\| implements Intf1/0x(\\p{XDigit}*) \\(inherited intf\\)"), 88 Pattern.compile("\\| \\| implements Intf2/0x(\\p{XDigit}*) \\(inherited intf\\)"), 89 Pattern.compile("\\| \\| implements java.lang.IdentityObject/null \\(inherited intf\\)") 90 }; 91 92 public void run(CommandExecutor executor) throws ClassNotFoundException { 93 OutputAnalyzer output; 94 Iterator<String> lines; 95 int i; 96 97 // Load our test class whose hierarchy we will print. 98 Class<?> c = Class.forName("DcmdTestClass"); 99 100 // Verify the presence of the lamba anonymous class 101 output = executor.execute("VM.class_hierarchy"); 102 lines = output.asLines().iterator(); 103 Boolean foundMatch = false; 104 while (lines.hasNext()) { 105 String line = lines.next(); 106 Matcher m = expected_lambda_line.matcher(line); 107 if (m.matches()) { 108 foundMatch = true; 109 break; 110 } 111 } 112 if (!foundMatch) { 113 Assert.fail("Failed to find lamda class"); 114 } 115 116 // Verify the output for the simple hierachry of just DcmdBaseClass. 117 output = executor.execute("VM.class_hierarchy DcmdBaseClass"); 118 lines = output.asLines().iterator(); 119 i = 0; 120 while (lines.hasNext()) { 121 String line = lines.next(); 122 Matcher m = expected_lines[i].matcher(line); 123 i++; 124 if (!m.matches()) { 125 Assert.fail("Failed to match line #" + i + ": " + line); 126 } 127 // Should only be two lines of output in this form. 128 if (i == 2) break; 129 } 130 if (lines.hasNext()) { 131 String line = lines.next(); 132 Assert.fail("Unexpected dcmd output: " + line); 133 } 134 135 // Verify the output for the full hierarchy of DcmdBaseClass, but without interfaces. 136 output = executor.execute("VM.class_hierarchy DcmdBaseClass -s"); 137 lines = output.asLines().iterator(); 138 i = 0; 139 while (lines.hasNext()) { 140 String line = lines.next(); 141 Matcher m = expected_lines[i].matcher(line); 142 i++; 143 if (!m.matches()) { 144 Assert.fail("Failed to match line #" + i + ": " + line); 145 } 146 // "implements" lines should not be in this output. 147 if (i == 2 || i == 6) i += 3; 148 } 149 if (lines.hasNext()) { 150 String line = lines.next(); 151 Assert.fail("Unexpected dcmd output: " + line); 152 } 153 154 // Verify the output for the full hierarchy of DcmdBaseClass, including interfaces. 155 output = executor.execute("VM.class_hierarchy DcmdBaseClass -i -s"); 156 lines = output.asLines().iterator(); 157 i = 0; 158 String classLoaderAddr = null; 159 while (lines.hasNext()) { 160 String line = lines.next(); 161 Matcher m = expected_lines[i].matcher(line); 162 i++; 163 if (!m.matches()) { 164 Assert.fail("Failed to match line #" + i + ": " + line); 165 } 166 if (i == 2) { 167 // Fetch the ClassLoader address, which should be the same in 168 // subsequent lines. 169 classLoaderAddr = m.group(1); 170 System.out.println(classLoaderAddr); 171 } else if (i > 2 && i != 4 && i != 9) { 172 if (!classLoaderAddr.equals(m.group(1))) { 173 Assert.fail("Classloader address didn't match on line #" 174 + i + ": " + line); 175 } 176 } 177 if (i == expected_lines.length) break; 178 } 179 if (lines.hasNext()) { 180 String line = lines.next(); 181 Assert.fail("Unexpected dcmd output: " + line); 182 } 183 } 184 185 @Test 186 public void jmx() throws ClassNotFoundException { 187 run(new JMXExecutor()); 188 } 189 } 190 191 interface Intf1 { 192 } 193 194 interface Intf2 extends Intf1 { 195 } 196 197 class DcmdBaseClass implements Intf2 { 198 } 199 200 class DcmdTestClass extends DcmdBaseClass { 201 static { 202 // Force creation of anonymous class (for the lambdaform). 203 Runnable r = () -> System.out.println("Hello"); 204 r.run(); 205 } 206 }