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