1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/jdk/internal/dynalink/support/Lookup.java Thu Feb 14 13:22:26 2013 +0100 1.3 @@ -0,0 +1,361 @@ 1.4 +/* 1.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +/* 1.30 + * This file is available under and governed by the GNU General Public 1.31 + * License version 2 only, as published by the Free Software Foundation. 1.32 + * However, the following notice accompanied the original version of this 1.33 + * file, and Oracle licenses the original version of this file under the BSD 1.34 + * license: 1.35 + */ 1.36 +/* 1.37 + Copyright 2009-2013 Attila Szegedi 1.38 + 1.39 + Licensed under both the Apache License, Version 2.0 (the "Apache License") 1.40 + and the BSD License (the "BSD License"), with licensee being free to 1.41 + choose either of the two at their discretion. 1.42 + 1.43 + You may not use this file except in compliance with either the Apache 1.44 + License or the BSD License. 1.45 + 1.46 + If you choose to use this file in compliance with the Apache License, the 1.47 + following notice applies to you: 1.48 + 1.49 + You may obtain a copy of the Apache License at 1.50 + 1.51 + http://www.apache.org/licenses/LICENSE-2.0 1.52 + 1.53 + Unless required by applicable law or agreed to in writing, software 1.54 + distributed under the License is distributed on an "AS IS" BASIS, 1.55 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1.56 + implied. See the License for the specific language governing 1.57 + permissions and limitations under the License. 1.58 + 1.59 + If you choose to use this file in compliance with the BSD License, the 1.60 + following notice applies to you: 1.61 + 1.62 + Redistribution and use in source and binary forms, with or without 1.63 + modification, are permitted provided that the following conditions are 1.64 + met: 1.65 + * Redistributions of source code must retain the above copyright 1.66 + notice, this list of conditions and the following disclaimer. 1.67 + * Redistributions in binary form must reproduce the above copyright 1.68 + notice, this list of conditions and the following disclaimer in the 1.69 + documentation and/or other materials provided with the distribution. 1.70 + * Neither the name of the copyright holder nor the names of 1.71 + contributors may be used to endorse or promote products derived from 1.72 + this software without specific prior written permission. 1.73 + 1.74 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 1.75 + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1.76 + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 1.77 + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 1.78 + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.79 + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.80 + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 1.81 + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 1.82 + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 1.83 + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 1.84 + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.85 +*/ 1.86 + 1.87 +package jdk.internal.dynalink.support; 1.88 + 1.89 +import java.lang.invoke.MethodHandle; 1.90 +import java.lang.invoke.MethodHandles; 1.91 +import java.lang.invoke.MethodType; 1.92 +import java.lang.reflect.Constructor; 1.93 +import java.lang.reflect.Field; 1.94 +import java.lang.reflect.Method; 1.95 +import java.lang.reflect.Modifier; 1.96 + 1.97 +/** 1.98 + * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods 1.99 + * within your own codebase (therefore it is an error if they are not present). 1.100 + * 1.101 + * @author Attila Szegedi 1.102 + */ 1.103 +public class Lookup { 1.104 + private final MethodHandles.Lookup lookup; 1.105 + 1.106 + /** 1.107 + * Creates a new instance, bound to an instance of {@link java.lang.invoke.MethodHandles.Lookup}. 1.108 + * 1.109 + * @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to. 1.110 + */ 1.111 + public Lookup(MethodHandles.Lookup lookup) { 1.112 + this.lookup = lookup; 1.113 + } 1.114 + 1.115 + /** 1.116 + * A canonical Lookup object that wraps {@link MethodHandles#publicLookup()}. 1.117 + */ 1.118 + public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup()); 1.119 + 1.120 + /** 1.121 + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered 1.122 + * {@link IllegalAccessException} into an {@link IllegalAccessError}. 1.123 + * 1.124 + * @param m the method to unreflect 1.125 + * @return the unreflected method handle. 1.126 + */ 1.127 + public MethodHandle unreflect(Method m) { 1.128 + try { 1.129 + return lookup.unreflect(m); 1.130 + } catch(IllegalAccessException e) { 1.131 + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); 1.132 + ee.initCause(e); 1.133 + throw ee; 1.134 + } 1.135 + } 1.136 + 1.137 + 1.138 + /** 1.139 + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered 1.140 + * {@link IllegalAccessException} into an {@link IllegalAccessError}. 1.141 + * 1.142 + * @param f the field for which a getter is unreflected 1.143 + * @return the unreflected field getter handle. 1.144 + */ 1.145 + public MethodHandle unreflectGetter(Field f) { 1.146 + try { 1.147 + return lookup.unreflectGetter(f); 1.148 + } catch(IllegalAccessException e) { 1.149 + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f); 1.150 + ee.initCause(e); 1.151 + throw ee; 1.152 + } 1.153 + } 1.154 + 1.155 + /** 1.156 + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, converting any 1.157 + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and {@link NoSuchFieldException} 1.158 + * into a {@link NoSuchFieldError}. 1.159 + * 1.160 + * @param refc the class declaring the field 1.161 + * @param name the name of the field 1.162 + * @param type the type of the field 1.163 + * @return the unreflected field getter handle. 1.164 + * @throws IllegalAccessError if the field is inaccessible. 1.165 + * @throws NoSuchFieldError if the field does not exist. 1.166 + */ 1.167 + public MethodHandle findGetter(Class<?>refc, String name, Class<?> type) { 1.168 + try { 1.169 + return lookup.findGetter(refc, name, type); 1.170 + } catch(IllegalAccessException e) { 1.171 + final IllegalAccessError ee = new IllegalAccessError("Failed to access getter for field " + refc.getName() + 1.172 + "." + name + " of type " + type.getName()); 1.173 + ee.initCause(e); 1.174 + throw ee; 1.175 + } catch(NoSuchFieldException e) { 1.176 + final NoSuchFieldError ee = new NoSuchFieldError("Failed to find getter for field " + refc.getName() + 1.177 + "." + name + " of type " + type.getName()); 1.178 + ee.initCause(e); 1.179 + throw ee; 1.180 + } 1.181 + } 1.182 + 1.183 + /** 1.184 + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered 1.185 + * {@link IllegalAccessException} into an {@link IllegalAccessError}. 1.186 + * 1.187 + * @param f the field for which a setter is unreflected 1.188 + * @return the unreflected field setter handle. 1.189 + */ 1.190 + public MethodHandle unreflectSetter(Field f) { 1.191 + try { 1.192 + return lookup.unreflectSetter(f); 1.193 + } catch(IllegalAccessException e) { 1.194 + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f); 1.195 + ee.initCause(e); 1.196 + throw ee; 1.197 + } 1.198 + } 1.199 + 1.200 + /** 1.201 + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any 1.202 + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. 1.203 + * 1.204 + * @param c the constructor to unreflect 1.205 + * @return the unreflected constructor handle. 1.206 + */ 1.207 + public MethodHandle unreflectConstructor(Constructor<?> c) { 1.208 + try { 1.209 + return lookup.unreflectConstructor(c); 1.210 + } catch(IllegalAccessException e) { 1.211 + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c); 1.212 + ee.initCause(e); 1.213 + throw ee; 1.214 + } 1.215 + } 1.216 + 1.217 + /** 1.218 + * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts 1.219 + * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a 1.220 + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 1.221 + * 1.222 + * @param declaringClass class declaring the method 1.223 + * @param name the name of the method 1.224 + * @param type the type of the method 1.225 + * @return a method handle for the method 1.226 + * @throws IllegalAccessError if the method is inaccessible. 1.227 + * @throws NoSuchMethodError if the method does not exist. 1.228 + */ 1.229 + public MethodHandle findSpecial(Class<?> declaringClass, String name, MethodType type) { 1.230 + try { 1.231 + if(Backport.inUse) { 1.232 + final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); 1.233 + if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { 1.234 + m.setAccessible(true); 1.235 + } 1.236 + return unreflect(m); 1.237 + } else { 1.238 + return lookup.findSpecial(declaringClass, name, type, declaringClass); 1.239 + } 1.240 + } catch(IllegalAccessException e) { 1.241 + final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( 1.242 + declaringClass, name, type)); 1.243 + ee.initCause(e); 1.244 + throw ee; 1.245 + } catch(NoSuchMethodException e) { 1.246 + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find special method " + methodDescription( 1.247 + declaringClass, name, type)); 1.248 + ee.initCause(e); 1.249 + throw ee; 1.250 + } 1.251 + } 1.252 + 1.253 + private static String methodDescription(Class<?> declaringClass, String name, MethodType type) { 1.254 + return declaringClass.getName() + "#" + name + type; 1.255 + } 1.256 + 1.257 + /** 1.258 + * Performs a findStatic on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an 1.259 + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 1.260 + * 1.261 + * @param declaringClass class declaring the method 1.262 + * @param name the name of the method 1.263 + * @param type the type of the method 1.264 + * @return a method handle for the method 1.265 + * @throws IllegalAccessError if the method is inaccessible. 1.266 + * @throws NoSuchMethodError if the method does not exist. 1.267 + */ 1.268 + public MethodHandle findStatic(Class<?> declaringClass, String name, MethodType type) { 1.269 + try { 1.270 + return lookup.findStatic(declaringClass, name, type); 1.271 + } catch(IllegalAccessException e) { 1.272 + final IllegalAccessError ee = new IllegalAccessError("Failed to access static method " + methodDescription( 1.273 + declaringClass, name, type)); 1.274 + ee.initCause(e); 1.275 + throw ee; 1.276 + } catch(NoSuchMethodException e) { 1.277 + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find static method " + methodDescription( 1.278 + declaringClass, name, type)); 1.279 + ee.initCause(e); 1.280 + throw ee; 1.281 + } 1.282 + } 1.283 + 1.284 + /** 1.285 + * Performs a findVirtual on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an 1.286 + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. 1.287 + * 1.288 + * @param declaringClass class declaring the method 1.289 + * @param name the name of the method 1.290 + * @param type the type of the method 1.291 + * @return a method handle for the method 1.292 + * @throws IllegalAccessError if the method is inaccessible. 1.293 + * @throws NoSuchMethodError if the method does not exist. 1.294 + */ 1.295 + public MethodHandle findVirtual(Class<?> declaringClass, String name, MethodType type) { 1.296 + try { 1.297 + return lookup.findVirtual(declaringClass, name, type); 1.298 + } catch(IllegalAccessException e) { 1.299 + final IllegalAccessError ee = new IllegalAccessError("Failed to access virtual method " + methodDescription( 1.300 + declaringClass, name, type)); 1.301 + ee.initCause(e); 1.302 + throw ee; 1.303 + } catch(NoSuchMethodException e) { 1.304 + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find virtual method " + methodDescription( 1.305 + declaringClass, name, type)); 1.306 + ee.initCause(e); 1.307 + throw ee; 1.308 + } 1.309 + } 1.310 + 1.311 + /** 1.312 + * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. 1.313 + * Useful in classes' code for convenient linking to their own privates. 1.314 + * @param lookup the lookup for the class 1.315 + * @param name the name of the method 1.316 + * @param rtype the return type of the method 1.317 + * @param ptypes the parameter types of the method 1.318 + * @return the method handle for the method 1.319 + */ 1.320 + public static MethodHandle findOwnSpecial(MethodHandles.Lookup lookup, String name, Class<?> rtype, Class<?>... ptypes) { 1.321 + return new Lookup(lookup).findOwnSpecial(name, rtype, ptypes); 1.322 + } 1.323 + 1.324 + 1.325 + /** 1.326 + * Finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. Useful in classes' 1.327 + * code for convenient linking to their own privates. It's easier to use than {@code findSpecial} in that you can 1.328 + * just list the parameter types, and don't have to specify lookup class. 1.329 + * @param name the name of the method 1.330 + * @param rtype the return type of the method 1.331 + * @param ptypes the parameter types of the method 1.332 + * @return the method handle for the method 1.333 + */ 1.334 + public MethodHandle findOwnSpecial(String name, Class<?> rtype, Class<?>... ptypes) { 1.335 + return findSpecial(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); 1.336 + } 1.337 + 1.338 + /** 1.339 + * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. 1.340 + * Useful in classes' code for convenient linking to their own privates. It's easier to use than {@code findStatic} 1.341 + * in that you can just list the parameter types, and don't have to specify lookup class. 1.342 + * @param lookup the lookup for the class 1.343 + * @param name the name of the method 1.344 + * @param rtype the return type of the method 1.345 + * @param ptypes the parameter types of the method 1.346 + * @return the method handle for the method 1.347 + */ 1.348 + public static MethodHandle findOwnStatic(MethodHandles.Lookup lookup, String name, Class<?> rtype, Class<?>... ptypes) { 1.349 + return new Lookup(lookup).findOwnStatic(name, rtype, ptypes); 1.350 + } 1.351 + 1.352 + /** 1.353 + * Finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. Useful in classes' 1.354 + * code for convenient linking to their own privates. It's easier to use than {@code findStatic} in that you can 1.355 + * just list the parameter types, and don't have to specify lookup class. 1.356 + * @param name the name of the method 1.357 + * @param rtype the return type of the method 1.358 + * @param ptypes the parameter types of the method 1.359 + * @return the method handle for the method 1.360 + */ 1.361 + public MethodHandle findOwnStatic(String name, Class<?> rtype, Class<?>... ptypes) { 1.362 + return findStatic(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); 1.363 + } 1.364 +}