/* * 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. * * 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. */ /* * @test * @summary Test of diagnostic command VM.class_hierarchy * @library /test/lib * @modules java.base/jdk.internal.misc * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor * @run testng ClassHierarchyTest */ import org.testng.annotations.Test; import org.testng.Assert; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ClassHierarchyTest { // $> jcmd DcmdTestClass VM.class_hierarchy DcmdTestClass | grep DcmdTestClass\$\$Lambda // |--DcmdTestClass$$Lambda$1/4081552/0xa529fbb0 // > VM.class_hierarchy DcmdBaseClass // java.lang.Object/null // |--DcmdBaseClass/0xa4abcd48 // > VM.class_hierarchy DcmdBaseClass -s // java.lang.Object/null // |--DcmdBaseClass/0xa4abcd48 // | |--DcmdTestClass/0xa4abcd48 // > VM.class_hierarchy DcmdBaseClass -i -s // java.lang.Object/null // |--DcmdBaseClass/0xa4abcd48 // | implements Intf2/0xa4abcd48 (declared intf) // | implements Intf1/0xa4abcd48 (inherited intf) // | |--DcmdTestClass/0xa4abcd48 // | | implements Intf1/0xa4abcd48 (inherited intf) // | | implements Intf2/0xa4abcd48 (inherited intf) static Pattern expected_lambda_line = Pattern.compile("\\|--DcmdTestClass\\$\\$Lambda.*"); static Pattern expected_lines[] = { Pattern.compile("java.lang.Object/null"), Pattern.compile("\\|--DcmdBaseClass/0x(\\p{XDigit}*)"), Pattern.compile("\\| implements Intf2/0x(\\p{XDigit}*) \\(declared intf\\)"), Pattern.compile("\\| implements Intf1/0x(\\p{XDigit}*) \\(inherited intf\\)"), Pattern.compile("\\| \\|--DcmdTestClass/0x(\\p{XDigit}*)"), Pattern.compile("\\| \\| implements Intf1/0x(\\p{XDigit}*) \\(inherited intf\\)"), Pattern.compile("\\| \\| implements Intf2/0x(\\p{XDigit}*) \\(inherited intf\\)") }; public void run(CommandExecutor executor) throws ClassNotFoundException { OutputAnalyzer output; Iterator lines; int i; // Load our test class whose hierarchy we will print. Class c = Class.forName("DcmdTestClass"); // Verify the presence of the lamba anonymous class output = executor.execute("VM.class_hierarchy"); lines = output.asLines().iterator(); Boolean foundMatch = false; while (lines.hasNext()) { String line = lines.next(); Matcher m = expected_lambda_line.matcher(line); if (m.matches()) { foundMatch = true; break; } } if (!foundMatch) { Assert.fail("Failed to find lamda class"); } // Verify the output for the simple hierachry of just DcmdBaseClass. output = executor.execute("VM.class_hierarchy DcmdBaseClass"); lines = output.asLines().iterator(); i = 0; while (lines.hasNext()) { String line = lines.next(); Matcher m = expected_lines[i].matcher(line); i++; if (!m.matches()) { Assert.fail("Failed to match line #" + i + ": " + line); } // Should only be two lines of output in this form. if (i == 2) break; } if (lines.hasNext()) { String line = lines.next(); Assert.fail("Unexpected dcmd output: " + line); } // Verify the output for the full hierarchy of DcmdBaseClass, but without interfaces. output = executor.execute("VM.class_hierarchy DcmdBaseClass -s"); lines = output.asLines().iterator(); i = 0; while (lines.hasNext()) { String line = lines.next(); Matcher m = expected_lines[i].matcher(line); i++; if (!m.matches()) { Assert.fail("Failed to match line #" + i + ": " + line); } // "implements" lines should not be in this output. if (i == 2 || i == 4) i += 2; } if (lines.hasNext()) { String line = lines.next(); Assert.fail("Unexpected dcmd output: " + line); } // Verify the output for the full hierarchy of DcmdBaseClass, including interfaces. output = executor.execute("VM.class_hierarchy DcmdBaseClass -i -s"); lines = output.asLines().iterator(); i = 0; String classLoaderAddr = null; while (lines.hasNext()) { String line = lines.next(); Matcher m = expected_lines[i].matcher(line); i++; if (!m.matches()) { Assert.fail("Failed to match line #" + i + ": " + line); } if (i == 2) { // Fetch the ClassLoader address, which should be the same in // subsequent lines. classLoaderAddr = m.group(1); System.out.println(classLoaderAddr); } else if (i > 2) { if (!classLoaderAddr.equals(m.group(1))) { Assert.fail("Classloader address didn't match on line #" + i + ": " + line); } } if (i == expected_lines.length) break; } if (lines.hasNext()) { String line = lines.next(); Assert.fail("Unexpected dcmd output: " + line); } } @Test public void jmx() throws ClassNotFoundException { run(new JMXExecutor()); } } interface Intf1 { } interface Intf2 extends Intf1 { } class DcmdBaseClass implements Intf2 { } class DcmdTestClass extends DcmdBaseClass { static { // Force creation of anonymous class (for the lambdaform). Runnable r = () -> System.out.println("Hello"); r.run(); } }