Path: blob/master/test/jdk/java/lang/StackTraceElement/SerialTest.java
41149 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 647923726* @summary Test the format of StackTraceElement::toString and its serial form27* @modules java.logging28*29* @run main SerialTest30*/3132import java.io.BufferedInputStream;33import java.io.BufferedOutputStream;34import java.io.IOException;35import java.io.InputStream;36import java.io.ObjectInputStream;37import java.io.ObjectOutputStream;38import java.io.OutputStream;39import java.io.UncheckedIOException;40import java.lang.reflect.Method;41import java.net.MalformedURLException;42import java.net.URL;43import java.net.URLClassLoader;44import java.nio.file.Files;45import java.nio.file.Path;46import java.nio.file.Paths;47import java.util.Arrays;48import java.util.logging.Logger;4950public class SerialTest {51private static final Path SER_DIR = Paths.get("sers");52private static final String JAVA_BASE = "java.base";53private static final String JAVA_LOGGING = "java.logging";5455private static boolean isImage;5657public static void main(String... args) throws Exception {58Files.createDirectories(SER_DIR);5960// detect if exploded image build61Path home = Paths.get(System.getProperty("java.home"));62isImage = Files.exists(home.resolve("lib").resolve("modules"));6364// test stack trace from built-in loaders65try {66Logger.getLogger(null);67} catch (NullPointerException e) {68Arrays.stream(e.getStackTrace())69.filter(ste -> ste.getClassName().startsWith("java.util.logging.") ||70ste.getClassName().equals("SerialTest"))71.forEach(SerialTest::test);72}7374// test stack trace with class loader name from other class loader75Loader loader = new Loader("myloader");76Class<?> cls = Class.forName("SerialTest", true, loader);77Method method = cls.getMethod("throwException");78StackTraceElement ste = (StackTraceElement)method.invoke(null);79test(ste, loader);8081// verify the class loader name and in the stack trace82if (!cls.getClassLoader().getName().equals("myloader.hacked")) {83throw new RuntimeException("Unexpected loader name: " +84cls.getClassLoader().getName());85}86if (!ste.getClassLoaderName().equals("myloader")) {87throw new RuntimeException("Unexpected loader name: " +88ste.getClassLoaderName());89}90}9192private static void test(StackTraceElement ste) {93test(ste, null);94}9596private static void test(StackTraceElement ste, ClassLoader loader) {97try {98SerialTest serialTest = new SerialTest(ste);99StackTraceElement ste2 = serialTest.serialize().deserialize();100System.out.println(ste2);101// verify StackTraceElement::toString returns the same string102if (!ste.equals(ste2) || !ste.toString().equals(ste2.toString())) {103throw new RuntimeException(ste + " != " + ste2);104}105106String mn = ste.getModuleName();107if (mn != null) {108switch (mn) {109case JAVA_BASE:110case JAVA_LOGGING:111checkNamedModule(ste, loader, false);112break;113default: // ignore114}115} else {116checkUnnamedModule(ste, loader);117}118} catch (IOException e) {119throw new UncheckedIOException(e);120}121}122123private static void checkUnnamedModule(StackTraceElement ste, ClassLoader loader) {124String mn = ste.getModuleName();125String s = ste.toString();126int i = s.indexOf('/');127128if (mn != null) {129throw new RuntimeException("expected null but got " + mn);130}131132if (loader != null) {133// Expect <loader>//<classname>.<method>(<src>:<ln>)134if (i <= 0) {135throw new RuntimeException("loader name missing: " + s);136}137if (!getLoaderName(loader).equals(s.substring(0, i))) {138throw new RuntimeException("unexpected loader name: " + s);139}140int j = s.substring(i+1).indexOf('/');141if (j != 0) {142throw new RuntimeException("unexpected element for unnamed module: " + s);143}144}145}146147/*148* Loader::getName is overridden to return some other name149*/150private static String getLoaderName(ClassLoader loader) {151if (loader == null)152return "";153154if (loader instanceof Loader) {155return ((Loader) loader).name;156} else {157return loader.getName();158}159}160161private static void checkNamedModule(StackTraceElement ste,162ClassLoader loader,163boolean showVersion) {164String loaderName = getLoaderName(loader);165String mn = ste.getModuleName();166String s = ste.toString();167int i = s.indexOf('/');168169if (mn == null) {170throw new RuntimeException("expected module name: " + s);171}172173if (i <= 0) {174throw new RuntimeException("module name missing: " + s);175}176177// Expect <module>/<classname>.<method>(<src>:<ln>)178if (!loaderName.isEmpty()) {179throw new IllegalArgumentException(loaderName);180}181182// <module>: name@version183int j = s.indexOf('@');184if ((showVersion && j <= 0) || (!showVersion && j >= 0)) {185throw new RuntimeException("unexpected version: " + s);186}187188String name = j < 0 ? s.substring(0, i) : s.substring(0, j);189if (!name.equals(mn)) {190throw new RuntimeException("unexpected module name: " + s);191}192}193194private final Path ser;195private final StackTraceElement ste;196SerialTest(StackTraceElement ste) throws IOException {197this.ser = Files.createTempFile(SER_DIR, "SerialTest", ".ser");198this.ste = ste;199}200201private StackTraceElement deserialize() throws IOException {202try (InputStream in = Files.newInputStream(ser);203BufferedInputStream bis = new BufferedInputStream(in);204ObjectInputStream ois = new ObjectInputStream(bis)) {205return (StackTraceElement)ois.readObject();206} catch (ClassNotFoundException e) {207throw new RuntimeException(e);208}209}210211private SerialTest serialize() throws IOException {212try (OutputStream out = Files.newOutputStream(ser);213BufferedOutputStream bos = new BufferedOutputStream(out);214ObjectOutputStream oos = new ObjectOutputStream(bos)) {215oos.writeObject(ste);216}217return this;218}219220221public static StackTraceElement throwException() {222try {223Integer.parseInt(null);224} catch (NumberFormatException e) {225return Arrays.stream(e.getStackTrace())226.filter(ste -> ste.getMethodName().equals("throwException"))227.findFirst().get();228}229return null;230}231232public static class Loader extends URLClassLoader {233final String name;234Loader(String name) throws MalformedURLException {235super(name, new URL[] { testClassesURL() } , null);236this.name = name;237}238239private static URL testClassesURL() throws MalformedURLException {240Path path = Paths.get(System.getProperty("test.classes"));241return path.toUri().toURL();242}243244public String getName() {245return name + ".hacked";246}247}248}249250251