blob: 6a03bfec6e73af4b9b82f3e7bf6d509492f08d97 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.transform.stc
import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.shouldFail
final class LambdaTest {
private final GroovyShell shell = GroovyShell.withConfig {
ast(groovy.transform.CompileStatic)
imports {
normal 'java.util.stream.Collectors'
star 'java.util.function'
star 'java.util.stream'
}
}
@Test
void testFunction() {
assertScript shell, '''
def f() {
[1, 2, 3].stream().map(e -> e + 1).collect(Collectors.toList())
}
assert f() == [2, 3, 4]
'''
}
@Test
void testFunction2() {
assertScript shell, '''
def f() {
[1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
}
assert f() == [2, 3, 4]
'''
}
@Test
void testFunctionWithTypeArgument() {
assertScript shell, '''
List<String> f() {
[1, 2, 3].stream().<String>map(i -> null).collect(Collectors.toList())
}
assert f() == [null, null, null]
'''
}
@Test
void testBinaryOperator() {
assertScript shell, '''
int f() {
[1, 2, 3].stream().reduce(7, (Integer r, Integer e) -> r + e)
}
assert f() == 13
'''
}
@Test // GROOVY-8917
void testBinaryOperatorWithoutExplicitTypes() {
assertScript shell, '''
int f() {
[1, 2, 3].stream().reduce(7, (r, e) -> r + e)
}
assert f() == 13
'''
}
@Test
void testBinaryOperatorWithoutExplicitTypes2() {
assertScript shell, '''
int f() {
BinaryOperator<Integer> accumulator = (r, e) -> r + e
return [1, 2, 3].stream().reduce(7, accumulator)
}
assert f() == 13
'''
}
@Test // GROOVY-10282
void testBiFunctionAndBinaryOperatorWithSharedTypeParameter() {
assertScript shell, '''
def f() {
IntStream.range(0, 10).boxed().reduce('', (s, i) -> s + '-', String::concat)
}
assert f() == '----------'
'''
}
@Test
void testBiFunctionAndVariadicMethod() {
assertScript shell, '''
class C {
List m(... args) {
[this,*args]
}
}
void test(C c) {
BiFunction<Integer, Integer, List> f = (i, j) -> c.m(i, j)
def list = f.apply(1,2)
assert list.size() == 3
assert list[0] == c
assert list[1] == 1
assert list[2] == 2
}
test(new C())
'''
}
@Test
void testPredicate() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
def list = ['ab', 'bc', 'de']
list.removeIf(e -> e.startsWith('a'))
assert ['bc', 'de'] == list
}
}
'''
}
@Test
void testPredicateWithoutExplicitTypeDef() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
List<String> myList = Arrays.asList('a1', 'a2', 'b2', 'b1', 'c2', 'c1')
Predicate<String> predicate = s -> s.startsWith('b')
Function<String, String> mapper = s -> s.toUpperCase()
List<String> result =
myList
.stream()
.filter(predicate)
.map(mapper)
.sorted()
.collect(Collectors.toList())
assert ['B1', 'B2'] == result
}
}
'''
}
@Test
void testUnaryOperator() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
def list = [1, 2, 3]
list.replaceAll(e -> e + 10)
assert [11, 12, 13] == list
}
}
'''
}
@Test
void testBiConsumer() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
def map = [a: 1, b: 2, c: 3]
map.forEach((k, v) -> System.out.println(k + ':' + v));
}
}
'''
}
@Test
void testComparator() {
assertScript shell, '''
class T {
Comparator<Integer> c = (Integer a, Integer b) -> Integer.compare(a, b)
}
def t = new T()
assert t.c.compare(0,0) == 0
'''
}
@Test // GROOVY-10372
void testComparator2() {
def err = shouldFail shell, '''
class T {
Comparator<Integer> c = (int a, String b) -> 42
}
'''
assert err =~ /Expected type java.lang.Integer for lambda parameter: b/
}
@Test // GROOVY-9977
void testComparator3() {
assertScript shell, '''
class T {
Comparator<Integer> c = (a, b) -> Integer.compare(a, b)
void m1() {
Comparator<Integer> x = (a, b) -> Integer.compare(a, b)
}
static void m2() {
Comparator<Integer> y = (a, b) -> Integer.compare(a, b)
}
}
def t = new T()
assert t.c.compare(0,0) == 0
'''
}
@Test // GROOVY-9997
void testComparator4() {
assertScript '''
@groovy.transform.TypeChecked
void test() {
def cast = (Comparator<Integer>) (a, b) -> Integer.compare(a, b)
assert cast.compare(0,0) == 0
def coerce = ((a, b) -> Integer.compare(a, b)) as Comparator<Integer>
assert coerce.compare(0,0) == 0
}
test()
'''
}
@Test
void testCollectors1() {
for (spec in ['', '<String,String,String>']) {
assertScript shell, """
def set = ['a', 'b', 'c'] as Set<String>
def map = set.stream().collect(Collectors.${spec}toMap(e -> e, e -> e))
assert map == [a: 'a', b: 'b', c: 'c']
"""
}
}
@Test
void testCollectors2() {
for (spec in ['', '<String,String,String>']) {
assertScript shell, """
def set = ['a', 'b', 'c'] as Set<String>
def map = set.stream().collect(Collectors.${spec}toMap(e -> e, e -> e, (v1,v2) -> v2))
assert map == [a: 'a', b: 'b', c: 'c']
"""
}
}
@Test
void testFunctionWithLocalVariables() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
String x = '#'
assert ['#1', '#2', '#3'] == [1, 2, 3].stream().map(e -> x + e).collect(Collectors.toList());
}
}
'''
}
@Test
void testFunctionWithLocalVariables2() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
String x = '#'
Integer y = 23
assert ['23#1', '23#2', '23#3'] == [1, 2, 3].stream().map(e -> '' + y + x + e).collect(Collectors.toList())
}
}
'''
}
@Test
void testFunctionWithLocalVariables3() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
String x = 'x'
StringBuilder y = new StringBuilder('y')
assert ['yx1', 'yx2', 'yx3'] == [1, 2, 3].stream().map(e -> y + x + e).collect(Collectors.toList())
}
}
'''
}
@Test
void testFunctionWithLocalVariables4() {
assertScript shell, '''
class Test1 {
static main(args) {
Function<Integer, String> f = p()
assert '#1' == f(1)
}
static Function<Integer, String> p() {
String x = '#'
Function<Integer, String> f = (Integer e) -> x + e
return f
}
}
'''
}
@Test
void testFunctionWithLocalVariables5() {
assertScript shell, '''
class Test1 {
static main(args) {
Function<Integer, String> f = new Test1().p();
assert '#1' == f(1)
}
Function<Integer, String> p() {
String x = '#'
Function<Integer, String> f = (Integer e) -> x + e
return f
}
}
'''
}
@Test
void testFunctionWithStaticMethodCall() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
String x = 'x'
StringBuilder y = new StringBuilder('y')
assert ['Hello yx1', 'Hello yx2', 'Hello yx3'] == [1, 2, 3].stream().map(e -> hello() + y + x + e).collect(Collectors.toList())
}
static String hello() {
return 'Hello '
}
}
'''
}
@Test
void testFunctionWithStaticMethodCall2() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
String x = 'x'
StringBuilder y = new StringBuilder('y')
assert ['Hello yx1', 'Hello yx2', 'Hello yx3'] == [1, 2, 3].stream().map(e -> Test1.hello() + y + x + e).collect(Collectors.toList())
}
static String hello() {
return 'Hello '
}
}
'''
}
@Test
void testFunctionWithInstanceMethodCall() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
assert ['Hello Jochen', 'Hello Daniel'] == ['Jochen', 'Daniel'].stream().map(e -> hello() + e).collect(Collectors.toList())
}
String hello() {
return 'Hello '
}
}
'''
}
@Test
void testFunctionInConstructor() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1()
}
Test1() {
assert ['Hello Jochen', 'Hello Daniel'] == ['Jochen', 'Daniel'].stream().map(e -> hello() + e).collect(Collectors.toList())
}
String hello() {
return 'Hello '
}
}
'''
}
@Test
void testFunctionWithInstanceMethodCall2() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
assert ['Hello Jochen', 'Hello Daniel'] == ['Jochen', 'Daniel'].stream().map(e -> this.hello() + e).collect(Collectors.toList())
}
String hello() {
return 'Hello '
}
}
'''
}
@Test
void testFunctionWithInstanceMethodCall3() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
assert ['Hello Jochen', 'Hello Daniel'] == ['Jochen', 'Daniel'].stream().map(e -> hello(e)).collect(Collectors.toList())
}
String hello(String name) {
return "Hello $name"
}
}
'''
}
@Test
void testFunctionCall() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
Function<Integer, Integer> f = (Integer e) -> (Integer) (e + 1)
assert 2 == f(1)
}
}
'''
}
@Test
void testFunctionCallWithoutExplicitTypeDef() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
Function<Integer, Integer> f = e -> e + 1
assert 2 == f(1)
}
}
'''
}
@Test
void testFunctionCall2() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
Function<Integer, Integer> f = (Integer e) -> (Integer) (e + 1)
assert 2 == f(1)
}
}
'''
}
@Test
void testFunctionCall3() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
Function<Integer, Integer> f = (Integer e) -> (Integer) (e + 1)
assert 2 == f.apply(1)
}
}
'''
}
@Test
void testConsumer1() {
assertScript shell, '''
int a = 1
Consumer<Integer> c = i -> { a += i }
c.accept(2)
assert a == 3
'''
}
@Test
void testConsumer2() {
assertScript shell, '''
int a = 1
Consumer<Integer> c = (i) -> { a += i }
c.accept(2)
assert a == 3
'''
}
@Test
void testConsumer3() {
assertScript shell, '''
int a = 1
Consumer<Integer> c = (Integer i) -> { a += i }
c.accept(2)
assert a == 3
'''
}
@Test
void testConsumer4() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
int a = 1
Consumer<Integer> c = e -> { a += e }
c.accept(2)
assert a == 3
}
}
'''
}
@Test
void testConsumer5() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
int a = 1
Consumer<Integer> c = (Integer e) -> { a += e }
c.accept(2)
assert a == 3
}
}
'''
}
@Test
void testConsumer6() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
int a = 1
Consumer<Integer> c = (Integer e) -> { a += e }
c(2)
assert a == 3
}
}
'''
}
@Test // GROOVY-9347
void testConsumer7() {
assertScript shell, '''
void test() {
int sum = 0
Consumer<? super Integer> add = i -> sum += i
[1, 2, 3].forEach(add)
assert sum == 6
}
test()
'''
}
@Test // GROOVY-9340
void testConsumer8() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
Consumer<Test1> c = t -> null
c.accept(this.newInstance())
}
}
'''
}
@Test
void testConsumer9() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
[1, 2, 3].stream().forEach(e -> { System.out.println(e + 1); })
}
}
'''
}
@Test // GROOVY-10056
void testConsumer10() {
['CompileStatic', 'TypeChecked'].each { xform ->
assertScript """
@groovy.transform.${xform}
void test() {
String[][] arrayArray = new String[][] {
new String[] {'a','b','c'},
new String[] {'d','e','f'}
}
Arrays.stream(arrayArray).limit(1).forEach(array -> {
assert Arrays.asList(array) == ['a','b','c']
})
}
test()
"""
}
}
@Test // GROOVY-10813
void testConsumer11() {
['CompileStatic', 'TypeChecked'].each { xform ->
assertScript """
@groovy.transform.${xform}
void test() {
java.util.function.Consumer c = x -> print(x)
c.accept('works')
}
test()
"""
assertScript """
interface I<T extends CharSequence> {
void accept(T t)
}
@groovy.transform.${xform}
void test() {
I i = x -> print(x)
i.accept('works')
}
test()
"""
}
}
@Test
void testFunctionalInterface1() {
assertScript shell, '''
interface SamCallable {
int call(int i)
}
void p() {
SamCallable c = (int x) -> x
assert c(1) == 1
}
p()
'''
}
@Test
void testFunctionalInterface2() {
assertScript shell, '''
interface SamCallable {
int call(int i)
}
void p() {
SamCallable c = x -> x
assert c(1) == 1
}
p()
'''
}
@Test
void testFunctionalInterface3() {
assertScript shell, '''
abstract class SamCallable {
abstract int call(int i)
}
void p() {
SamCallable c = (int x) -> x // this is a closure, not a native lambda
assert c(1) == 1
}
p()
'''
}
@Test // GROOVY-9881
void testFunctionalInterface4() {
assertScript shell, '''
class Value<V> {
final V val
Value(V v) {
this.val = v
}
String toString() {
val as String
}
def <T> Value<T> replace(Supplier<T> supplier) {
new Value<>(supplier.get())
}
def <T> Value<T> replace(Function<? super V, ? extends T> function) {
new Value<>(function.apply(val))
}
}
assert new Value<>(123).replace(() -> 'foo').toString() == 'foo'
assert new Value<>(123).replace((Integer v) -> 'bar').toString() == 'bar'
'''
}
@Test // GROOVY-10372
void testFunctionalInterface5() {
def err = shouldFail shell, '''
interface I {
def m(List<String> strings)
}
I face = (List<Object> list) -> null
'''
assert err =~ /Expected type java.util.List<java.lang.String> for lambda parameter: list/
}
@Test
void testFunctionWithUpdatingLocalVariable() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
int i = 1
assert [2, 4, 7] == [1, 2, 3].stream().map(e -> i += e).collect(Collectors.toList())
assert 7 == i
}
}
'''
}
@Test
void testFunctionWithUpdatingLocalVariable2() {
assertScript shell, '''
class Test1 {
static main(args) {
new Test1().p()
}
void p() {
int i = 1
assert [2, 4, 7] == [1, 2, 3].stream().map(e -> i += e).collect(Collectors.toList())
assert 7 == i
}
}
'''
}
@Test
void testFunctionWithVariableDeclaration() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
public static void p() {
Function<Integer, String> f = (Integer e) -> 'a' + e
assert ['a1', 'a2', 'a3'] == [1, 2, 3].stream().map(f).collect(Collectors.toList())
}
}
'''
}
@Test
void testFunctionWithMixingVariableDeclarationAndMethodInvocation() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
String x = '#'
Integer y = 23
assert ['23#1', '23#2', '23#3'] == [1, 2, 3].stream().map(e -> '' + y + x + e).collect(Collectors.toList())
Function<Integer, String> f = (Integer e) -> 'a' + e
assert ['a1', 'a2', 'a3'] == [1, 2, 3].stream().map(f).collect(Collectors.toList())
assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList());
}
}
'''
}
@Test
void testFunctionWithNestedLambda() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
[1, 2].stream().forEach(e -> {
def list = ['a', 'b'].stream().map(f -> f + e).toList()
if (1 == e) {
assert ['a1', 'b1'] == list
} else if (2 == e) {
assert ['a2', 'b2'] == list
}
})
}
}
'''
}
@Test
void testFunctionWithNestedLambda2() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
def list = ['a', 'b'].stream()
.map(e -> {
[1, 2].stream().map(f -> e + f).toList()
}).toList()
assert ['a1', 'a2'] == list[0]
assert ['b1', 'b2'] == list[1]
}
}
'''
}
@Test
void testFunctionWithNestedLambda3() {
assertScript shell, '''
class Test1 {
static main(args) {
p()
}
static void p() {
def list = ['a', 'b'].stream()
.map(e -> {
Function<Integer, String> x = (Integer f) -> e + f
[1, 2].stream().map(x).toList()
}).toList()
assert ['a1', 'a2'] == list[0]
assert ['b1', 'b2'] == list[1]
}
}
'''
}
@Test
void testMixingLambdaAndMethodReference() {
assertScript shell, '''
assert ['1', '2', '3'] == [1, 2, 3].stream().map(Object::toString).collect(Collectors.toList())
assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
assert ['1', '2', '3'] == [1, 2, 3].stream().map(Object::toString).collect(Collectors.toList())
'''
}
@Test
void testInitializeBlocks() {
assertScript shell, '''
class Test1 {
static sl
def il
static { sl = [1, 2, 3].stream().map(e -> e + 1).toList() }
{
il = [1, 2, 3].stream().map(e -> e + 2).toList()
}
}
assert [2, 3, 4] == Test1.sl
assert [3, 4, 5] == new Test1().il
'''
}
@Test
void testNestedLambdaAccessingInstanceFields() {
assertScript shell, '''
class Test1 {
private List<String> strList = ['a', 'e', 'f']
private Map<String, List<String>> strListHolder = ['strList': strList]
private String b = 'b'
def p() {
['abc', 'def', 'ghi'].stream().filter(e -> strList.stream().anyMatch(c -> e.contains(c + b))).toList()
}
def p2() {
['abc', 'def', 'ghi'].stream().filter(e -> strListHolder.strList.stream().anyMatch(c -> e.contains(c + b))).toList()
}
}
assert ['abc'] == new Test1().p()
assert ['abc'] == new Test1().p2()
'''
}
@Test // GROOVY-9332
void testStaticInitializeBlocks1() {
assertScript shell, '''
class Test1 {
static list
static final int one = 1
static { list = [1, 2, 3].stream().map(e -> e + one).toList() }
}
assert [2, 3, 4] == Test1.list
'''
}
@Test // GROOVY-9347
void testStaticInitializeBlocks2() {
assertScript shell, '''
class Test1 {
static int acc = 1
static { [1, 2, 3].forEach(e -> acc += e) }
}
assert Test1.acc == 7
'''
}
@Test // GROOVY-9342
void testStaticInitializeBlocks3() {
assertScript shell, '''
class Test1 {
static int acc = 1
static { [1, 2, 3].forEach((Integer i) -> acc += i) }
}
assert Test1.acc == 7
'''
}
@Test
void testAccessingThis1() {
assertScript shell, '''
class ThisTest {
private final ThisTest that = this
void m() {
Predicate<ThisTest> p = (ThisTest t) -> {
assert this === t
}
p.test(that)
p.test(this)
}
}
new ThisTest().m()
'''
}
@Test
void testAccessingThis2() {
assertScript shell, '''
class ThisTest {
private final ThisTest that = this
void m() {
Predicate<ThisTest> p1 = (ThisTest t1) -> {
Predicate<ThisTest> p2 = (ThisTest t2) -> {
assert this === t1 && this === t2
}
p2.test(t1)
}
p1.test(that)
p1.test(this)
}
}
new ThisTest().m()
'''
}
@Test
void testAccessingThis3() {
assertScript shell, '''
class ThisTest {
String p = 'a'
void m() {
def list = [1, 2].stream().map(e -> this.p + e).toList()
assert list == ['a1', 'a2']
}
}
new ThisTest().m()
'''
}
@Test
void testAccessingThis4() {
assertScript shell, '''
class ThisTest {
String getP() { 'a' }
void m() {
def list = [1, 2].stream().map(e -> this.p + e).toList()
assert list == ['a1', 'a2']
}
}
new ThisTest().m()
'''
}
@Test
void testSerialize1() {
assertScript shell, '''
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
byte[] test() {
try (def out = new ByteArrayOutputStream()) {
out.withObjectOutputStream {
SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
it.writeObject(f)
}
out.toByteArray()
}
}
assert test().length > 0
'''
}
@Test
void testSerialize2() {
def err = shouldFail shell, NotSerializableException, '''
byte[] test() {
try (def out = new ByteArrayOutputStream()) {
out.withObjectOutputStream {
Function<Integer, String> f = ((Integer i) -> 'a' + i)
it.writeObject(f)
}
out.toByteArray()
}
}
test()
'''
assert err.message.contains('$Lambda')
}
@Test
void testDeserialize1() {
assertScript shell, '''
package tests.lambda
class C {
byte[] test() {
def out = new ByteArrayOutputStream()
out.withObjectOutputStream { it ->
SerializableFunction<Integer, String> f = (Integer i) -> 'a' + i
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize2() {
assertScript shell, '''
package tests.lambda
class C implements Serializable {
private static final long serialVersionUID = -1L
String s = 'a'
transient SerializableFunction<Integer, String> f = (Integer i) -> s + i
byte[] test() {
def out = new ByteArrayOutputStream()
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize3() {
def err = shouldFail shell, NotSerializableException, '''
package tests.lambda
class C {
String s = 'a'
SerializableFunction<Integer, String> f = (Integer i) -> s + i
byte[] test() {
def out = new ByteArrayOutputStream()
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
this.newInstance().test()
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
assert err.message.contains('tests.lambda.C')
}
@Test
void testDeserialize4() {
assertScript shell, '''
class C {
static byte[] test() {
def out = new ByteArrayOutputStream()
out.withObjectOutputStream { it ->
SerializableFunction<Integer, String> f = (Integer i) -> 'a' + i
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize5() {
assertScript shell, '''
package tests.lambda
class C {
byte[] test() {
def out = new ByteArrayOutputStream()
out.withObjectOutputStream {
String s = 'a'
SerializableFunction<Integer, String> f = (Integer i) -> s + i
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize6() {
assertScript shell, '''
package tests.lambda
class C {
byte[] test() {
def out = new ByteArrayOutputStream()
String s = 'a'
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize7() {
assertScript shell, '''
package tests.lambda
class C {
static byte[] test() {
def out = new ByteArrayOutputStream()
String s = 'a'
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize8() {
assertScript shell, '''
package tests.lambda
class C implements Serializable {
private static final long serialVersionUID = -1L
private String s = 'a'
byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize9() {
def err = shouldFail shell, NotSerializableException, '''
package tests.lambda
class C {
private String s = 'a'
byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
assert err.message.contains('tests.lambda.C')
}
@Test
void testDeserialize10() {
assertScript shell, '''
package tests.lambda
class C implements Serializable {
private static final long serialVersionUID = -1L
private String getS() { 'a' }
byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize11() {
def err = shouldFail shell, NotSerializableException, '''
package tests.lambda
class C {
private String getS() { 'a' }
byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
assert err.message.contains('tests.lambda.C')
}
@Test
void testDeserialize12() {
assertScript shell, '''
package tests.lambda
class C {
private static final String s = 'a'
static byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserialize13() {
assertScript shell, '''
package tests.lambda
class C {
private static String getS() { 'a' }
static byte[] test() {
def out = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f = (Integer i) -> s + i
out.withObjectOutputStream {
it.writeObject(f)
}
out.toByteArray()
}
static main(args) {
new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
}
interface SerializableFunction<I,O> extends Serializable, Function<I,O> {
}
}
'''
}
@Test
void testDeserializeNestedLambda1() {
assertScript '''
interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
}
@groovy.transform.CompileStatic
class C {
def test() {
def out1 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f1 = (Integer i) -> 'a' + i
out1.withObjectOutputStream {
it.writeObject(f1)
}
def out2 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f2 = (Integer i) -> 'b' + i
out2.withObjectOutputStream {
it.writeObject(f2)
}
// nested lambda expression
def out3 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f3 = (Integer i) -> {
SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
nf(i) + 'c'
}
out3.withObjectOutputStream {
it.writeObject(f3)
}
[out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
}
}
def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = new C().test()
new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'b1'
}
new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'c1c'
}
'''
}
@Test
void testDeserializeNestedLambda2() {
assertScript '''
interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
}
@groovy.transform.CompileStatic
class C {
def test() {
def out1 = new ByteArrayOutputStream()
out1.withObjectOutputStream {
SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
it.writeObject(f)
}
def out2 = new ByteArrayOutputStream()
out2.withObjectOutputStream {
SerializableFunction<Integer, String> f = ((Integer i) -> 'b' + i)
it.writeObject(f)
}
// nested lambda expression
def out3 = new ByteArrayOutputStream()
out3.withObjectOutputStream { it ->
SerializableFunction<Integer, String> f = (Integer i) -> {
SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
nf(i) + 'c'
}
it.writeObject(f)
}
[out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
}
}
def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = new C().test()
new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'b1'
}
new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'c1c'
}
'''
}
@Test
void testDeserializeNestedLambda3() {
assertScript '''
interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
}
@groovy.transform.CompileStatic
class C {
static test() {
def out1 = new ByteArrayOutputStream()
out1.withObjectOutputStream {
SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
it.writeObject(f)
}
def out2 = new ByteArrayOutputStream()
out2.withObjectOutputStream {
SerializableFunction<Integer, String> f = ((Integer i) -> 'b' + i)
it.writeObject(f)
}
// nested lambda expression
def out3 = new ByteArrayOutputStream()
out3.withObjectOutputStream { it ->
SerializableFunction<Integer, String> f = (Integer i) -> {
SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
nf(i) + 'c'
}
it.writeObject(f)
}
[out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
}
}
def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = C.test()
new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'b1'
}
new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'c1c'
}
'''
}
@Test
void testDeserializeNestedLambda4() {
assertScript '''
interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
}
@groovy.transform.CompileStatic
class C {
static test() {
def out1 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f1 = (Integer i) -> 'a' + i
out1.withObjectOutputStream {
it.writeObject(f1)
}
def out2 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f2 = (Integer i) -> 'b' + i
out2.withObjectOutputStream {
it.writeObject(f2)
}
// nested lambda expression
def out3 = new ByteArrayOutputStream()
SerializableFunction<Integer, String> f3 = (Integer i) -> {
SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
nf(i) + 'c'
}
out3.withObjectOutputStream {
it.writeObject(f3)
}
[out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
}
}
def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = C.test()
new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'a1'
}
new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'b1'
}
new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
assert f.apply(1) == 'c1c'
}
'''
}
@Test // GROOVY-9146
void testScriptWithExistingMainCS() {
assertScript shell, '''
static void main(args) {
Function<String, String> lower = String::toLowerCase
assert lower.toString().contains('$$Lambda')
}
'''
}
}