Lookup.java revision 1894:48d8835e3aaa
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.linker.support; 85 86import java.lang.invoke.MethodHandle; 87import java.lang.invoke.MethodHandles; 88import java.lang.invoke.MethodType; 89import java.lang.reflect.Constructor; 90import java.lang.reflect.Executable; 91import java.lang.reflect.Field; 92import java.lang.reflect.Method; 93 94/** 95 * A wrapper around {@link java.lang.invoke.MethodHandles.Lookup} that masks 96 * checked exceptions. It is useful in those cases when you're looking up 97 * methods within your own codebase (therefore it is an error if they are not 98 * present). 99 */ 100public final class Lookup { 101 private final MethodHandles.Lookup lookup; 102 103 /** 104 * Creates a new instance, bound to an instance of 105 * {@link java.lang.invoke.MethodHandles.Lookup}. 106 * 107 * @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to. 108 */ 109 public Lookup(final MethodHandles.Lookup lookup) { 110 this.lookup = lookup; 111 } 112 113 /** 114 * A canonical Lookup object that wraps {@link MethodHandles#publicLookup()}. 115 */ 116 public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup()); 117 118 /** 119 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, 120 * converting any encountered {@link IllegalAccessException} into an 121 * {@link IllegalAccessError}. 122 * 123 * @param m the method to unreflect 124 * @return the unreflected method handle. 125 * @throws IllegalAccessError if the method is inaccessible. 126 */ 127 public MethodHandle unreflect(final Method m) { 128 return unreflect(lookup, m); 129 } 130 131 /** 132 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, 133 * converting any encountered {@link IllegalAccessException} into an 134 * {@link IllegalAccessError}. 135 * 136 * @param lookup the lookup used to unreflect 137 * @param m the method to unreflect 138 * @return the unreflected method handle. 139 * @throws IllegalAccessError if the method is inaccessible. 140 */ 141 public static MethodHandle unreflect(final MethodHandles.Lookup lookup, final Method m) { 142 try { 143 return lookup.unreflect(m); 144 } catch(final IllegalAccessException e) { 145 final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); 146 ee.initCause(e); 147 throw ee; 148 } 149 } 150 151 /** 152 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, 153 * converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. 154 * 155 * @param f the field for which a getter is unreflected 156 * @return the unreflected field getter handle. 157 * @throws IllegalAccessError if the getter is inaccessible. 158 */ 159 public MethodHandle unreflectGetter(final Field f) { 160 try { 161 return lookup.unreflectGetter(f); 162 } catch(final IllegalAccessException e) { 163 final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f); 164 ee.initCause(e); 165 throw ee; 166 } 167 } 168 169 /** 170 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, 171 * converting any encountered {@link IllegalAccessException} into an 172 * {@link IllegalAccessError} and {@link NoSuchFieldException} into a 173 * {@link NoSuchFieldError}. 174 * 175 * @param refc the class declaring the field 176 * @param name the name of the field 177 * @param type the type of the field 178 * @return the unreflected field getter handle. 179 * @throws IllegalAccessError if the field is inaccessible. 180 * @throws NoSuchFieldError if the field does not exist. 181 */ 182 public MethodHandle findGetter(final Class<?>refc, final String name, final Class<?> type) { 183 try { 184 return lookup.findGetter(refc, name, type); 185 } catch(final IllegalAccessException e) { 186 final IllegalAccessError ee = new IllegalAccessError("Failed to access getter for field " + refc.getName() + 187 "." + name + " of type " + type.getName()); 188 ee.initCause(e); 189 throw ee; 190 } catch(final NoSuchFieldException e) { 191 final NoSuchFieldError ee = new NoSuchFieldError("Failed to find getter for field " + refc.getName() + 192 "." + name + " of type " + type.getName()); 193 ee.initCause(e); 194 throw ee; 195 } 196 } 197 198 /** 199 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, 200 * converting any encountered {@link IllegalAccessException} into an 201 * {@link IllegalAccessError}. 202 * 203 * @param f the field for which a setter is unreflected 204 * @return the unreflected field setter handle. 205 * @throws IllegalAccessError if the field is inaccessible. 206 * @throws NoSuchFieldError if the field does not exist. 207 */ 208 public MethodHandle unreflectSetter(final Field f) { 209 try { 210 return lookup.unreflectSetter(f); 211 } catch(final IllegalAccessException e) { 212 final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f); 213 ee.initCause(e); 214 throw ee; 215 } 216 } 217 218 /** 219 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, 220 * converting any encountered {@link IllegalAccessException} into an 221 * {@link IllegalAccessError}. 222 * 223 * @param c the constructor to unreflect 224 * @return the unreflected constructor handle. 225 * @throws IllegalAccessError if the constructor is inaccessible. 226 */ 227 public MethodHandle unreflectConstructor(final Constructor<?> c) { 228 return unreflectConstructor(lookup, c); 229 } 230 231 /** 232 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, 233 * converting any encountered {@link IllegalAccessException} into an 234 * {@link IllegalAccessError}. 235 * 236 * @param lookup the lookup used to unreflect 237 * @param c the constructor to unreflect 238 * @return the unreflected constructor handle. 239 * @throws IllegalAccessError if the constructor is inaccessible. 240 */ 241 public static MethodHandle unreflectConstructor(final MethodHandles.Lookup lookup, final Constructor<?> c) { 242 try { 243 return lookup.unreflectConstructor(c); 244 } catch(final IllegalAccessException e) { 245 final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c); 246 ee.initCause(e); 247 throw ee; 248 } 249 } 250 251 /** 252 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findSpecial(Class, String, MethodType, Class)} 253 * on the underlying lookup. Converts any encountered 254 * {@link IllegalAccessException} into an {@link IllegalAccessError} and 255 * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 256 * 257 * @param declaringClass class declaring the method 258 * @param name the name of the method 259 * @param type the type of the method 260 * @return a method handle for the method 261 * @throws IllegalAccessError if the method is inaccessible. 262 * @throws NoSuchMethodError if the method does not exist. 263 */ 264 public MethodHandle findSpecial(final Class<?> declaringClass, final String name, final MethodType type) { 265 try { 266 return lookup.findSpecial(declaringClass, name, type, declaringClass); 267 } catch(final IllegalAccessException e) { 268 final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( 269 declaringClass, name, type)); 270 ee.initCause(e); 271 throw ee; 272 } catch(final NoSuchMethodException e) { 273 final NoSuchMethodError ee = new NoSuchMethodError("Failed to find special method " + methodDescription( 274 declaringClass, name, type)); 275 ee.initCause(e); 276 throw ee; 277 } 278 } 279 280 private static String methodDescription(final Class<?> declaringClass, final String name, final MethodType type) { 281 return declaringClass.getName() + "#" + name + type; 282 } 283 284 /** 285 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findStatic(Class, String, MethodType)} 286 * on the underlying lookup. Converts any encountered 287 * {@link IllegalAccessException} into an {@link IllegalAccessError} and 288 * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 289 * 290 * @param declaringClass class declaring the method 291 * @param name the name of the method 292 * @param type the type of the method 293 * @return a method handle for the method 294 * @throws IllegalAccessError if the method is inaccessible. 295 * @throws NoSuchMethodError if the method does not exist. 296 */ 297 public MethodHandle findStatic(final Class<?> declaringClass, final String name, final MethodType type) { 298 try { 299 return lookup.findStatic(declaringClass, name, type); 300 } catch(final IllegalAccessException e) { 301 final IllegalAccessError ee = new IllegalAccessError("Failed to access static method " + methodDescription( 302 declaringClass, name, type)); 303 ee.initCause(e); 304 throw ee; 305 } catch(final NoSuchMethodException e) { 306 final NoSuchMethodError ee = new NoSuchMethodError("Failed to find static method " + methodDescription( 307 declaringClass, name, type)); 308 ee.initCause(e); 309 throw ee; 310 } 311 } 312 313 /** 314 * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findVirtual(Class, String, MethodType)} 315 * on the underlying lookup. Converts any encountered 316 * {@link IllegalAccessException} into an {@link IllegalAccessError} and 317 * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 318 * 319 * @param declaringClass class declaring the method 320 * @param name the name of the method 321 * @param type the type of the method 322 * @return a method handle for the method 323 * @throws IllegalAccessError if the method is inaccessible. 324 * @throws NoSuchMethodError if the method does not exist. 325 */ 326 public MethodHandle findVirtual(final Class<?> declaringClass, final String name, final MethodType type) { 327 try { 328 return lookup.findVirtual(declaringClass, name, type); 329 } catch(final IllegalAccessException e) { 330 final IllegalAccessError ee = new IllegalAccessError("Failed to access virtual method " + methodDescription( 331 declaringClass, name, type)); 332 ee.initCause(e); 333 throw ee; 334 } catch(final NoSuchMethodException e) { 335 final NoSuchMethodError ee = new NoSuchMethodError("Failed to find virtual method " + methodDescription( 336 declaringClass, name, type)); 337 ee.initCause(e); 338 throw ee; 339 } 340 } 341 342 /** 343 * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} 344 * a method on that lookup's class. Useful in classes' code for convenient 345 * linking to their own privates. 346 * @param lookup the lookup for the class 347 * @param name the name of the method 348 * @param rtype the return type of the method 349 * @param ptypes the parameter types of the method 350 * @return the method handle for the method 351 */ 352 public static MethodHandle findOwnSpecial(final MethodHandles.Lookup lookup, final String name, final Class<?> rtype, final Class<?>... ptypes) { 353 return new Lookup(lookup).findOwnSpecial(name, rtype, ptypes); 354 } 355 356 357 /** 358 * Finds using {@link #findSpecial(Class, String, MethodType)} a method on 359 * that lookup's class. Useful in classes' code for convenient linking to 360 * their own privates. It's also more convenient than {@code findSpecial} 361 * in that you can just list the parameter types, and don't have to specify 362 * lookup class. 363 * @param name the name of the method 364 * @param rtype the return type of the method 365 * @param ptypes the parameter types of the method 366 * @return the method handle for the method 367 */ 368 public MethodHandle findOwnSpecial(final String name, final Class<?> rtype, final Class<?>... ptypes) { 369 return findSpecial(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); 370 } 371 372 /** 373 * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} 374 * a method on that lookup's class. Useful in classes' code for convenient 375 * linking to their own privates. It's easier to use than {@code findStatic} 376 * in that you can just list the parameter types, and don't have to specify 377 * lookup class. 378 * @param lookup the lookup for the class 379 * @param name the name of the method 380 * @param rtype the return type of the method 381 * @param ptypes the parameter types of the method 382 * @return the method handle for the method 383 */ 384 public static MethodHandle findOwnStatic(final MethodHandles.Lookup lookup, final String name, final Class<?> rtype, final Class<?>... ptypes) { 385 return new Lookup(lookup).findOwnStatic(name, rtype, ptypes); 386 } 387 388 /** 389 * Finds using {@link #findStatic(Class, String, MethodType)} a method on 390 * that lookup's class. Useful in classes' code for convenient linking to 391 * their own privates. It's easier to use than {@code findStatic} 392 * in that you can just list the parameter types, and don't have to specify 393 * lookup class. 394 * @param name the name of the method 395 * @param rtype the return type of the method 396 * @param ptypes the parameter types of the method 397 * @return the method handle for the method 398 */ 399 public MethodHandle findOwnStatic(final String name, final Class<?> rtype, final Class<?>... ptypes) { 400 return findStatic(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); 401 } 402} 403