BeansLinkerTest.java revision 1551:f3b883bec2d0
1100966Siwasaki/*
2100966Siwasaki * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3100966Siwasaki * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4100966Siwasaki *
5100966Siwasaki * This code is free software; you can redistribute it and/or modify it
6100966Siwasaki * under the terms of the GNU General Public License version 2 only, as
7217365Sjkim * published by the Free Software Foundation.  Oracle designates this
8245582Sjkim * particular file as subject to the "Classpath" exception as provided
9100966Siwasaki * by Oracle in the LICENSE file that accompanied this code.
10100966Siwasaki *
11217365Sjkim * This code is distributed in the hope that it will be useful, but WITHOUT
12217365Sjkim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13217365Sjkim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14217365Sjkim * version 2 for more details (a copy is included in the LICENSE file that
15217365Sjkim * accompanied this code).
16217365Sjkim *
17217365Sjkim * You should have received a copy of the GNU General Public License version
18217365Sjkim * 2 along with this work; if not, write to the Free Software Foundation,
19217365Sjkim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20217365Sjkim *
21217365Sjkim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22217365Sjkim * or visit www.oracle.com if you need additional information or have any
23217365Sjkim * questions.
24217365Sjkim */
25100966Siwasakipackage jdk.dynalink.beans.test;
26217365Sjkim
27217365Sjkimimport static jdk.dynalink.StandardOperation.CALL;
28217365Sjkimimport static jdk.dynalink.StandardOperation.GET_ELEMENT;
29100966Siwasakiimport static jdk.dynalink.StandardOperation.GET_METHOD;
30217365Sjkimimport static jdk.dynalink.StandardOperation.GET_PROPERTY;
31217365Sjkimimport static jdk.dynalink.StandardOperation.SET_ELEMENT;
32217365Sjkimimport static jdk.dynalink.StandardOperation.SET_PROPERTY;
33217365Sjkim
34217365Sjkimimport java.lang.invoke.MethodHandles;
35217365Sjkimimport java.lang.invoke.MethodType;
36217365Sjkimimport java.util.Collections;
37217365Sjkimimport java.util.HashMap;
38217365Sjkimimport java.util.Map;
39217365Sjkimimport java.util.function.Consumer;
40217365Sjkimimport java.util.function.Predicate;
41217365Sjkimimport java.util.regex.Pattern;
42217365Sjkimimport java.util.stream.Stream;
43100966Siwasakiimport jdk.dynalink.CallSiteDescriptor;
44100966Siwasakiimport jdk.dynalink.CompositeOperation;
45100966Siwasakiimport jdk.dynalink.DynamicLinkerFactory;
46100966Siwasakiimport jdk.dynalink.NamedOperation;
47193341Sjkimimport jdk.dynalink.Operation;
48100966Siwasakiimport jdk.dynalink.StandardOperation;
49100966Siwasakiimport jdk.dynalink.support.SimpleRelinkableCallSite;
50100966Siwasakiimport org.testng.Assert;
51100966Siwasakiimport org.testng.annotations.Test;
52100966Siwasaki
53100966Siwasakipublic class BeansLinkerTest {
54167802Sjkim    public static class Bean1 {
55100966Siwasaki        public final int answer = 42;
56217365Sjkim
57217365Sjkim        public String getName() {
58217365Sjkim            return "bean1";
59217365Sjkim        }
60217365Sjkim
61128212Snjl        public String someMethod(final String x) {
62217365Sjkim            return x + "-foo";
63167802Sjkim        }
64167802Sjkim    }
65167802Sjkim
66229989Sjkim    @Test
67167802Sjkim    public static void testPublicFieldPropertyUnnamedGetter() {
68209746Sjkim        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
69100966Siwasaki    }
70167802Sjkim
71100966Siwasaki    @Test
72209746Sjkim    public static void testPublicFieldPropertyNamedGetter() {
73209746Sjkim        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(named("answer", op), new Bean1())));
74209746Sjkim    }
75209746Sjkim
76209746Sjkim    @Test
77209746Sjkim    public static void testGetterPropertyUnnamedGetter() {
78209746Sjkim        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
79209746Sjkim    }
80209746Sjkim
81167802Sjkim    @Test
82167802Sjkim    public static void testGetterPropertyNamedGetter() {
83228110Sjkim        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(named("name", op), new Bean1())));
84228110Sjkim    }
85167802Sjkim
86228110Sjkim    @Test
87228110Sjkim    public static void testMethodUnnamedGetter() {
88228110Sjkim        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
89167802Sjkim    }
90228110Sjkim
91228110Sjkim    @Test
92228110Sjkim    public static void testMethodNamedGetter() {
93228110Sjkim        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(named("someMethod", op), new Bean1()), new Bean1(), "bar")));
94228110Sjkim    }
95228110Sjkim
96228110Sjkim    private static final Map<String, String> MAP1 = new HashMap<>();
97228110Sjkim    static {
98228110Sjkim        MAP1.put("foo", "bar");
99228110Sjkim    }
100228110Sjkim
101228110Sjkim    @Test
102228110Sjkim    public static void testElementUnnamedGetter() {
103228110Sjkim        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
104228110Sjkim    }
105228110Sjkim
106228110Sjkim    @Test
107228110Sjkim    public static void testElementNamedGetter() {
108228110Sjkim        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(named("foo", op), MAP1)));
109228110Sjkim    }
110228110Sjkim
111252279Sjkim    public static class Bean2 {
112228110Sjkim        public int answer;
113228110Sjkim        private String name;
114228110Sjkim
115228110Sjkim        public void setName(final String name) {
116228110Sjkim            this.name = name;
117228110Sjkim        }
118228110Sjkim    }
119228110Sjkim
120228110Sjkim    @Test
121228110Sjkim    public static void testUnnamedFieldSetter() {
122228110Sjkim        testSetterPermutations(SET_PROPERTY, (op) -> {
123228110Sjkim            final Bean2 bean2 = new Bean2();
124228110Sjkim            call(op, bean2, "answer", 12);
125228110Sjkim            Assert.assertEquals(bean2.answer, 12);
126228110Sjkim        });
127228110Sjkim    }
128228110Sjkim
129228110Sjkim    @Test
130228110Sjkim    public static void testNamedFieldSetter() {
131228110Sjkim        testSetterPermutations(SET_PROPERTY, (op) -> {
132228110Sjkim            final Bean2 bean2 = new Bean2();
133228110Sjkim            call(named("answer", op), bean2, 14);
134228110Sjkim            Assert.assertEquals(bean2.answer, 14);
135228110Sjkim        });
136228110Sjkim    }
137228110Sjkim
138228110Sjkim    @Test
139228110Sjkim    public static void testUnnamedPropertySetter() {
140228110Sjkim        testSetterPermutations(SET_PROPERTY, (op) -> {
141228110Sjkim            final Bean2 bean2 = new Bean2();
142228110Sjkim            call(op, bean2, "name", "boo");
143228110Sjkim            Assert.assertEquals(bean2.name, "boo");
144228110Sjkim        });
145228110Sjkim    }
146228110Sjkim
147228110Sjkim    @Test
148228110Sjkim    public static void testNamedPropertySetter() {
149228110Sjkim        testSetterPermutations(SET_PROPERTY, (op) -> {
150228110Sjkim            final Bean2 bean2 = new Bean2();
151228110Sjkim            call(named("name", op), bean2, "blah");
152228110Sjkim            Assert.assertEquals(bean2.name, "blah");
153228110Sjkim        });
154228110Sjkim    }
155228110Sjkim
156228110Sjkim    private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*GET_ELEMENT.*GET_PROPERTY.*");
157228110Sjkim
158228110Sjkim    @Test
159228110Sjkim    public static void testUnnamedElementAndPropertyGetter() {
160228110Sjkim        final Map<String, Object> map = new HashMap<>();
161167802Sjkim        map.put("empty", true);
162193267Sjkim        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op, map, "empty")));
163167802Sjkim    }
164167802Sjkim
165209746Sjkim    @Test
166209746Sjkim    public static void testNamedElementAndPropertyGetter() {
167209746Sjkim        final Map<String, Object> map = new HashMap<>();
168209746Sjkim        map.put("empty", true);
169167802Sjkim        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(named("empty", op), map)));
170167802Sjkim    }
171167802Sjkim
172193267Sjkim    private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*GET_PROPERTY.*GET_ELEMENT.*");
173193267Sjkim
174209746Sjkim    @Test
175209746Sjkim    public static void testUnnamedPropertyAndElementGetter() {
176167802Sjkim        final Map<String, Object> map = new HashMap<>();
177167802Sjkim        map.put("empty", true);
178167802Sjkim        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op, map, "empty")));
179167802Sjkim    }
180167802Sjkim
181100966Siwasaki    @Test
182100966Siwasaki    public static void testNamedPropertyAndElementGetter() {
183100966Siwasaki        final Map<String, Object> map = new HashMap<>();
184167802Sjkim        map.put("empty", true);
185167802Sjkim        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(named("empty", op), map)));
186100966Siwasaki    }
187167802Sjkim
188151937Sjkim    public static class MapWithProperty extends HashMap<String, Object> {
189100966Siwasaki        private String name;
190100966Siwasaki
191100966Siwasaki        public void setName(final String name) {
192209746Sjkim            this.name = name;
193209746Sjkim        }
194209746Sjkim    }
195209746Sjkim
196100966Siwasaki    @Test
197100966Siwasaki    public static void testUnnamedPropertyAndElementSetter() {
198100966Siwasaki        final MapWithProperty map = new MapWithProperty();
199100966Siwasaki        map.put("name", "element");
200100966Siwasaki
201209746Sjkim        call(ops(SET_PROPERTY, SET_ELEMENT), map, "name", "property");
202209746Sjkim        Assert.assertEquals("property", map.name);
203100966Siwasaki        Assert.assertEquals("element", map.get("name"));
204228110Sjkim
205228110Sjkim        call(ops(SET_ELEMENT, SET_PROPERTY), map, "name", "element2");
206228110Sjkim        Assert.assertEquals("property", map.name);
207228110Sjkim        Assert.assertEquals("element2", map.get("name"));
208228110Sjkim    }
209209746Sjkim
210167802Sjkim    private static Operation[] GETTER_PERMUTATIONS = new Operation[] {
211167802Sjkim        GET_PROPERTY,
212167802Sjkim        GET_METHOD,
213167802Sjkim        GET_ELEMENT,
214100966Siwasaki        ops(GET_PROPERTY, GET_ELEMENT),
215167802Sjkim        ops(GET_PROPERTY, GET_METHOD),
216167802Sjkim        ops(GET_ELEMENT,  GET_PROPERTY),
217167802Sjkim        ops(GET_ELEMENT,  GET_METHOD),
218167802Sjkim        ops(GET_METHOD,   GET_PROPERTY),
219167802Sjkim        ops(GET_METHOD,   GET_ELEMENT),
220167802Sjkim        ops(GET_PROPERTY, GET_ELEMENT,  GET_METHOD),
221167802Sjkim        ops(GET_PROPERTY, GET_METHOD,   GET_ELEMENT),
222167802Sjkim        ops(GET_ELEMENT,  GET_PROPERTY, GET_METHOD),
223167802Sjkim        ops(GET_ELEMENT,  GET_METHOD,   GET_PROPERTY),
224167802Sjkim        ops(GET_METHOD,   GET_PROPERTY, GET_ELEMENT),
225167802Sjkim        ops(GET_METHOD,   GET_ELEMENT,  GET_PROPERTY),
226167802Sjkim    };
227167802Sjkim
228167802Sjkim    private static Operation[] SETTER_PERMUTATIONS = new Operation[] {
229167802Sjkim        SET_PROPERTY,
230167802Sjkim        SET_ELEMENT,
231167802Sjkim        ops(SET_PROPERTY, SET_ELEMENT),
232167802Sjkim        ops(SET_ELEMENT,  SET_PROPERTY)
233167802Sjkim    };
234167802Sjkim
235193267Sjkim    private static void testPermutations(final Operation[] ops, final StandardOperation requiredOp, final int expectedCount, final Consumer<Operation> test) {
236228110Sjkim        testPermutationsWithFilter(ops, (op)->CompositeOperation.contains(op, requiredOp), expectedCount, test);
237167802Sjkim    }
238167802Sjkim
239239340Sjkim    private static void testPermutations(final Operation[] ops, final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
240239340Sjkim        testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
241245582Sjkim    }
242239340Sjkim
243239340Sjkim    private static void testPermutationsWithFilter(final Operation[] ops, final Predicate<Operation> filter, final int expectedCount, final Consumer<Operation> test) {
244239340Sjkim        final int[] counter = new int[1];
245239340Sjkim        Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
246239340Sjkim        Assert.assertEquals(counter[0], expectedCount);
247167802Sjkim    }
248167802Sjkim
249167802Sjkim    private static void testGetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
250167802Sjkim        testPermutations(GETTER_PERMUTATIONS, requiredOp, 11, test);
251167802Sjkim    }
252167802Sjkim
253193267Sjkim    private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
254197104Sjkim        testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test);
255228110Sjkim    }
256167802Sjkim
257193267Sjkim    private static void testSetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
258193267Sjkim        testPermutations(SETTER_PERMUTATIONS, requiredOp, 3, test);
259193267Sjkim    }
260209746Sjkim
261167802Sjkim    private static Object call(final Operation op, final Object... args) {
262167802Sjkim        try {
263167802Sjkim            return new DynamicLinkerFactory().createLinker().link(
264193267Sjkim                    new SimpleRelinkableCallSite(new CallSiteDescriptor(
265228110Sjkim                            MethodHandles.publicLookup(), op, t(args.length))))
266228110Sjkim                            .dynamicInvoker().invokeWithArguments(args);
267228110Sjkim        } catch (final Error|RuntimeException e) {
268228110Sjkim            throw e;
269228110Sjkim        } catch (final Throwable t) {
270167802Sjkim            throw new RuntimeException(t);
271228110Sjkim        }
272167802Sjkim    }
273193267Sjkim
274193267Sjkim    private static Object call(final Object... args) {
275193267Sjkim        return call(CALL, args);
276197104Sjkim    }
277193267Sjkim
278193267Sjkim    private static Operation named(final Object name, final Operation... ops) {
279193267Sjkim        return new NamedOperation(ops(ops), name);
280193267Sjkim    }
281193267Sjkim
282197104Sjkim    private static Operation ops(final Operation... ops) {
283167802Sjkim        return ops.length == 1 ? ops[0] : new CompositeOperation(ops);
284197104Sjkim    }
285197104Sjkim
286197104Sjkim    private static MethodType t(final int argCount) {
287197104Sjkim        return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class));
288197104Sjkim    }
289197104Sjkim}
290197104Sjkim