BeansLinkerTest.java revision 1551:f3b883bec2d0
1/*
2 * Copyright (c) 2015, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package jdk.dynalink.beans.test;
26
27import static jdk.dynalink.StandardOperation.CALL;
28import static jdk.dynalink.StandardOperation.GET_ELEMENT;
29import static jdk.dynalink.StandardOperation.GET_METHOD;
30import static jdk.dynalink.StandardOperation.GET_PROPERTY;
31import static jdk.dynalink.StandardOperation.SET_ELEMENT;
32import static jdk.dynalink.StandardOperation.SET_PROPERTY;
33
34import java.lang.invoke.MethodHandles;
35import java.lang.invoke.MethodType;
36import java.util.Collections;
37import java.util.HashMap;
38import java.util.Map;
39import java.util.function.Consumer;
40import java.util.function.Predicate;
41import java.util.regex.Pattern;
42import java.util.stream.Stream;
43import jdk.dynalink.CallSiteDescriptor;
44import jdk.dynalink.CompositeOperation;
45import jdk.dynalink.DynamicLinkerFactory;
46import jdk.dynalink.NamedOperation;
47import jdk.dynalink.Operation;
48import jdk.dynalink.StandardOperation;
49import jdk.dynalink.support.SimpleRelinkableCallSite;
50import org.testng.Assert;
51import org.testng.annotations.Test;
52
53public class BeansLinkerTest {
54    public static class Bean1 {
55        public final int answer = 42;
56
57        public String getName() {
58            return "bean1";
59        }
60
61        public String someMethod(final String x) {
62            return x + "-foo";
63        }
64    }
65
66    @Test
67    public static void testPublicFieldPropertyUnnamedGetter() {
68        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
69    }
70
71    @Test
72    public static void testPublicFieldPropertyNamedGetter() {
73        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(named("answer", op), new Bean1())));
74    }
75
76    @Test
77    public static void testGetterPropertyUnnamedGetter() {
78        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
79    }
80
81    @Test
82    public static void testGetterPropertyNamedGetter() {
83        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(named("name", op), new Bean1())));
84    }
85
86    @Test
87    public static void testMethodUnnamedGetter() {
88        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
89    }
90
91    @Test
92    public static void testMethodNamedGetter() {
93        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(named("someMethod", op), new Bean1()), new Bean1(), "bar")));
94    }
95
96    private static final Map<String, String> MAP1 = new HashMap<>();
97    static {
98        MAP1.put("foo", "bar");
99    }
100
101    @Test
102    public static void testElementUnnamedGetter() {
103        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
104    }
105
106    @Test
107    public static void testElementNamedGetter() {
108        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(named("foo", op), MAP1)));
109    }
110
111    public static class Bean2 {
112        public int answer;
113        private String name;
114
115        public void setName(final String name) {
116            this.name = name;
117        }
118    }
119
120    @Test
121    public static void testUnnamedFieldSetter() {
122        testSetterPermutations(SET_PROPERTY, (op) -> {
123            final Bean2 bean2 = new Bean2();
124            call(op, bean2, "answer", 12);
125            Assert.assertEquals(bean2.answer, 12);
126        });
127    }
128
129    @Test
130    public static void testNamedFieldSetter() {
131        testSetterPermutations(SET_PROPERTY, (op) -> {
132            final Bean2 bean2 = new Bean2();
133            call(named("answer", op), bean2, 14);
134            Assert.assertEquals(bean2.answer, 14);
135        });
136    }
137
138    @Test
139    public static void testUnnamedPropertySetter() {
140        testSetterPermutations(SET_PROPERTY, (op) -> {
141            final Bean2 bean2 = new Bean2();
142            call(op, bean2, "name", "boo");
143            Assert.assertEquals(bean2.name, "boo");
144        });
145    }
146
147    @Test
148    public static void testNamedPropertySetter() {
149        testSetterPermutations(SET_PROPERTY, (op) -> {
150            final Bean2 bean2 = new Bean2();
151            call(named("name", op), bean2, "blah");
152            Assert.assertEquals(bean2.name, "blah");
153        });
154    }
155
156    private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*GET_ELEMENT.*GET_PROPERTY.*");
157
158    @Test
159    public static void testUnnamedElementAndPropertyGetter() {
160        final Map<String, Object> map = new HashMap<>();
161        map.put("empty", true);
162        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op, map, "empty")));
163    }
164
165    @Test
166    public static void testNamedElementAndPropertyGetter() {
167        final Map<String, Object> map = new HashMap<>();
168        map.put("empty", true);
169        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(named("empty", op), map)));
170    }
171
172    private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*GET_PROPERTY.*GET_ELEMENT.*");
173
174    @Test
175    public static void testUnnamedPropertyAndElementGetter() {
176        final Map<String, Object> map = new HashMap<>();
177        map.put("empty", true);
178        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op, map, "empty")));
179    }
180
181    @Test
182    public static void testNamedPropertyAndElementGetter() {
183        final Map<String, Object> map = new HashMap<>();
184        map.put("empty", true);
185        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(named("empty", op), map)));
186    }
187
188    public static class MapWithProperty extends HashMap<String, Object> {
189        private String name;
190
191        public void setName(final String name) {
192            this.name = name;
193        }
194    }
195
196    @Test
197    public static void testUnnamedPropertyAndElementSetter() {
198        final MapWithProperty map = new MapWithProperty();
199        map.put("name", "element");
200
201        call(ops(SET_PROPERTY, SET_ELEMENT), map, "name", "property");
202        Assert.assertEquals("property", map.name);
203        Assert.assertEquals("element", map.get("name"));
204
205        call(ops(SET_ELEMENT, SET_PROPERTY), map, "name", "element2");
206        Assert.assertEquals("property", map.name);
207        Assert.assertEquals("element2", map.get("name"));
208    }
209
210    private static Operation[] GETTER_PERMUTATIONS = new Operation[] {
211        GET_PROPERTY,
212        GET_METHOD,
213        GET_ELEMENT,
214        ops(GET_PROPERTY, GET_ELEMENT),
215        ops(GET_PROPERTY, GET_METHOD),
216        ops(GET_ELEMENT,  GET_PROPERTY),
217        ops(GET_ELEMENT,  GET_METHOD),
218        ops(GET_METHOD,   GET_PROPERTY),
219        ops(GET_METHOD,   GET_ELEMENT),
220        ops(GET_PROPERTY, GET_ELEMENT,  GET_METHOD),
221        ops(GET_PROPERTY, GET_METHOD,   GET_ELEMENT),
222        ops(GET_ELEMENT,  GET_PROPERTY, GET_METHOD),
223        ops(GET_ELEMENT,  GET_METHOD,   GET_PROPERTY),
224        ops(GET_METHOD,   GET_PROPERTY, GET_ELEMENT),
225        ops(GET_METHOD,   GET_ELEMENT,  GET_PROPERTY),
226    };
227
228    private static Operation[] SETTER_PERMUTATIONS = new Operation[] {
229        SET_PROPERTY,
230        SET_ELEMENT,
231        ops(SET_PROPERTY, SET_ELEMENT),
232        ops(SET_ELEMENT,  SET_PROPERTY)
233    };
234
235    private static void testPermutations(final Operation[] ops, final StandardOperation requiredOp, final int expectedCount, final Consumer<Operation> test) {
236        testPermutationsWithFilter(ops, (op)->CompositeOperation.contains(op, requiredOp), expectedCount, test);
237    }
238
239    private static void testPermutations(final Operation[] ops, final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
240        testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
241    }
242
243    private static void testPermutationsWithFilter(final Operation[] ops, final Predicate<Operation> filter, final int expectedCount, final Consumer<Operation> test) {
244        final int[] counter = new int[1];
245        Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
246        Assert.assertEquals(counter[0], expectedCount);
247    }
248
249    private static void testGetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
250        testPermutations(GETTER_PERMUTATIONS, requiredOp, 11, test);
251    }
252
253    private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
254        testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test);
255    }
256
257    private static void testSetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
258        testPermutations(SETTER_PERMUTATIONS, requiredOp, 3, test);
259    }
260
261    private static Object call(final Operation op, final Object... args) {
262        try {
263            return new DynamicLinkerFactory().createLinker().link(
264                    new SimpleRelinkableCallSite(new CallSiteDescriptor(
265                            MethodHandles.publicLookup(), op, t(args.length))))
266                            .dynamicInvoker().invokeWithArguments(args);
267        } catch (final Error|RuntimeException e) {
268            throw e;
269        } catch (final Throwable t) {
270            throw new RuntimeException(t);
271        }
272    }
273
274    private static Object call(final Object... args) {
275        return call(CALL, args);
276    }
277
278    private static Operation named(final Object name, final Operation... ops) {
279        return new NamedOperation(ops(ops), name);
280    }
281
282    private static Operation ops(final Operation... ops) {
283        return ops.length == 1 ? ops[0] : new CompositeOperation(ops);
284    }
285
286    private static MethodType t(final int argCount) {
287        return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class));
288    }
289}
290