SamConversion.java revision 1414:01c9d4161882
1/*
2 * Copyright (c) 2012, 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 8003280
27 * @summary Add lambda tests
28 *   Test SAM conversion of method references in contexts of assignment, method/constructor argument,
29 *           return statement, array initializer, lambda expression body, conditional expression and cast.
30 * @compile SamConversion.java
31 * @run main SamConversion
32 */
33
34public class SamConversion {
35
36    static int assertionCount = 0;
37
38    static interface Foo {
39        Integer m(int i);
40    }
41
42    static interface Bar {
43        int m(Integer i) throws MyException;
44    }
45
46    private static void assertTrue(boolean b) {
47        assertionCount++;
48        if(!b)
49            throw new AssertionError();
50    }
51
52    private static int test1(Foo foo) {
53        return foo.m(1);
54    }
55
56    private static void test2(Bar bar, int result) {
57        try {
58            assertTrue(bar.m(1) == result);
59        } catch (Exception e){
60            assertTrue(false);
61        }
62    }
63
64    private static Bar test3(int i) {
65        switch (i) {
66        case 0:
67            return A::method1;
68        case 1:
69            return new A()::method2;
70        case 2:
71            return A::method3;
72        case 3:
73            return new A()::method4;
74        case 4:
75            return new A()::method5;
76        case 5:
77            return A::method6;
78        default:
79            return null;
80        }
81    }
82
83    /**
84     * Test SAM conversion of method reference in assignment context
85     */
86    private static void testAssignment() {
87        Foo foo = A::method1; //static reference, parameter type matching and return type matching
88        assertTrue(foo.m(1) == 2);
89
90        foo = new A()::method2; //instance reference, parameter type unboxing and return type boxing
91        assertTrue(foo.m(1) == 3);
92
93        foo = A::method3; //static reference, parameter type matching and return type boxing
94        assertTrue(foo.m(1) == 4);
95
96        foo = new A()::method4; //instance reference, parameter type unboxing and return type matching
97        assertTrue(foo.m(1) == 5);
98
99        foo = new A()::method5; //instance reference, parameter type unboxing and return type matching
100        assertTrue(foo.m(1) == 6);
101
102        Bar bar = A::method1;
103        try {
104            assertTrue(bar.m(1) == 2);
105        } catch (Exception e) {
106            assertTrue(false);
107        }
108
109        bar = new A()::method2;
110        try {
111            assertTrue(bar.m(1) == 3);
112        } catch (Exception e) {
113            assertTrue(false);
114        }
115
116        bar = A::method3;
117        try {
118            assertTrue(bar.m(1) == 4);
119        } catch (Exception e) {
120            assertTrue(false);
121        }
122
123        bar = new A()::method4;
124        try {
125            assertTrue(bar.m(1) == 5);
126        } catch (Exception e) {
127            assertTrue(false);
128        }
129
130        bar = new A()::method5;
131        try {
132            assertTrue(bar.m(1) == 6);
133        } catch (Exception e) {
134            assertTrue(false);
135        }
136
137        bar = new A()::method6;
138        try {
139            bar.m(1);
140            assertTrue(false);
141        } catch (MyException e) {
142        } catch (Exception e) {
143            assertTrue(false);
144        }
145    }
146
147    /**
148     * Test SAM conversion of method reference in method/constructor argument context
149     */
150    private static void testMethodArgument() {
151        assertTrue(test1(A::method1) == 2);
152        assertTrue(test1(new A()::method2) == 3);
153        assertTrue(test1(A::method3) == 4);
154        assertTrue(test1(new A()::method4) == 5);
155        assertTrue(test1(new A()::method5) == 6);
156        test2(A::method1, 2);
157        test2(new A()::method2, 3);
158        test2(A::method3, 4);
159        test2(new A()::method4, 5);
160        test2(new A()::method5, 6);
161        A a = new A(A::method1); //A(Foo f) called
162        assertTrue(a.method2(1) == 11);
163        assertTrue(a.method4(1) == 11);
164        assertTrue(a.method5(1) == 11);
165        A a2 = new A(new A()::method2); //A(Bar b) called
166        assertTrue(a2.method2(1) == 12);
167        assertTrue(a2.method4(1) == 12);
168        assertTrue(a2.method5(1) == 12);
169    }
170
171    /**
172     * Test SAM conversion of method reference in return statement context
173     */
174    private static void testReturnStatement() {
175        Bar bar = test3(0);
176        try {
177            assertTrue(bar.m(1) == 2);
178        } catch (Exception e) {
179            assertTrue(false);
180        }
181        bar = test3(1);
182        try {
183            assertTrue(bar.m(1) == 3);
184        } catch (Exception e) {
185            assertTrue(false);
186        }
187        bar = test3(2);
188        try {
189            assertTrue(bar.m(1) == 4);
190        } catch (Exception e) {
191            assertTrue(false);
192        }
193        bar = test3(3);
194        try {
195            assertTrue(bar.m(1) == 5);
196        } catch (Exception e) {
197            assertTrue(false);
198        }
199        bar = test3(4);
200        try {
201            assertTrue(bar.m(1) == 6);
202        } catch (Exception e) {
203            assertTrue(false);
204        }
205        bar = test3(5);
206        try {
207            bar.m(1);
208            assertTrue(false);
209        } catch (MyException e) {
210        } catch (Exception e) {
211            assertTrue(false);
212        }
213    }
214
215    /**
216     * Test SAM conversion of method reference in cast context
217     */
218    private static void testCast() {
219        assertTrue(((Foo)A::method1).m(1) == 2);
220        try {
221            assertTrue(((Bar)new A()::method2).m(1) == 3);
222        } catch (Exception e) {
223            assertTrue(false);
224        }
225    }
226
227    /**
228     * Test SAM conversion of method reference in array initializer context
229     */
230    private static void testArrayInitializer() {
231        Object[] oarray = {"a", 1, (Foo)A::method3}; //last element need a cast
232        Object[] oarray2 = {"a", 1, (Bar)new A()::method4}; //last element need a cast
233        Foo[] farray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5};
234        Bar[] barray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5, A::method6};
235    }
236
237    /**
238     * Test SAM conversion of method reference in conditional expression context
239     */
240    private static void testConditionalExpression(boolean b) {
241        Foo f = b ? A::method3 : new A()::method5;
242        if(b)
243            assertTrue(f.m(1) == 4);
244        else
245            assertTrue(f.m(1) == 6);
246
247        Bar bar = b ? A::method1 : A::method6;
248        if(b) {
249            try {
250                assertTrue(bar.m(1) == 2);
251            } catch (Exception e) {
252                assertTrue(false);
253            }
254        }
255        else {
256            try {
257                bar.m(1);
258                assertTrue(false);
259            } catch (MyException e) {
260            } catch (Exception e) {
261                assertTrue(false);
262            }
263        }
264    }
265
266    /**
267     * Test SAM conversion of method reference in lambda expression body
268     */
269    private static void testLambdaExpressionBody() {
270        Foo f = n -> ((Foo)A::method3).m(n);
271        assertTrue(f.m(1) == 4);
272
273        Bar b = n -> { return ((Foo)new A()::method5).m(n); };
274        try {
275            assertTrue(b.m(1) == 6);
276        } catch (Exception e) {
277            assertTrue(false);
278        }
279    }
280
281    public static void main(String[] args) {
282        testAssignment();
283        testMethodArgument();
284        testReturnStatement();
285        testCast();
286        testArrayInitializer();
287        testConditionalExpression(true);
288        testConditionalExpression(false);
289        testLambdaExpressionBody();
290
291        assertTrue(assertionCount == 38);
292    }
293
294    static class MyException extends Exception {}
295
296    static class A {
297
298        int value = 0;
299
300        A() {
301        }
302
303        A(Foo f) {
304            value = f.m(9);
305        }
306
307        A(Bar b) {
308            try {
309                value = b.m(9);
310            } catch (MyException e){}
311        }
312
313        static Integer method1(int n) {
314            return n + 1;
315        }
316
317        int method2(Integer n) {
318            return value == 0 ? n + 2 : n + value;
319        }
320
321        static int method3(int n) {
322            return n + 3;
323        }
324
325        Integer method4(Integer n) {
326            return value == 0 ? n + 4 : n + value;
327        }
328
329        Integer method5(Integer n) {
330            return value == 0 ? new Integer(n + 5) : new Integer(n + value);
331        }
332
333        static int method6(Integer n) throws MyException{
334            throw new MyException();
335        }
336    }
337}
338