1/*
2 * Copyright (c) 2013, 2016, 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 * @bug 8023668
27 * @summary Desugar serializable lambda bodies using more robust naming scheme
28 * @library /tools/lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.main
31 *          jdk.jdeps/com.sun.tools.javap
32 * @build toolbox.ToolBox toolbox.JavacTask
33 * @run main TestSerializedLambdaNameStability
34 */
35
36import java.io.*;
37import java.lang.reflect.Constructor;
38import java.lang.reflect.InvocationTargetException;
39import java.lang.reflect.Method;
40import java.nio.file.*;
41
42import toolbox.JavacTask;
43import toolbox.ToolBox;
44
45public class TestSerializedLambdaNameStability {
46
47    final ClassLoader writingClassLoader;
48    final ClassLoader clonedClassLoader;
49    final ClassLoader checkingClassLoader;
50
51    TestSerializedLambdaNameStability()  {
52        writingClassLoader = new TestClassLoader("before");
53        clonedClassLoader = new TestClassLoader("before");
54        checkingClassLoader = new TestClassLoader("after");
55    }
56
57    public static void main(String... args) throws Exception {
58        new TestSerializedLambdaNameStability().doit("NameOfCapturedArgs", true);
59        new TestSerializedLambdaNameStability().doit("TypesOfCapturedArgs", true);
60        new TestSerializedLambdaNameStability().doit("OrderOfCapturedArgs", true);
61        new TestSerializedLambdaNameStability().doit("VariableAssignmentTarget", false);
62        new TestSerializedLambdaNameStability().doit("TargetName", true);
63        new TestSerializedLambdaNameStability().doit("TargetType", true);
64    }
65
66    public void doit(String name, boolean expectFail) throws Exception {
67        String iName = "I" + name;
68        String testName = "TEST" + name;
69        Class<?> kw = writingClassLoader.loadClass(testName);
70        Object instw = getInstance(kw);
71        Method mw = getMethod(kw, "write", ObjectOutput.class);
72        ByteArrayOutputStream baos = new ByteArrayOutputStream();
73        try (ObjectOutput out = new ObjectOutputStream(baos)) {
74            mw.invoke(instw, out);
75        }
76        byte[] ser = baos.toByteArray();
77
78        // Read and check clone
79        readCheck(iName, testName, clonedClassLoader, ser);
80        System.err.printf("cloned test readCheck %s\n", testName);
81
82        // Read and check other
83        if (expectFail) {
84            try {
85                readCheck(iName, testName, checkingClassLoader, ser);
86            } catch (InvocationTargetException ite) {
87                Throwable underlying = ite;
88                while (underlying != null && !(underlying instanceof IllegalArgumentException)) {
89                    underlying = underlying.getCause();
90                }
91                if (underlying != null) {
92                    if (underlying.getMessage().contains("deserialization")) {
93                        System.err.printf("PASS: other test %s got expected exception %s\n", testName, underlying);
94                        return;
95                    }
96                }
97                System.err.printf("FAIL: other test %s got unexpected exception %s\n", testName, ite);
98                throw new Exception("unexpected exception ", ite);
99            }
100            System.err.printf("FAIL: other test %s expected an exception", testName);
101            throw new Exception("expected an exception" + testName);
102        } else {
103            readCheck(iName, testName, checkingClassLoader, ser);
104            System.err.printf("PASS: other test %s readCheck\n", testName);
105        }
106    }
107
108    void readCheck(String iName, String testName, ClassLoader loader, byte[] ser) throws Exception {
109        Class<?> k = loader.loadClass(testName);
110        Object inst = getInstance(k);
111        Method mrc = getMethod(k, "readCheck", ObjectInput.class);
112        ByteArrayInputStream bais = new ByteArrayInputStream(ser);
113        try (ObjectInput in = new ObjectInputStream(bais)) {
114            mrc.invoke(inst, in);
115        }
116    }
117
118    Method getMethod(Class<?> k, String name, Class<?> argTypes) throws Exception {
119        Method meth = k.getDeclaredMethod(name, argTypes);
120        meth.setAccessible(true);
121        return meth;
122    }
123
124    Object getInstance(Class<?> k) throws Exception {
125        Constructor<?> cons = k.getConstructors()[0];
126        cons.setAccessible(true);
127        return cons.newInstance();
128    }
129
130    static class TestClassLoader extends ClassLoader  {
131        static final String compiledDir = System.getProperty("user.dir");
132        static final String sourceBaseDir = System.getProperty("test.src");
133
134        final ToolBox tb = new ToolBox();
135        final String context;
136
137        public TestClassLoader(String context) {
138            super();
139            this.context = context;
140        }
141
142        @Override
143        public Class findClass(String name) throws ClassNotFoundException {
144            byte[] b;
145
146            try {
147                b = loadClassData(name);
148            } catch (Throwable th) {
149                // th.printStackTrace();
150                throw new ClassNotFoundException("Loading error", th);
151            }
152            return defineClass(name, b, 0, b.length);
153        }
154
155        private byte[] loadClassData(String name) throws Exception {
156            String srcName;
157            if (name.startsWith("TEST"))
158                srcName = name;
159            else if (name.startsWith("I"))
160                srcName = "TEST" + name.substring(1);
161            else
162                throw new Exception("Did not expect to load " + name);
163            Path srcFile = Paths.get(sourceBaseDir, context, srcName + ".java");
164            new JavacTask(tb)
165                    .outdir(compiledDir)
166                    .files(srcFile)
167                    .run();
168            Path cfFile = Paths.get(compiledDir, name + ".class");
169            byte[] bytes = Files.readAllBytes(cfFile);
170            return bytes;
171        }
172    }
173}
174