1/* 2 * Copyright (c) 2010, 2013, 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 */ 25 26/* 27 * This file is available under and governed by the GNU General Public 28 * License version 2 only, as published by the Free Software Foundation. 29 * However, the following notice accompanied the original version of this 30 * file, and Oracle licenses the original version of this file under the BSD 31 * license: 32 */ 33/* 34 Copyright 2009-2013 Attila Szegedi 35 36 Licensed under both the Apache License, Version 2.0 (the "Apache License") 37 and the BSD License (the "BSD License"), with licensee being free to 38 choose either of the two at their discretion. 39 40 You may not use this file except in compliance with either the Apache 41 License or the BSD License. 42 43 If you choose to use this file in compliance with the Apache License, the 44 following notice applies to you: 45 46 You may obtain a copy of the Apache License at 47 48 http://www.apache.org/licenses/LICENSE-2.0 49 50 Unless required by applicable law or agreed to in writing, software 51 distributed under the License is distributed on an "AS IS" BASIS, 52 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 53 implied. See the License for the specific language governing 54 permissions and limitations under the License. 55 56 If you choose to use this file in compliance with the BSD License, the 57 following notice applies to you: 58 59 Redistribution and use in source and binary forms, with or without 60 modification, are permitted provided that the following conditions are 61 met: 62 * Redistributions of source code must retain the above copyright 63 notice, this list of conditions and the following disclaimer. 64 * Redistributions in binary form must reproduce the above copyright 65 notice, this list of conditions and the following disclaimer in the 66 documentation and/or other materials provided with the distribution. 67 * Neither the name of the copyright holder nor the names of 68 contributors may be used to endorse or promote products derived from 69 this software without specific prior written permission. 70 71 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 72 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82*/ 83 84package jdk.dynalink.beans; 85 86import java.lang.invoke.MethodHandles.Lookup; 87import java.util.Collections; 88import java.util.Set; 89import jdk.dynalink.DynamicLinkerFactory; 90import jdk.dynalink.StandardNamespace; 91import jdk.dynalink.StandardOperation; 92import jdk.dynalink.linker.GuardedInvocation; 93import jdk.dynalink.linker.GuardingDynamicLinker; 94import jdk.dynalink.linker.LinkRequest; 95import jdk.dynalink.linker.LinkerServices; 96import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 97 98/** 99 * A linker for ordinary Java objects. Normally used as the ultimate fallback 100 * linker by the {@link DynamicLinkerFactory} so it is given the chance to link 101 * calls to all objects that no other linker recognized. Specifically, this 102 * linker will: 103 * <ul> 104 * <li>expose all public methods of form {@code setXxx()}, {@code getXxx()}, 105 * and {@code isXxx()} as property setters and getters for 106 * {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the 107 * {@link StandardNamespace#PROPERTY} namespace;</li> 108 * <li>expose all public methods for retrieval for 109 * {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace; 110 * the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}.</li> 111 * <li>expose all public fields as properties, unless there are getters or 112 * setters for the properties of the same name;</li> 113 * <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as 114 * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the 115 * {@link StandardNamespace#ELEMENT} namespace;</li> 116 * <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and 117 * {@link java.util.Map} objects;</li> 118 * <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass} 119 * as calls to constructors, including those static class objects that represent 120 * Java arrays (their constructors take a single {@code int} parameter 121 * representing the length of the array to create);</li> 122 * <li>expose static methods, fields, and properties of classes in a similar 123 * manner to how instance method, fields, and properties are exposed, on 124 * {@link StaticClass} objects.</li> 125 * <li>expose a virtual property named {@code static} on instances of 126 * {@link java.lang.Class} to access their {@link StaticClass}.</li> 127 * </ul> 128 * <p><strong>Overloaded method resolution</strong> is performed automatically 129 * for property setters, methods, and constructors. Additionally, manual 130 * overloaded method selection is supported by having a call site specify a name 131 * for a method that contains an explicit signature, e.g. 132 * {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")} 133 * You can use non-qualified class names in such signatures regardless of those 134 * classes' packages, they will match any class with the same non-qualified name. You 135 * only have to use a fully qualified class name in case non-qualified class 136 * names would cause selection ambiguity (that is extremely rare). Overloaded 137 * resolution for constructors is not automatic as there is no logical place to 138 * attach that functionality to but if a language wishes to provide this 139 * functionality, it can use {@link #getConstructorMethod(Class, String)} as a 140 * useful building block for it.</p> 141 * <p><strong>Variable argument invocation</strong> is handled for both methods 142 * and constructors.</p> 143 * <p><strong>Caller sensitive methods</strong> can be linked as long as they 144 * are otherwise public and link requests have call site descriptors carrying 145 * full-strength {@link Lookup} objects and not weakened lookups or the public 146 * lookup.</p> 147 * <p><strong>The behavior for handling missing members</strong> can be 148 * customized by passing a {@link MissingMemberHandlerFactory} to the 149 * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory) constructor}. 150 * </p> 151 * <p>The class also exposes various methods for discovery of available 152 * property and method names on classes and class instances, as well as access 153 * to per-class linkers using the {@link #getLinkerForClass(Class)} 154 * method.</p> 155 */ 156public class BeansLinker implements GuardingDynamicLinker { 157 private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<TypeBasedGuardingDynamicLinker>() { 158 @Override 159 protected TypeBasedGuardingDynamicLinker computeValue(final Class<?> clazz) { 160 // If ClassValue.put() were public, we could just pre-populate with these known mappings... 161 return 162 clazz == Class.class ? new ClassLinker() : 163 clazz == StaticClass.class ? new StaticClassLinker() : 164 DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() : 165 new BeanLinker(clazz); 166 } 167 }; 168 169 private final MissingMemberHandlerFactory missingMemberHandlerFactory; 170 171 /** 172 * Creates a new beans linker. Equivalent to 173 * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory)} with 174 * {@code null} passed as the missing member handler factory, resulting in 175 * the default behavior for linking and evaluating missing members. 176 */ 177 public BeansLinker() { 178 this(null); 179 } 180 181 /** 182 * Creates a new beans linker with the specified factory for creating 183 * missing member handlers. The passed factory can be null if the default 184 * behavior is adequate. See {@link MissingMemberHandlerFactory} for details. 185 * @param missingMemberHandlerFactory a factory for creating handlers for 186 * operations on missing members. 187 */ 188 public BeansLinker(final MissingMemberHandlerFactory missingMemberHandlerFactory) { 189 this.missingMemberHandlerFactory = missingMemberHandlerFactory; 190 } 191 192 /** 193 * Returns a bean linker for a particular single class. Useful when you need 194 * to override or extend the behavior of linking for some classes in your 195 * language runtime's linker, but still want to delegate to the default 196 * behavior in some cases. 197 * @param clazz the class 198 * @return a bean linker for that class 199 */ 200 public TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) { 201 final TypeBasedGuardingDynamicLinker staticLinker = getStaticLinkerForClass(clazz); 202 if (missingMemberHandlerFactory == null) { 203 return staticLinker; 204 } 205 return new NoSuchMemberHandlerBindingLinker(staticLinker, missingMemberHandlerFactory); 206 } 207 208 private static class NoSuchMemberHandlerBindingLinker implements TypeBasedGuardingDynamicLinker { 209 private final TypeBasedGuardingDynamicLinker linker; 210 private final MissingMemberHandlerFactory missingMemberHandlerFactory; 211 212 NoSuchMemberHandlerBindingLinker(final TypeBasedGuardingDynamicLinker linker, final MissingMemberHandlerFactory missingMemberHandlerFactory) { 213 this.linker = linker; 214 this.missingMemberHandlerFactory = missingMemberHandlerFactory; 215 } 216 217 @Override 218 public boolean canLinkType(final Class<?> type) { 219 return linker.canLinkType(type); 220 } 221 222 @Override 223 public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 224 return linker.getGuardedInvocation(linkRequest, 225 LinkerServicesWithMissingMemberHandlerFactory.get( 226 linkerServices, missingMemberHandlerFactory)); 227 } 228 } 229 230 static TypeBasedGuardingDynamicLinker getStaticLinkerForClass(final Class<?> clazz) { 231 return linkers.get(clazz); 232 } 233 234 /** 235 * Returns true if the object is a Java dynamic method (e.g., one 236 * obtained through a {@code GET:METHOD} operation on a Java object or 237 * {@link StaticClass} or through 238 * {@link #getConstructorMethod(Class, String)}. 239 * 240 * @param obj the object we want to test for being a Java dynamic method. 241 * @return true if it is a dynamic method, false otherwise. 242 */ 243 public static boolean isDynamicMethod(final Object obj) { 244 return obj instanceof DynamicMethod; 245 } 246 247 /** 248 * Returns true if the object is a Java constructor (obtained through 249 * {@link #getConstructorMethod(Class, String)}}. 250 * 251 * @param obj the object we want to test for being a Java constructor. 252 * @return true if it is a constructor, false otherwise. 253 */ 254 public static boolean isDynamicConstructor(final Object obj) { 255 return obj instanceof DynamicMethod && ((DynamicMethod)obj).isConstructor(); 256 } 257 258 /** 259 * Return the dynamic method of constructor of the given class and the given 260 * signature. This method is useful for exposing a functionality for 261 * selecting an overloaded constructor based on an explicit signature, as 262 * this functionality is not otherwise exposed by Dynalink as 263 * {@link StaticClass} objects act as overloaded constructors without 264 * explicit signature selection. Example usage would be: 265 * {@code getConstructorMethod(java.awt.Color.class, "int, int, int")}. 266 * @param clazz the class 267 * @param signature full signature of the constructor. Note how you can use 268 * names of primitive types, array names with normal Java notation (e.g. 269 * {@code "int[]"}), and normally you can even use unqualified class names 270 * (e.g. {@code "String, List"} instead of 271 * {@code "java.lang.String, java.util.List"} as long as they don't cause 272 * ambiguity in the specific parameter position. 273 * @return dynamic method for the constructor or null if no constructor with 274 * the specified signature exists. 275 */ 276 public static Object getConstructorMethod(final Class<?> clazz, final String signature) { 277 return StaticClassLinker.getConstructorMethod(clazz, signature); 278 } 279 280 /** 281 * Returns a set of names of all readable instance properties of a class. 282 * @param clazz the class 283 * @return a set of names of all readable instance properties of a class. 284 */ 285 public static Set<String> getReadableInstancePropertyNames(final Class<?> clazz) { 286 final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); 287 if(linker instanceof BeanLinker) { 288 return ((BeanLinker)linker).getReadablePropertyNames(); 289 } 290 return Collections.emptySet(); 291 } 292 293 /** 294 * Returns a set of names of all writable instance properties of a class. 295 * @param clazz the class 296 * @return a set of names of all writable instance properties of a class. 297 */ 298 public static Set<String> getWritableInstancePropertyNames(final Class<?> clazz) { 299 final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); 300 if(linker instanceof BeanLinker) { 301 return ((BeanLinker)linker).getWritablePropertyNames(); 302 } 303 return Collections.emptySet(); 304 } 305 306 /** 307 * Returns a set of names of all instance methods of a class. 308 * @param clazz the class 309 * @return a set of names of all instance methods of a class. 310 */ 311 public static Set<String> getInstanceMethodNames(final Class<?> clazz) { 312 final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); 313 if(linker instanceof BeanLinker) { 314 return ((BeanLinker)linker).getMethodNames(); 315 } 316 return Collections.emptySet(); 317 } 318 319 /** 320 * Returns a set of names of all readable static properties of a class. 321 * @param clazz the class 322 * @return a set of names of all readable static properties of a class. 323 */ 324 public static Set<String> getReadableStaticPropertyNames(final Class<?> clazz) { 325 return StaticClassLinker.getReadableStaticPropertyNames(clazz); 326 } 327 328 /** 329 * Returns a set of names of all writable static properties of a class. 330 * @param clazz the class 331 * @return a set of names of all writable static properties of a class. 332 */ 333 public static Set<String> getWritableStaticPropertyNames(final Class<?> clazz) { 334 return StaticClassLinker.getWritableStaticPropertyNames(clazz); 335 } 336 337 /** 338 * Returns a set of names of all static methods of a class. 339 * @param clazz the class 340 * @return a set of names of all static methods of a class. 341 */ 342 public static Set<String> getStaticMethodNames(final Class<?> clazz) { 343 return StaticClassLinker.getStaticMethodNames(clazz); 344 } 345 346 @Override 347 public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) 348 throws Exception { 349 final Object receiver = request.getReceiver(); 350 if(receiver == null) { 351 // Can't operate on null 352 return null; 353 } 354 return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, 355 LinkerServicesWithMissingMemberHandlerFactory.get(linkerServices, 356 missingMemberHandlerFactory)); 357 } 358} 359