LambdaClassLoaderSerialization.java revision 9783:3b50efed107a
1/*
2 * Copyright (c) 2013, 2014, 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 8004970
27 * @summary Lambda serialization in the presence of class loaders
28 * @library /lib/testlibrary
29 * @build jdk.testlibrary.IOUtils
30 * @run main LambdaClassLoaderSerialization
31 * @author Peter Levart
32 */
33
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36import java.io.IOException;
37import java.io.InputStream;
38import java.io.ObjectInputStream;
39import java.io.ObjectOutputStream;
40import java.io.Serializable;
41import java.util.Arrays;
42
43import jdk.testlibrary.IOUtils;
44
45public class LambdaClassLoaderSerialization {
46
47    public interface SerializableRunnable extends Runnable, Serializable {}
48
49    public static class MyCode implements SerializableRunnable {
50
51        private byte[] serialize(Object o) {
52            ByteArrayOutputStream baos;
53            try (
54                ObjectOutputStream oos =
55                    new ObjectOutputStream(baos = new ByteArrayOutputStream())
56            ) {
57                oos.writeObject(o);
58            }
59            catch (IOException e) {
60                throw new RuntimeException(e);
61            }
62            return baos.toByteArray();
63        }
64
65        private <T> T deserialize(byte[] bytes) {
66            try (
67                ObjectInputStream ois =
68                    new ObjectInputStream(new ByteArrayInputStream(bytes))
69            ) {
70                return (T) ois.readObject();
71            }
72            catch (IOException | ClassNotFoundException e) {
73                throw new RuntimeException(e);
74            }
75        }
76
77        @Override
78        public void run() {
79            System.out.println("                this: " + this);
80
81            SerializableRunnable deSerializedThis = deserialize(serialize(this));
82            System.out.println("    deSerializedThis: " + deSerializedThis);
83
84            SerializableRunnable runnable = () -> {System.out.println("HELLO");};
85            System.out.println("            runnable: " + runnable);
86
87            SerializableRunnable deSerializedRunnable = deserialize(serialize(runnable));
88            System.out.println("deSerializedRunnable: " + deSerializedRunnable);
89        }
90    }
91
92    public static void main(String[] args) throws Exception {
93        ClassLoader myCl = new MyClassLoader(
94            LambdaClassLoaderSerialization.class.getClassLoader()
95        );
96        Class<?> myCodeClass = Class.forName(
97            LambdaClassLoaderSerialization.class.getName() + "$MyCode",
98            true,
99            myCl
100        );
101        Runnable myCode = (Runnable) myCodeClass.newInstance();
102        myCode.run();
103    }
104
105    static class MyClassLoader extends ClassLoader {
106        MyClassLoader(ClassLoader parent) {
107            super(parent);
108        }
109
110        @Override
111        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
112            if (name.indexOf('.') < 0) {
113                synchronized (getClassLoadingLock(name)) {
114                    Class<?> c = findLoadedClass(name);
115                    if (c == null) {
116                        c = findClass(name);
117                    }
118                    if (resolve) {
119                        resolveClass(c);
120                    }
121                    return c;
122                }
123            } else {
124                return super.loadClass(name, resolve);
125            }
126        }
127
128        @Override
129        protected Class<?> findClass(String name) throws ClassNotFoundException {
130            String path = name.replace('.', '/').concat(".class");
131            try (InputStream is = getResourceAsStream(path)) {
132                if (is != null) {
133                    byte[] bytes = IOUtils.readFully(is);
134                    return defineClass(name, bytes, 0, bytes.length);
135                } else {
136                    throw new ClassNotFoundException(name);
137                }
138            }
139            catch (IOException e) {
140                throw new ClassNotFoundException(name, e);
141            }
142        }
143    }
144}
145