blob: fdbd689ad362b39008cb9a585e54c43ee95dad59 [file] [log] [blame]
/*
* Copyright (c) 2012, 2013, 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.
*/
package org.openjdk.tests.java.lang.invoke;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.testng.annotations.Test;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* SerializedLambdaTest
*
* @author Brian Goetz
*/
@Test
public class SerializedLambdaTest {
public static final int REPS = 50;
@SuppressWarnings("unchecked")
private<T> void assertSerial(T p, Consumer<T> asserter) throws IOException, ClassNotFoundException {
asserter.accept(p);
for (int i=0; i<REPS; i++) {
byte[] bytes = serialize(p);
assertTrue(bytes.length > 0);
asserter.accept((T) deserialize(bytes));
}
}
private void assertNotSerial(Predicate<String> p, Consumer<Predicate<String>> asserter)
throws IOException, ClassNotFoundException {
asserter.accept(p);
try {
byte[] bytes = serialize(p);
fail("Expected serialization failure");
}
catch (NotSerializableException e) {
// success
}
}
private byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.close();
return bos.toByteArray();
}
private Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
try(ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
return ois.readObject();
}
}
// Test instantiating against intersection type
public void testSimpleSerializedInstantiation() throws IOException, ClassNotFoundException {
@SuppressWarnings("unchecked")
Predicate<String> pred = (Predicate<String> & Serializable) s -> true;
assertSerial(pred,
p -> {
assertTrue(p instanceof Predicate);
assertTrue(p instanceof Serializable);
assertTrue(p.test(""));
});
}
interface SerPredicate<T> extends Predicate<T>, Serializable { }
// Test instantiating against derived type
public void testSimpleSerializedInstantiation2() throws IOException, ClassNotFoundException {
SerPredicate<String> serPred = (SerPredicate<String>) s -> true;
assertSerial(serPred,
p -> {
assertTrue(p instanceof Predicate);
assertTrue(p instanceof Serializable);
assertTrue(p instanceof SerPredicate);
assertTrue(p.test(""));
});
}
// Negative test: non-serializable lambdas are in fact not serializable
public void testNonserializableInstantiation() throws IOException, ClassNotFoundException {
@SuppressWarnings("unchecked")
Predicate<String> pred = (Predicate<String>) s -> true;
assertNotSerial(pred,
p -> {
assertTrue(p instanceof Predicate);
assertFalse(p instanceof Serializable);
assertTrue(p.test(""));
});
}
// Test lambda capturing int
public void testSerializeCapturingInt() throws IOException, ClassNotFoundException {
class Moo {
@SuppressWarnings("unchecked")
Predicate<String> foo(int x) {
return (Predicate<String> & Serializable) s -> s.length() >= x;
}
}
Predicate<String> pred = new Moo().foo(3);
assertSerial(pred, p -> {
assertTrue(p.test("yada"));
assertFalse(p.test("no"));
});
}
// Test lambda capturing String
public void testSerializeCapturingString() throws IOException, ClassNotFoundException {
class Moo {
@SuppressWarnings("unchecked")
Predicate<String> foo(String t) {
return (Predicate<String> & Serializable) s -> s.equals(t);
}
}
Predicate<String> pred = new Moo().foo("goo");
assertSerial(pred, p -> {
assertTrue(p.test("goo"));
assertFalse(p.test("foo"));
});
}
// Negative test: lambdas that capture a non-serializable var
public void testSerializeCapturingNonSerializable() throws IOException, ClassNotFoundException {
class Box {
String s;
Box(String s) { this.s = s; }
}
class Moo {
@SuppressWarnings("unchecked")
Predicate<String> foo(Box b) {
return (Predicate<String> & Serializable) s -> s.equals(b.s);
}
}
Predicate<String> pred = new Moo().foo(new Box("goo"));
assertNotSerial(pred, p -> {
assertTrue(p.test("goo"));
assertFalse(p.test("foo"));
});
}
static boolean startsWithA(String s) {
return s.startsWith("a");
}
// Test static method ref
public void testStaticMR() throws IOException, ClassNotFoundException {
@SuppressWarnings("unchecked")
Predicate<String> mh1 = (Predicate<String> & Serializable) SerializedLambdaTest::startsWithA;
@SuppressWarnings("unchecked")
Predicate<String> mh2 = (SerPredicate<String>) SerializedLambdaTest::startsWithA;
Consumer<Predicate<String>> b = p -> {
assertTrue(p instanceof Serializable);
assertTrue(p.test("arf"));
assertFalse(p.test("barf"));
};
assertSerial(mh1, b);
assertSerial(mh2, b);
}
// Test unbound method ref of nonserializable class -- should still succeed
public void testUnboundMR() throws IOException, ClassNotFoundException {
class Moo {
public boolean startsWithB(String s) {
return s.startsWith("b");
}
}
@SuppressWarnings("unchecked")
BiPredicate<Moo, String> mh1 = (BiPredicate<Moo, String> & Serializable) Moo::startsWithB;
Consumer<BiPredicate<Moo, String>> b = p -> {
assertTrue(p instanceof Serializable);
assertTrue(p.test(new Moo(), "barf"));
assertFalse(p.test(new Moo(), "arf"));
};
assertSerial(mh1, b);
}
// Negative test: test bound MR of nonserializable class
public void testBoundMRNotSerReceiver() throws IOException, ClassNotFoundException {
class Moo {
public boolean startsWithB(String s) {
return s.startsWith("b");
}
}
Moo moo = new Moo();
@SuppressWarnings("unchecked")
Predicate<String> mh1 = (Predicate<String> & Serializable) moo::startsWithB;
@SuppressWarnings("unchecked")
Predicate<String> mh2 = (SerPredicate<String>) moo::startsWithB;
Consumer<Predicate<String>> b = p -> {
assertTrue(p instanceof Serializable);
assertTrue(p.test("barf"));
assertFalse(p.test("arf"));
};
assertNotSerial(mh1, b);
assertNotSerial(mh2, b);
}
// Test bound MR of serializable class
@SuppressWarnings("serial")
static class ForBoundMRef implements Serializable {
public boolean startsWithB(String s) {
return s.startsWith("b");
}
}
public void testBoundMR() throws IOException, ClassNotFoundException {
ForBoundMRef moo = new ForBoundMRef();
@SuppressWarnings("unchecked")
Predicate<String> mh1 = (Predicate<String> & Serializable) moo::startsWithB;
@SuppressWarnings("unchecked")
Predicate<String> mh2 = (SerPredicate<String>) moo::startsWithB;
Consumer<Predicate<String>> b = p -> {
assertTrue(p instanceof Serializable);
assertTrue(p.test("barf"));
assertFalse(p.test("arf"));
};
assertSerial(mh1, b);
assertSerial(mh2, b);
}
static class ForCtorRef {
public boolean startsWithB(String s) {
return s.startsWith("b");
}
}
// Test ctor ref of nonserializable class
public void testCtorRef() throws IOException, ClassNotFoundException {
@SuppressWarnings("unchecked")
Supplier<ForCtorRef> ctor = (Supplier<ForCtorRef> & Serializable) ForCtorRef::new;
Consumer<Supplier<ForCtorRef>> b = s -> {
assertTrue(s instanceof Serializable);
ForCtorRef m = s.get();
assertTrue(m.startsWithB("barf"));
assertFalse(m.startsWithB("arf"));
};
assertSerial(ctor, b);
}
//Test throwing away return type
public void testDiscardReturnBound() throws IOException, ClassNotFoundException {
List<String> list = new ArrayList<>();
Consumer<String> c = (Consumer<String> & Serializable) list::add;
assertSerial(c, cc -> { assertTrue(cc instanceof Consumer); });
AtomicLong a = new AtomicLong();
LongConsumer lc = (LongConsumer & Serializable) a::addAndGet;
assertSerial(lc, plc -> { plc.accept(3); });
}
// Tests of direct use of metafactories
private static boolean foo(Object s) { return s != null && ((String) s).length() > 0; }
private static final MethodType predicateMT = MethodType.methodType(boolean.class, Object.class);
private static final MethodType stringPredicateMT = MethodType.methodType(boolean.class, String.class);
private static final Consumer<Predicate<String>> fooAsserter = x -> {
assertTrue(x.test("foo"));
assertFalse(x.test(""));
assertFalse(x.test(null));
};
// standard MF: nonserializable supertype
public void testDirectStdNonser() throws Throwable {
MethodHandle fooMH = MethodHandles.lookup().findStatic(SerializedLambdaTest.class, "foo", predicateMT);
// Standard metafactory, non-serializable target: not serializable
CallSite cs = LambdaMetafactory.metafactory(MethodHandles.lookup(),
"test", MethodType.methodType(Predicate.class),
predicateMT, fooMH, stringPredicateMT);
Predicate<String> p = (Predicate<String>) cs.getTarget().invokeExact();
assertNotSerial(p, fooAsserter);
}
// standard MF: serializable supertype
public void testDirectStdSer() throws Throwable {
MethodHandle fooMH = MethodHandles.lookup().findStatic(SerializedLambdaTest.class, "foo", predicateMT);
// Standard metafactory, serializable target: not serializable
CallSite cs = LambdaMetafactory.metafactory(MethodHandles.lookup(),
"test", MethodType.methodType(SerPredicate.class),
predicateMT, fooMH, stringPredicateMT);
assertNotSerial((SerPredicate<String>) cs.getTarget().invokeExact(), fooAsserter);
}
// alt MF: nonserializable supertype
public void testAltStdNonser() throws Throwable {
MethodHandle fooMH = MethodHandles.lookup().findStatic(SerializedLambdaTest.class, "foo", predicateMT);
// Alt metafactory, non-serializable target: not serializable
CallSite cs = LambdaMetafactory.altMetafactory(MethodHandles.lookup(),
"test", MethodType.methodType(Predicate.class),
predicateMT, fooMH, stringPredicateMT, 0);
assertNotSerial((Predicate<String>) cs.getTarget().invokeExact(), fooAsserter);
}
// alt MF: serializable supertype
public void testAltStdSer() throws Throwable {
MethodHandle fooMH = MethodHandles.lookup().findStatic(SerializedLambdaTest.class, "foo", predicateMT);
// Alt metafactory, serializable target, no FLAG_SERIALIZABLE: not serializable
CallSite cs = LambdaMetafactory.altMetafactory(MethodHandles.lookup(),
"test", MethodType.methodType(SerPredicate.class),
predicateMT, fooMH, stringPredicateMT, 0);
assertNotSerial((SerPredicate<String>) cs.getTarget().invokeExact(), fooAsserter);
// Alt metafactory, serializable marker, no FLAG_SERIALIZABLE: not serializable
cs = LambdaMetafactory.altMetafactory(MethodHandles.lookup(),
"test", MethodType.methodType(Predicate.class),
predicateMT, fooMH, stringPredicateMT, LambdaMetafactory.FLAG_MARKERS, 1, Serializable.class);
assertNotSerial((Predicate<String>) cs.getTarget().invokeExact(), fooAsserter);
}
}