SamConversion.java revision 1434:9b26c96f5138
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
138    /**
139     * Test SAM conversion of method reference in method/constructor argument context
140     */
141    private static void testMethodArgument() {
142        assertTrue(test1(A::method1) == 2);
143        assertTrue(test1(new A()::method2) == 3);
144        assertTrue(test1(A::method3) == 4);
145        assertTrue(test1(new A()::method4) == 5);
146        assertTrue(test1(new A()::method5) == 6);
147        test2(A::method1, 2);
148        test2(new A()::method2, 3);
149        test2(A::method3, 4);
150        test2(new A()::method4, 5);
151        test2(new A()::method5, 6);
152        A a = new A(A::method1); //A(Foo f) called
153        assertTrue(a.method2(1) == 11);
154        assertTrue(a.method4(1) == 11);
155        assertTrue(a.method5(1) == 11);
156        A a2 = new A(new A()::method2); //A(Bar b) called
157        assertTrue(a2.method2(1) == 12);
158        assertTrue(a2.method4(1) == 12);
159        assertTrue(a2.method5(1) == 12);
160    }
161
162    /**
163     * Test SAM conversion of method reference in return statement context
164     */
165    private static void testReturnStatement() {
166        Bar bar = test3(0);
167        try {
168            assertTrue(bar.m(1) == 2);
169        } catch (Exception e) {
170            assertTrue(false);
171        }
172        bar = test3(1);
173        try {
174            assertTrue(bar.m(1) == 3);
175        } catch (Exception e) {
176            assertTrue(false);
177        }
178        bar = test3(2);
179        try {
180            assertTrue(bar.m(1) == 4);
181        } catch (Exception e) {
182            assertTrue(false);
183        }
184        bar = test3(3);
185        try {
186            assertTrue(bar.m(1) == 5);
187        } catch (Exception e) {
188            assertTrue(false);
189        }
190        bar = test3(4);
191        try {
192            assertTrue(bar.m(1) == 6);
193        } catch (Exception e) {
194            assertTrue(false);
195        }
196        bar = test3(5);
197        try {
198            bar.m(1);
199            assertTrue(false);
200        } catch (MyException e) {
201        } catch (Exception e) {
202            assertTrue(false);
203        }
204    }
205
206    /**
207     * Test SAM conversion of method reference in cast context
208     */
209    private static void testCast() {
210        assertTrue(((Foo)A::method1).m(1) == 2);
211        try {
212            assertTrue(((Bar)new A()::method2).m(1) == 3);
213        } catch (Exception e) {
214            assertTrue(false);
215        }
216    }
217
218    /**
219     * Test SAM conversion of method reference in array initializer context
220     */
221    private static void testArrayInitializer() {
222        Object[] oarray = {"a", 1, (Foo)A::method3}; //last element need a cast
223        Object[] oarray2 = {"a", 1, (Bar)new A()::method4}; //last element need a cast
224        Foo[] farray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5};
225        Bar[] barray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5, A::method6};
226    }
227
228    /**
229     * Test SAM conversion of method reference in conditional expression context
230     */
231    private static void testConditionalExpression(boolean b) {
232        Foo f = b ? A::method3 : new A()::method5;
233        if(b)
234            assertTrue(f.m(1) == 4);
235        else
236            assertTrue(f.m(1) == 6);
237
238        Bar bar = b ? A::method1 : A::method6;
239        if(b) {
240            try {
241                assertTrue(bar.m(1) == 2);
242            } catch (Exception e) {
243                assertTrue(false);
244            }
245        }
246        else {
247            try {
248                bar.m(1);
249                assertTrue(false);
250            } catch (MyException e) {
251            } catch (Exception e) {
252                assertTrue(false);
253            }
254        }
255    }
256
257    /**
258     * Test SAM conversion of method reference in lambda expression body
259     */
260    private static void testLambdaExpressionBody() {
261        Foo f = n -> ((Foo)A::method3).m(n);
262        assertTrue(f.m(1) == 4);
263
264        Bar b = n -> { return ((Foo)new A()::method5).m(n); };
265        try {
266            assertTrue(b.m(1) == 6);
267        } catch (Exception e) {
268            assertTrue(false);
269        }
270    }
271
272    public static void main(String[] args) {
273        testAssignment();
274        testMethodArgument();
275        testReturnStatement();
276        testCast();
277        testArrayInitializer();
278        testConditionalExpression(true);
279        testConditionalExpression(false);
280        testLambdaExpressionBody();
281
282        assertTrue(assertionCount == 38);
283    }
284
285    static class MyException extends Exception {}
286
287    static class A {
288
289        int value = 0;
290
291        A() {
292        }
293
294        A(Foo f) {
295            value = f.m(9);
296        }
297
298        A(Bar b) {
299            try {
300                value = b.m(9);
301            } catch (MyException e){}
302        }
303
304        static Integer method1(int n) {
305            return n + 1;
306        }
307
308        int method2(Integer n) {
309            return value == 0 ? n + 2 : n + value;
310        }
311
312        static int method3(int n) {
313            return n + 3;
314        }
315
316        Integer method4(Integer n) {
317            return value == 0 ? n + 4 : n + value;
318        }
319
320        Integer method5(Integer n) {
321            return value == 0 ? new Integer(n + 5) : new Integer(n + value);
322        }
323
324        static int method6(Integer n) throws MyException{
325            throw new MyException();
326        }
327    }
328}
329