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