/* * 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 * * @build ClassHierarchyTest DcmdUtil * @run main ClassHierarchyTest */ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.StringReader; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; 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 lambdaLine = Pattern.compile("\\|--DcmdTestClass\\$\\$Lambda.*"); static Pattern 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 static void main(String arg[]) throws Exception { String result; BufferedReader r; int i; String line; // Load our test class whose hierarchy we will print. Class c = Class.forName("DcmdTestClass"); // Verify the presence of the lamba anonymous class result = DcmdUtil.executeDcmd("VM.class_hierarchy"); r = new BufferedReader(new StringReader(result)); Boolean foundMatch = false; while ((line = r.readLine()) != null) { Matcher m = lambdaLine.matcher(line); if (m.matches()) { foundMatch = true; break; } } if (!foundMatch) { throw new Exception("Failed to find lamda class"); } // Verify the output for the simple hierachry of just DcmdBaseClass. result = DcmdUtil.executeDcmd("VM.class_hierarchy", "DcmdBaseClass"); r = new BufferedReader(new StringReader(result)); i = 0; while ((line = r.readLine()) != null) { Matcher m = lines[i].matcher(line); i++; if (!m.matches()) { throw new Exception("Failed to match line #" + i + ": " + line); } // Should only be two lines of output in this form. if (i == 2) break; } if ((line = r.readLine()) != null) { throw new Exception("Unexpected dcmd output: " + line); } // Verify the output for the full hierarchy of DcmdBaseClass, but without interfaces. result = DcmdUtil.executeDcmd("VM.class_hierarchy", "DcmdBaseClass -s"); r = new BufferedReader(new StringReader(result)); i = 0; while ((line = r.readLine()) != null) { Matcher m = lines[i].matcher(line); i++; if (!m.matches()) { throw new Exception("Failed to match line #" + i + ": " + line); } // "implements" lines should not be in this output. if (i == 2 || i == 4) i += 2; } if ((line = r.readLine()) != null) { throw new Exception("Unexpected dcmd output: " + line); } // Verify the output for the full hierarchy of DcmdBaseClass, including interfaces. result = DcmdUtil.executeDcmd("VM.class_hierarchy", "DcmdBaseClass -i -s"); r = new BufferedReader(new StringReader(result)); i = 0; String classLoaderAddr = null; while ((line = r.readLine()) != null) { Matcher m = lines[i].matcher(line); i++; if (!m.matches()) { throw new Exception("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))) { throw new Exception("Classloader address didn't match on line #" + i + ": " + line); } } if (i == lines.length) break; } if ((line = r.readLine()) != null) { throw new Exception("Unexpected dcmd output: " + line); } } } 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(); } }