2009-05-05 22:40:09 -07:00
/ *
2013-02-26 11:05:26 +00:00
* Copyright ( c ) 2008 , 2013 , Oracle and / or its affiliates . All rights reserved .
2009-05-05 22:40:09 -07:00
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
2010-05-25 15:58:33 -07:00
* published by the Free Software Foundation . Oracle designates this
2009-05-05 22:40:09 -07:00
* particular file as subject to the " Classpath " exception as provided
2010-05-25 15:58:33 -07:00
* by Oracle in the LICENSE file that accompanied this code .
2009-05-05 22:40:09 -07:00
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
2010-05-25 15:58:33 -07:00
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
2009-05-05 22:40:09 -07:00
* /
2011-03-23 23:02:31 -07:00
package java.lang.invoke ;
2009-05-05 22:40:09 -07:00
2010-09-08 18:40:34 -07:00
import java.lang.reflect.* ;
2010-01-07 16:16:45 -08:00
import java.util.List ;
2009-05-05 22:40:09 -07:00
import java.util.ArrayList ;
import java.util.Arrays ;
2013-05-08 12:09:35 -07:00
2013-04-16 21:39:52 -07:00
import sun.invoke.util.ValueConversions ;
import sun.invoke.util.VerifyAccess ;
import sun.invoke.util.Wrapper ;
import sun.reflect.CallerSensitive ;
2009-05-05 22:40:09 -07:00
import sun.reflect.Reflection ;
2013-05-08 12:09:35 -07:00
import sun.reflect.misc.ReflectUtil ;
2013-04-16 21:39:52 -07:00
import sun.security.util.SecurityConstants ;
2011-03-23 23:02:31 -07:00
import static java.lang.invoke.MethodHandleStatics.* ;
2011-06-01 23:56:47 -07:00
import static java.lang.invoke.MethodHandleNatives.Constants.* ;
2013-10-05 05:30:38 -07:00
import java.util.concurrent.ConcurrentHashMap ;
2013-07-02 15:58:09 -07:00
import sun.security.util.SecurityConstants ;
2009-05-05 22:40:09 -07:00
/ * *
2010-04-30 23:48:23 -07:00
* This class consists exclusively of static methods that operate on or return
* method handles . They fall into several categories :
2010-01-07 16:16:45 -08:00
* < ul >
2011-02-11 01:26:28 -08:00
* < li > Lookup methods which help create method handles for methods and fields .
* < li > Combinator methods , which combine or transform pre - existing method handles into new ones .
* < li > Other factory methods to create method handles that emulate other common JVM operations or control flow patterns .
2011-03-23 23:02:31 -07:00
* < li > Wrapper methods which can convert between method handles and interface types .
2010-01-07 16:16:45 -08:00
* < / ul >
2009-05-05 22:40:09 -07:00
* < p >
* @author John Rose , JSR 292 EG
2013-09-03 21:42:56 -07:00
* @since 1 . 7
2009-05-05 22:40:09 -07:00
* /
public class MethodHandles {
private MethodHandles ( ) { } // do not instantiate
2011-03-18 00:03:24 -07:00
private static final MemberName . Factory IMPL_NAMES = MemberName . getFactory ( ) ;
2009-05-05 22:40:09 -07:00
static { MethodHandleImpl . initStatics ( ) ; }
// See IMPL_LOOKUP below.
//// Method handle creation from ordinary methods.
2010-04-30 23:48:23 -07:00
/ * *
2011-03-23 23:02:31 -07:00
* Returns a { @link Lookup lookup object } on the caller ,
2010-04-30 23:48:23 -07:00
* which has the capability to access any method handle that the caller has access to ,
* including direct method handles to private fields and methods .
* This lookup object is a < em > capability < / em > which may be delegated to trusted agents .
* Do not store it in place where untrusted code can access it .
2013-06-27 19:02:02 -07:00
* @return a lookup object for the caller of this method
2010-01-07 16:16:45 -08:00
* /
2013-04-16 21:39:52 -07:00
@CallerSensitive
2009-05-05 22:40:09 -07:00
public static Lookup lookup ( ) {
2013-04-16 21:39:52 -07:00
return new Lookup ( Reflection . getCallerClass ( ) ) ;
2009-05-05 22:40:09 -07:00
}
2010-04-30 23:48:23 -07:00
/ * *
2011-03-23 23:02:31 -07:00
* Returns a { @link Lookup lookup object } which is trusted minimally .
2010-04-30 23:48:23 -07:00
* It can only be used to create method handles to
* publicly accessible fields and methods .
2010-09-08 18:40:23 -07:00
* < p >
* As a matter of pure convention , the { @linkplain Lookup # lookupClass lookup class }
* of this lookup object will be { @link java . lang . Object } .
* < p >
* The lookup class can be changed to any other class { @ code C } using an expression of the form
* { @linkplain Lookup # in < code > publicLookup ( ) . in ( C . class ) < / code > } .
* Since all classes have equal access to public names ,
* such a change would confer no new access rights .
2013-06-27 19:02:02 -07:00
* @return a lookup object which is trusted minimally
2010-01-07 16:16:45 -08:00
* /
public static Lookup publicLookup ( ) {
return Lookup . PUBLIC_LOOKUP ;
}
2013-09-03 21:42:56 -07:00
/ * *
* Performs an unchecked " crack " of a direct method handle .
* The result is as if the user had obtained a lookup object capable enough
* to crack the target method handle , called
* { @link java . lang . invoke . MethodHandles . Lookup # revealDirect Lookup . revealDirect }
* on the target to obtain its symbolic reference , and then called
* { @link java . lang . invoke . MethodHandleInfo # reflectAs MethodHandleInfo . reflectAs }
* to resolve the symbolic reference to a member .
* < p >
* If there is a security manager , its { @code checkPermission } method
* is called with a { @code ReflectPermission ( " suppressAccessChecks " ) } permission .
* @param < T > the desired type of the result , either { @link Member } or a subtype
* @param target a direct method handle to crack into symbolic reference components
* @param expected a class object representing the desired result type { @code T }
* @return a reference to the method , constructor , or field object
* @exception SecurityException if the caller is not privileged to call { @code setAccessible }
* @exception NullPointerException if either argument is { @code null }
* @exception IllegalArgumentException if the target is not a direct method handle
* @exception ClassCastException if the member is not of the expected type
* @since 1 . 8
* /
public static < T extends Member > T
reflectAs ( Class < T > expected , MethodHandle target ) {
SecurityManager smgr = System . getSecurityManager ( ) ;
if ( smgr ! = null ) smgr . checkPermission ( ACCESS_PERMISSION ) ;
Lookup lookup = Lookup . IMPL_LOOKUP ; // use maximally privileged lookup
return lookup . revealDirect ( target ) . reflectAs ( expected , lookup ) ;
}
// Copied from AccessibleObject, as used by Method.setAccessible, etc.:
static final private java . security . Permission ACCESS_PERMISSION =
new ReflectPermission ( " suppressAccessChecks " ) ;
2009-05-05 22:40:09 -07:00
/ * *
2010-04-30 23:48:23 -07:00
* A < em > lookup object < / em > is a factory for creating method handles ,
* when the creation requires access checking .
* Method handles do not perform
2010-09-08 18:40:23 -07:00
* access checks when they are called , but rather when they are created .
2010-04-30 23:48:23 -07:00
* Therefore , method handle access
* restrictions must be enforced when a method handle is created .
2009-05-05 22:40:09 -07:00
* The caller class against which those restrictions are enforced
2010-04-30 23:48:23 -07:00
* is known as the { @linkplain # lookupClass lookup class } .
2011-02-11 01:26:28 -08:00
* < p >
* A lookup class which needs to create method handles will call
* { @link MethodHandles # lookup MethodHandles . lookup } to create a factory for itself .
* When the { @code Lookup } factory object is created , the identity of the lookup class is
* determined , and securely stored in the { @code Lookup } object .
* The lookup class ( or its delegates ) may then use factory methods
* on the { @code Lookup } object to create method handles for access - checked members .
* This includes all methods , constructors , and fields which are allowed to the lookup class ,
* even private ones .
2013-06-27 19:02:02 -07:00
*
* < h1 > < a name = " lookups " > < / a > Lookup Factory Methods < / h1 >
2011-02-11 01:26:28 -08:00
* The factory methods on a { @code Lookup } object correspond to all major
* use cases for methods , constructors , and fields .
* Here is a summary of the correspondence between these factory methods and
* the behavior the resulting method handles :
* < table border = 1 cellpadding = 5 summary = " lookup method behaviors " >
* < tr > < th > lookup expression < / th > < th > member < / th > < th > behavior < / th > < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findGetter lookup . findGetter ( C . class , " f " , FT . class ) } < / td >
* < td > { @code FT f ; } < / td > < td > { @code ( T ) this . f ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findStaticGetter lookup . findStaticGetter ( C . class , " f " , FT . class ) } < / td >
* < td > { @code static } < br > { @code FT f ; } < / td > < td > { @code ( T ) C . f ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findSetter lookup . findSetter ( C . class , " f " , FT . class ) } < / td >
* < td > { @code FT f ; } < / td > < td > { @code this . f = x ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findStaticSetter lookup . findStaticSetter ( C . class , " f " , FT . class ) } < / td >
* < td > { @code static } < br > { @code FT f ; } < / td > < td > { @code C . f = arg ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findVirtual lookup . findVirtual ( C . class , " m " , MT ) } < / td >
* < td > { @code T m ( A * ) ; } < / td > < td > { @code ( T ) this . m ( arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findStatic lookup . findStatic ( C . class , " m " , MT ) } < / td >
* < td > { @code static } < br > { @code T m ( A * ) ; } < / td > < td > { @code ( T ) C . m ( arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findSpecial lookup . findSpecial ( C . class , " m " , MT , this . class ) } < / td >
* < td > { @code T m ( A * ) ; } < / td > < td > { @code ( T ) super . m ( arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # findConstructor lookup . findConstructor ( C . class , MT ) } < / td >
* < td > { @code C ( A * ) ; } < / td > < td > { @code new C ( arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # unreflectGetter lookup . unreflectGetter ( aField ) } < / td >
* < td > ( { @code static } ) ? < br > { @code FT f ; } < / td > < td > { @code ( FT ) aField . get ( thisOrNull ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # unreflectSetter lookup . unreflectSetter ( aField ) } < / td >
* < td > ( { @code static } ) ? < br > { @code FT f ; } < / td > < td > { @code aField . set ( thisOrNull , arg ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # unreflect lookup . unreflect ( aMethod ) } < / td >
* < td > ( { @code static } ) ? < br > { @code T m ( A * ) ; } < / td > < td > { @code ( T ) aMethod . invoke ( thisOrNull , arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # unreflectConstructor lookup . unreflectConstructor ( aConstructor ) } < / td >
* < td > { @code C ( A * ) ; } < / td > < td > { @code ( C ) aConstructor . newInstance ( arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < tr >
2013-06-27 19:02:02 -07:00
* < td > { @link java . lang . invoke . MethodHandles . Lookup # unreflect lookup . unreflect ( aMethod ) } < / td >
* < td > ( { @code static } ) ? < br > { @code T m ( A * ) ; } < / td > < td > { @code ( T ) aMethod . invoke ( thisOrNull , arg * ) ; } < / td >
2011-02-11 01:26:28 -08:00
* < / tr >
* < / table >
2013-06-27 19:02:02 -07:00
*
2011-02-11 01:26:28 -08:00
* Here , the type { @code C } is the class or interface being searched for a member ,
* documented as a parameter named { @code refc } in the lookup methods .
2013-06-27 19:02:02 -07:00
* The method type { @code MT } is composed from the return type { @code T }
2011-02-11 01:26:28 -08:00
* and the sequence of argument types { @code A * } .
2013-06-27 19:02:02 -07:00
* The constructor also has a sequence of argument types { @code A * } and
* is deemed to return the newly - created object of type { @code C } .
2011-02-11 01:26:28 -08:00
* Both { @code MT } and the field type { @code FT } are documented as a parameter named { @code type } .
* The formal parameter { @code this } stands for the self - reference of type { @code C } ;
* if it is present , it is always the leading argument to the method handle invocation .
2012-07-24 10:47:44 -07:00
* ( In the case of some { @code protected } members , { @code this } may be
* restricted in type to the lookup class ; see below . )
2011-02-11 01:26:28 -08:00
* The name { @code arg } stands for all the other method handle arguments .
* In the code examples for the Core Reflection API , the name { @code thisOrNull }
* stands for a null reference if the accessed method or field is static ,
* and { @code this } otherwise .
* The names { @code aMethod } , { @code aField } , and { @code aConstructor } stand
* for reflective objects corresponding to the given members .
* < p >
2011-05-26 17:37:36 -07:00
* In cases where the given member is of variable arity ( i . e . , a method or constructor )
* the returned method handle will also be of { @linkplain MethodHandle # asVarargsCollector variable arity } .
* In all other cases , the returned method handle will be of fixed arity .
* < p >
2011-02-11 01:26:28 -08:00
* The equivalence between looked - up method handles and underlying
* class members can break down in a few ways :
* < ul >
* < li > If { @code C } is not symbolically accessible from the lookup class ' s loader ,
* the lookup can still succeed , even when there is no equivalent
* Java expression or bytecoded constant .
* < li > Likewise , if { @code T } or { @code MT }
* is not symbolically accessible from the lookup class ' s loader ,
* the lookup can still succeed .
* For example , lookups for { @code MethodHandle . invokeExact } and
2011-05-12 19:27:33 -07:00
* { @code MethodHandle . invoke } will always succeed , regardless of requested type .
2011-02-15 00:16:53 -08:00
* < li > If there is a security manager installed , it can forbid the lookup
* on various grounds ( < a href = " #secmgr " > see below < / a > ) .
* By contrast , the { @code ldc } instruction is not subject to
* security manager checks .
2013-10-05 05:30:39 -07:00
* < li > If the looked - up method has a
* < a href = " MethodHandle.html#maxarity " > very large arity < / a > ,
* the method handle creation may fail , due to the method handle
* type having too many parameters .
2011-02-11 01:26:28 -08:00
* < / ul >
*
2013-06-27 19:02:02 -07:00
* < h1 > < a name = " access " > < / a > Access checking < / h1 >
2011-02-11 01:26:28 -08:00
* Access checks are applied in the factory methods of { @code Lookup } ,
* when a method handle is created .
* This is a key difference from the Core Reflection API , since
2011-05-26 17:37:36 -07:00
* { @link java . lang . reflect . Method # invoke java . lang . reflect . Method . invoke }
2011-02-11 01:26:28 -08:00
* performs access checking against every caller , on every call .
* < p >
* All access checks start from a { @code Lookup } object , which
* compares its recorded lookup class against all requests to
* create method handles .
* A single { @code Lookup } object can be used to create any number
2009-05-05 22:40:09 -07:00
* of access - checked method handles , all checked against a single
* lookup class .
* < p >
2011-02-11 01:26:28 -08:00
* A { @code Lookup } object can be shared with other trusted code ,
* such as a metaobject protocol .
* A shared { @code Lookup } object delegates the capability
* to create method handles on private members of the lookup class .
* Even if privileged code uses the { @code Lookup } object ,
* the access checking is confined to the privileges of the
* original lookup class .
2009-05-05 22:40:09 -07:00
* < p >
2010-04-30 23:48:23 -07:00
* A lookup can fail , because
2009-05-05 22:40:09 -07:00
* the containing class is not accessible to the lookup class , or
* because the desired class member is missing , or because the
* desired class member is not accessible to the lookup class .
2011-02-11 01:26:32 -08:00
* In any of these cases , a { @code ReflectiveOperationException } will be
* thrown from the attempted lookup . The exact class will be one of
* the following :
* < ul >
* < li > NoSuchMethodException & mdash ; if a method is requested but does not exist
* < li > NoSuchFieldException & mdash ; if a field is requested but does not exist
* < li > IllegalAccessException & mdash ; if the member exists but an access check fails
* < / ul >
2010-09-08 18:40:23 -07:00
* < p >
2009-05-05 22:40:09 -07:00
* In general , the conditions under which a method handle may be
2011-02-11 01:26:28 -08:00
* looked up for a method { @code M } are exactly equivalent to the conditions
* under which the lookup class could have compiled and resolved a call to { @code M } .
* And the effect of invoking the method handle resulting from the lookup
* is exactly equivalent to executing the compiled and resolved call to { @code M } .
2011-02-11 01:26:24 -08:00
* The same point is true of fields and constructors .
2010-10-30 21:08:23 -07:00
* < p >
2012-07-24 10:47:44 -07:00
* If the desired member is { @code protected } , the usual JVM rules apply ,
* including the requirement that the lookup class must be either be in the
* same package as the desired member , or must inherit that member .
* ( See the Java Virtual Machine Specification , sections 4 . 9 . 2 , 5 . 4 . 3 . 5 , and 6 . 4 . )
* In addition , if the desired member is a non - static field or method
* in a different package , the resulting method handle may only be applied
* to objects of the lookup class or one of its subclasses .
* This requirement is enforced by narrowing the type of the leading
* { @code this } parameter from { @code C }
* ( which will necessarily be a superclass of the lookup class )
* to the lookup class itself .
* < p >
2011-02-11 01:26:28 -08:00
* In some cases , access between nested classes is obtained by the Java compiler by creating
2010-09-08 18:40:23 -07:00
* an wrapper method to access a private method of another class
* in the same top - level declaration .
2010-10-30 21:08:23 -07:00
* For example , a nested class { @ code C . D }
2010-09-08 18:40:23 -07:00
* can access private members within other related classes such as
2010-10-30 21:08:23 -07:00
* { @code C } , { @code C . D . E } , or { @code C . B } ,
* but the Java compiler may need to generate wrapper methods in
* those related classes . In such cases , a { @code Lookup } object on
* { @code C . E } would be unable to those private members .
* A workaround for this limitation is the { @link Lookup # in Lookup . in } method ,
* which can transform a lookup on { @code C . E } into one on any of those other
* classes , without special elevation of privilege .
2011-02-11 01:26:28 -08:00
* < p >
2011-02-15 00:16:53 -08:00
* Although bytecode instructions can only refer to classes in
* a related class loader , this API can search for methods in any
* class , as long as a reference to its { @code Class } object is
* available . Such cross - loader references are also possible with the
* Core Reflection API , and are impossible to bytecode instructions
* such as { @code invokestatic } or { @code getfield } .
* There is a { @linkplain java . lang . SecurityManager security manager API }
* to allow applications to check such cross - loader references .
* These checks apply to both the { @code MethodHandles . Lookup } API
* and the Core Reflection API
* ( as found on { @link java . lang . Class Class } ) .
* < p >
2011-02-11 01:26:28 -08:00
* Access checks only apply to named and reflected methods ,
* constructors , and fields .
* Other method handle creation methods , such as
2011-05-26 17:37:36 -07:00
* { @link MethodHandle # asType MethodHandle . asType } ,
2011-02-11 01:26:28 -08:00
* do not require any access checks , and are done
* with static methods of { @link MethodHandles } ,
* independently of any { @code Lookup } object .
2011-02-15 00:16:53 -08:00
*
2013-06-27 19:02:02 -07:00
* < h1 > Security manager interactions < / h1 >
2011-02-15 00:16:53 -08:00
* < a name = " secmgr " > < / a >
* If a security manager is present , member lookups are subject to
* additional checks .
2013-07-02 15:58:09 -07:00
* From one to three calls are made to the security manager .
2011-02-15 00:16:53 -08:00
* Any of these calls can refuse access by throwing a
* { @link java . lang . SecurityException SecurityException } .
* Define { @code smgr } as the security manager ,
2013-07-02 15:58:09 -07:00
* { @code lookc } as the lookup class of the current lookup object ,
2011-02-15 00:16:53 -08:00
* { @code refc } as the containing class in which the member
* is being sought , and { @code defc } as the class in which the
* member is actually defined .
2013-07-02 15:58:09 -07:00
* The value { @code lookc } is defined as < em > not present < / em >
* if the current lookup object does not have
* { @linkplain java . lang . invoke . MethodHandles . Lookup # PRIVATE private access } .
2011-02-15 00:16:53 -08:00
* The calls are made according to the following rules :
* < ul >
2013-07-02 15:58:09 -07:00
* < li > If { @code lookc } is not present , or if its class loader is not
2011-02-15 00:16:53 -08:00
* the same as or an ancestor of the class loader of { @code refc } ,
* then { @link SecurityManager # checkPackageAccess
* smgr . checkPackageAccess ( refcPkg ) } is called ,
* where { @code refcPkg } is the package of { @code refc } .
2013-07-02 15:58:09 -07:00
* < li > If the retrieved member is not public and
* { @code lookc } is not present , then
* { @link SecurityManager # checkPermission smgr . checkPermission }
* with { @code RuntimePermission ( " accessDeclaredMembers " ) } is called .
2011-02-15 00:16:53 -08:00
* < li > If the retrieved member is not public ,
2013-07-02 15:58:09 -07:00
* and if { @code defc } and { @code refc } are different ,
2011-02-15 00:16:53 -08:00
* then { @link SecurityManager # checkPackageAccess
* smgr . checkPackageAccess ( defcPkg ) } is called ,
* where { @code defcPkg } is the package of { @code defc } .
* < / ul >
2009-05-05 22:40:09 -07:00
* /
2012-09-20 14:02:55 -07:00
// FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle
2009-05-05 22:40:09 -07:00
public static final
class Lookup {
2010-04-30 23:48:23 -07:00
/** The class on behalf of whom the lookup is being performed. */
2009-05-05 22:40:09 -07:00
private final Class < ? > lookupClass ;
2010-12-16 15:59:27 -08:00
/** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
2010-04-30 23:48:23 -07:00
private final int allowedModes ;
2010-12-16 15:59:27 -08:00
/ * * A single - bit mask representing { @code public } access ,
* which may contribute to the result of { @link # lookupModes lookupModes } .
* The value , { @code 0x01 } , happens to be the same as the value of the
* { @code public } { @linkplain java . lang . reflect . Modifier # PUBLIC modifier bit } .
* /
public static final int PUBLIC = Modifier . PUBLIC ;
/ * * A single - bit mask representing { @code private } access ,
* which may contribute to the result of { @link # lookupModes lookupModes } .
* The value , { @code 0x02 } , happens to be the same as the value of the
* { @code private } { @linkplain java . lang . reflect . Modifier # PRIVATE modifier bit } .
* /
public static final int PRIVATE = Modifier . PRIVATE ;
/ * * A single - bit mask representing { @code protected } access ,
* which may contribute to the result of { @link # lookupModes lookupModes } .
* The value , { @code 0x04 } , happens to be the same as the value of the
* { @code protected } { @linkplain java . lang . reflect . Modifier # PROTECTED modifier bit } .
* /
public static final int PROTECTED = Modifier . PROTECTED ;
/ * * A single - bit mask representing { @code package } access ( default access ) ,
* which may contribute to the result of { @link # lookupModes lookupModes } .
* The value is { @code 0x08 } , which does not correspond meaningfully to
* any particular { @linkplain java . lang . reflect . Modifier modifier bit } .
* /
public static final int PACKAGE = Modifier . STATIC ;
private static final int ALL_MODES = ( PUBLIC | PRIVATE | PROTECTED | PACKAGE ) ;
private static final int TRUSTED = - 1 ;
2010-04-30 23:48:23 -07:00
private static int fixmods ( int mods ) {
mods & = ( ALL_MODES - PACKAGE ) ;
return ( mods ! = 0 ) ? mods : PACKAGE ;
}
2011-02-11 01:26:28 -08:00
/ * * Tells which class is performing the lookup . It is this class against
2009-05-05 22:40:09 -07:00
* which checks are performed for visibility and access permissions .
* < p >
2010-09-08 18:40:23 -07:00
* The class implies a maximum level of access permission ,
* but the permissions may be additionally limited by the bitmask
2011-02-11 01:26:28 -08:00
* { @link # lookupModes lookupModes } , which controls whether non - public members
2010-09-08 18:40:23 -07:00
* can be accessed .
2013-06-27 19:02:02 -07:00
* @return the lookup class , on behalf of which this lookup object finds members
2009-05-05 22:40:09 -07:00
* /
public Class < ? > lookupClass ( ) {
return lookupClass ;
}
2010-04-30 23:48:23 -07:00
// This is just for calling out to MethodHandleImpl.
private Class < ? > lookupClassOrNull ( ) {
return ( allowedModes = = TRUSTED ) ? null : lookupClass ;
}
2011-02-11 01:26:28 -08:00
/ * * Tells which access - protection classes of members this lookup object can produce .
2010-12-16 15:59:27 -08:00
* The result is a bit - mask of the bits
* { @linkplain # PUBLIC PUBLIC ( 0x01 ) } ,
* { @linkplain # PRIVATE PRIVATE ( 0x02 ) } ,
* { @linkplain # PROTECTED PROTECTED ( 0x04 ) } ,
* and { @linkplain # PACKAGE PACKAGE ( 0x08 ) } .
2010-10-30 21:08:23 -07:00
* < p >
* A freshly - created lookup object
2011-03-23 23:02:31 -07:00
* on the { @linkplain java . lang . invoke . MethodHandles # lookup ( ) caller ' s class }
2010-10-30 21:08:23 -07:00
* has all possible bits set , since the caller class can access all its own members .
* A lookup object on a new lookup class
2011-03-23 23:02:31 -07:00
* { @linkplain java . lang . invoke . MethodHandles . Lookup # in created from a previous lookup object }
2010-10-30 21:08:23 -07:00
* may have some mode bits set to zero .
* The purpose of this is to restrict access via the new lookup object ,
* so that it can access only names which can be reached by the original
* lookup object , and also by the new lookup class .
2013-06-27 19:02:02 -07:00
* @return the lookup modes , which limit the kinds of access performed by this lookup object
2010-04-30 23:48:23 -07:00
* /
2010-09-08 18:40:23 -07:00
public int lookupModes ( ) {
2010-04-30 23:48:23 -07:00
return allowedModes & ALL_MODES ;
}
2009-05-05 22:40:09 -07:00
/ * * Embody the current class ( the lookupClass ) as a lookup class
* for method handle creation .
* Must be called by from a method in this package ,
* which in turn is called by a method not in this package .
* /
2011-03-18 00:03:24 -07:00
Lookup ( Class < ? > lookupClass ) {
2010-04-30 23:48:23 -07:00
this ( lookupClass , ALL_MODES ) ;
2013-04-16 21:39:52 -07:00
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass ( lookupClass ) ;
2010-04-30 23:48:23 -07:00
}
private Lookup ( Class < ? > lookupClass , int allowedModes ) {
2010-01-07 16:16:45 -08:00
this . lookupClass = lookupClass ;
2010-04-30 23:48:23 -07:00
this . allowedModes = allowedModes ;
2010-01-07 16:16:45 -08:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Creates a lookup on the specified new lookup class .
2010-04-30 23:48:23 -07:00
* The resulting object will report the specified
2010-12-16 15:59:27 -08:00
* class as its own { @link # lookupClass lookupClass } .
2010-04-30 23:48:23 -07:00
* < p >
* However , the resulting { @code Lookup } object is guaranteed
* to have no more access capabilities than the original .
2010-10-30 21:08:23 -07:00
* In particular , access capabilities can be lost as follows : < ul >
2010-04-30 23:48:23 -07:00
* < li > If the new lookup class differs from the old one ,
* protected members will not be accessible by virtue of inheritance .
2010-10-30 21:08:23 -07:00
* ( Protected members may continue to be accessible because of package sharing. )
2010-04-30 23:48:23 -07:00
* < li > If the new lookup class is in a different package
* than the old one , protected and default ( package ) members will not be accessible .
* < li > If the new lookup class is not within the same package member
* as the old one , private members will not be accessible .
2010-10-30 21:08:23 -07:00
* < li > If the new lookup class is not accessible to the old lookup class ,
* then no members , not even public members , will be accessible .
* ( In all other cases , public members will continue to be accessible . )
2010-04-30 23:48:23 -07:00
* < / ul >
2011-02-11 01:26:28 -08:00
*
* @param requestedLookupClass the desired lookup class for the new lookup object
* @return a lookup object which reports the desired lookup class
* @throws NullPointerException if the argument is null
2010-01-07 16:16:45 -08:00
* /
2010-04-30 23:48:23 -07:00
public Lookup in ( Class < ? > requestedLookupClass ) {
requestedLookupClass . getClass ( ) ; // null check
if ( allowedModes = = TRUSTED ) // IMPL_LOOKUP can make any lookup at all
return new Lookup ( requestedLookupClass , ALL_MODES ) ;
if ( requestedLookupClass = = this . lookupClass )
return this ; // keep same capabilities
int newModes = ( allowedModes & ( ALL_MODES & ~ PROTECTED ) ) ;
if ( ( newModes & PACKAGE ) ! = 0
& & ! VerifyAccess . isSamePackage ( this . lookupClass , requestedLookupClass ) ) {
newModes & = ~ ( PACKAGE | PRIVATE ) ;
2010-01-07 16:16:45 -08:00
}
2010-10-30 21:08:23 -07:00
// Allow nestmate lookups to be created without special privilege:
2010-04-30 23:48:23 -07:00
if ( ( newModes & PRIVATE ) ! = 0
& & ! VerifyAccess . isSamePackageMember ( this . lookupClass , requestedLookupClass ) ) {
newModes & = ~ PRIVATE ;
}
2012-05-18 20:31:28 -07:00
if ( ( newModes & PUBLIC ) ! = 0
& & ! VerifyAccess . isClassAccessible ( requestedLookupClass , this . lookupClass , allowedModes ) ) {
2010-10-30 21:08:23 -07:00
// The requested class it not accessible from the lookup class.
// No permissions.
newModes = 0 ;
}
2010-04-30 23:48:23 -07:00
checkUnprivilegedlookupClass ( requestedLookupClass ) ;
return new Lookup ( requestedLookupClass , newModes ) ;
2009-05-05 22:40:09 -07:00
}
2010-01-07 16:16:45 -08:00
// Make sure outer class is initialized first.
2011-03-18 00:03:24 -07:00
static { IMPL_NAMES . getClass ( ) ; }
2010-01-07 16:16:45 -08:00
2009-05-05 22:40:09 -07:00
/ * * Version of lookup which is trusted minimally .
* It can only be used to create method handles to
* publicly accessible members .
* /
2010-04-30 23:48:23 -07:00
static final Lookup PUBLIC_LOOKUP = new Lookup ( Object . class , PUBLIC ) ;
2009-05-05 22:40:09 -07:00
/** Package-private version of lookup which is trusted. */
2010-04-30 23:48:23 -07:00
static final Lookup IMPL_LOOKUP = new Lookup ( Object . class , TRUSTED ) ;
2009-05-05 22:40:09 -07:00
private static void checkUnprivilegedlookupClass ( Class < ? > lookupClass ) {
2009-05-12 13:54:22 -07:00
String name = lookupClass . getName ( ) ;
2011-03-23 23:02:31 -07:00
if ( name . startsWith ( " java.lang.invoke. " ) )
2009-05-05 22:40:09 -07:00
throw newIllegalArgumentException ( " illegal lookupClass: " + lookupClass ) ;
}
2010-12-16 15:59:27 -08:00
/ * *
2011-02-11 01:26:28 -08:00
* Displays the name of the class from which lookups are to be made .
2010-12-16 15:59:27 -08:00
* ( The name is the one reported by { @link java . lang . Class # getName ( ) Class . getName } . )
* If there are restrictions on the access permitted to this lookup ,
* this is indicated by adding a suffix to the class name , consisting
2011-02-11 01:26:28 -08:00
* of a slash and a keyword . The keyword represents the strongest
* allowed access , and is chosen as follows :
2010-12-16 15:59:27 -08:00
* < ul >
* < li > If no access is allowed , the suffix is " /noaccess " .
* < li > If only public access is allowed , the suffix is " /public " .
* < li > If only public and package access are allowed , the suffix is " /package " .
* < li > If only public , package , and private access are allowed , the suffix is " /private " .
* < / ul >
* If none of the above cases apply , it is the case that full
* access ( public , package , private , and protected ) is allowed .
* In this case , no suffix is added .
* This is true only of an object obtained originally from
2011-03-23 23:02:31 -07:00
* { @link java . lang . invoke . MethodHandles # lookup MethodHandles . lookup } .
* Objects created by { @link java . lang . invoke . MethodHandles . Lookup # in Lookup . in }
2010-12-16 15:59:27 -08:00
* always have restricted access , and will display a suffix .
2011-02-11 01:26:28 -08:00
* < p >
* ( It may seem strange that protected access should be
* stronger than private access . Viewed independently from
* package access , protected access is the first to be lost ,
* because it requires a direct subclass relationship between
* caller and callee . )
* @see # in
2010-04-30 23:48:23 -07:00
* /
2009-05-05 22:40:09 -07:00
@Override
public String toString ( ) {
2010-04-30 23:48:23 -07:00
String cname = lookupClass . getName ( ) ;
switch ( allowedModes ) {
2011-02-11 01:26:28 -08:00
case 0 : // no privileges
return cname + " /noaccess " ;
2010-04-30 23:48:23 -07:00
case PUBLIC :
2010-12-16 15:59:27 -08:00
return cname + " /public " ;
2010-04-30 23:48:23 -07:00
case PUBLIC | PACKAGE :
return cname + " /package " ;
2011-02-11 01:26:28 -08:00
case ALL_MODES & ~ PROTECTED :
return cname + " /private " ;
2010-04-30 23:48:23 -07:00
case ALL_MODES :
return cname ;
2011-02-11 01:26:28 -08:00
case TRUSTED :
return " /trusted " ; // internal only; not exported
default : // Should not happen, but it's a bitfield...
cname = cname + " / " + Integer . toHexString ( allowedModes ) ;
assert ( false ) : cname ;
return cname ;
2010-04-30 23:48:23 -07:00
}
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle for a static method .
2009-05-05 22:40:09 -07:00
* The type of the method handle will be that of the method .
2010-01-07 16:16:45 -08:00
* ( Since static methods do not take receivers , there is no
* additional receiver argument inserted into the method handle type ,
2011-02-11 01:26:28 -08:00
* as there would be with { @link # findVirtual findVirtual } or { @link # findSpecial findSpecial } . )
2009-05-05 22:40:09 -07:00
* The method and all its argument types must be accessible to the lookup class .
* If the method ' s class has not yet been initialized , that is done
* immediately , before the method handle is returned .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2010-04-30 23:48:23 -07:00
* @param refc the class from which the method is accessed
2009-05-05 22:40:09 -07:00
* @param name the name of the method
* @param type the type of the method
* @return the desired method handle
2011-02-11 01:26:32 -08:00
* @throws NoSuchMethodException if the method does not exist
2011-05-26 17:37:36 -07:00
* @throws IllegalAccessException if access checking fails ,
* or if the method is not { @code static } ,
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* /
public
2011-02-11 01:26:32 -08:00
MethodHandle findStatic ( Class < ? > refc , String name , MethodType type ) throws NoSuchMethodException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
MemberName method = resolveOrFail ( REF_invokeStatic , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , method ) ;
return getDirectMethod ( REF_invokeStatic , refc , method , findBoundCallerClass ( method ) ) ;
2011-06-01 23:56:47 -07:00
}
2009-05-05 22:40:09 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle for a virtual method .
2009-05-05 22:40:09 -07:00
* The type of the method handle will be that of the method ,
2010-04-30 23:48:23 -07:00
* with the receiver type ( usually { @code refc } ) prepended .
2009-05-05 22:40:09 -07:00
* The method and all its argument types must be accessible to the lookup class .
* < p >
* When called , the handle will treat the first argument as a receiver
* and dispatch on the receiver ' s type to determine which method
* implementation to enter .
* ( The dispatching action is identical with that performed by an
* { @code invokevirtual } or { @code invokeinterface } instruction . )
2011-02-11 01:26:24 -08:00
* < p >
2012-07-24 10:47:44 -07:00
* The first argument will be of type { @code refc } if the lookup
* class has full privileges to access the member . Otherwise
* the member must be { @code protected } and the first argument
* will be restricted in type to the lookup class .
* < p >
2011-02-11 01:26:24 -08:00
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2011-02-11 01:26:28 -08:00
* < p >
* Because of the general equivalence between { @code invokevirtual }
* instructions and method handles produced by { @code findVirtual } ,
* if the class is { @code MethodHandle } and the name string is
2011-05-12 19:27:33 -07:00
* { @code invokeExact } or { @code invoke } , the resulting
2011-02-11 01:26:28 -08:00
* method handle is equivalent to one produced by
2011-03-23 23:02:31 -07:00
* { @link java . lang . invoke . MethodHandles # exactInvoker MethodHandles . exactInvoker } or
2011-05-12 19:27:33 -07:00
* { @link java . lang . invoke . MethodHandles # invoker MethodHandles . invoker }
2011-02-11 01:26:28 -08:00
* with the same { @code type } argument .
*
2010-04-30 23:48:23 -07:00
* @param refc the class or interface from which the method is accessed
2009-05-05 22:40:09 -07:00
* @param name the name of the method
* @param type the type of the method , with the receiver argument omitted
* @return the desired method handle
2011-02-11 01:26:32 -08:00
* @throws NoSuchMethodException if the method does not exist
2011-05-26 17:37:36 -07:00
* @throws IllegalAccessException if access checking fails ,
* or if the method is { @code static }
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findVirtual ( Class < ? > refc , String name , MethodType type ) throws NoSuchMethodException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
if ( refc = = MethodHandle . class ) {
MethodHandle mh = findVirtualForMH ( name , type ) ;
if ( mh ! = null ) return mh ;
}
byte refKind = ( refc . isInterface ( ) ? REF_invokeInterface : REF_invokeVirtual ) ;
MemberName method = resolveOrFail ( refKind , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , method ) ;
return getDirectMethod ( refKind , refc , method , findBoundCallerClass ( method ) ) ;
2011-06-01 23:56:47 -07:00
}
2012-07-24 10:47:44 -07:00
private MethodHandle findVirtualForMH ( String name , MethodType type ) {
// these names require special lookups because of the implicit MethodType argument
if ( " invoke " . equals ( name ) )
return invoker ( type ) ;
if ( " invokeExact " . equals ( name ) )
return exactInvoker ( type ) ;
2013-09-03 21:42:56 -07:00
assert ( ! MemberName . isMethodHandleInvokeName ( name ) ) ;
2012-07-24 10:47:44 -07:00
return null ;
2010-04-30 23:48:23 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which creates an object and initializes it , using
2010-04-30 23:48:23 -07:00
* the constructor of the specified type .
* The parameter types of the method handle will be those of the constructor ,
* while the return type will be a reference to the constructor ' s class .
* The constructor and all its argument types must be accessible to the lookup class .
* If the constructor ' s class has not yet been initialized , that is done
* immediately , before the method handle is returned .
* < p >
* Note : The requested type must have a return type of { @code void } .
2011-02-11 01:26:28 -08:00
* This is consistent with the JVM ' s treatment of constructor type descriptors .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the constructor ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2010-04-30 23:48:23 -07:00
* @param refc the class or interface from which the method is accessed
* @param type the type of the method , with the receiver argument omitted , and a void return type
* @return the desired method handle
2011-02-11 01:26:32 -08:00
* @throws NoSuchMethodException if the constructor does not exist
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2010-04-30 23:48:23 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findConstructor ( Class < ? > refc , MethodType type ) throws NoSuchMethodException , IllegalAccessException {
2010-04-30 23:48:23 -07:00
String name = " <init> " ;
2012-07-24 10:47:44 -07:00
MemberName ctor = resolveOrFail ( REF_newInvokeSpecial , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , ctor ) ;
2012-07-24 10:47:44 -07:00
return getDirectConstructor ( refc , ctor ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces an early - bound method handle for a virtual method ,
2009-05-11 21:09:58 -07:00
* as if called from an { @code invokespecial }
2009-05-05 22:40:09 -07:00
* instruction from { @code caller } .
2009-05-11 21:09:58 -07:00
* The type of the method handle will be that of the method ,
2009-05-05 22:40:09 -07:00
* with a suitably restricted receiver type ( such as { @code caller } ) prepended .
2009-05-11 21:09:58 -07:00
* The method and all its argument types must be accessible
2009-05-05 22:40:09 -07:00
* to the caller .
* < p >
* When called , the handle will treat the first argument as a receiver ,
* but will not dispatch on the receiver ' s type .
* ( This direct invocation action is identical with that performed by an
* { @code invokespecial } instruction . )
* < p >
* If the explicitly specified caller class is not identical with the
2010-10-30 21:08:23 -07:00
* lookup class , or if this lookup object does not have private access
* privileges , the access fails .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2010-04-30 23:48:23 -07:00
* @param refc the class or interface from which the method is accessed
* @param name the name of the method ( which must not be " <init> " )
2009-05-05 22:40:09 -07:00
* @param type the type of the method , with the receiver argument omitted
* @param specialCaller the proposed calling class to perform the { @code invokespecial }
* @return the desired method handle
2011-02-11 01:26:32 -08:00
* @throws NoSuchMethodException if the method does not exist
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* /
2010-04-30 23:48:23 -07:00
public MethodHandle findSpecial ( Class < ? > refc , String name , MethodType type ,
2011-02-11 01:26:32 -08:00
Class < ? > specialCaller ) throws NoSuchMethodException , IllegalAccessException {
2010-04-30 23:48:23 -07:00
checkSpecialCaller ( specialCaller ) ;
2012-07-24 10:47:44 -07:00
Lookup specialLookup = this . in ( specialCaller ) ;
MemberName method = specialLookup . resolveOrFail ( REF_invokeSpecial , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , method ) ;
return specialLookup . getDirectMethod ( REF_invokeSpecial , refc , method , findBoundCallerClass ( method ) ) ;
2011-06-01 23:56:47 -07:00
}
2010-04-30 23:48:23 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving read access to a non - static field .
2010-04-30 23:48:23 -07:00
* The type of the method handle will have a return type of the field ' s
* value type .
2010-06-08 23:08:56 -07:00
* The method handle ' s single argument will be the instance containing
2010-04-30 23:48:23 -07:00
* the field .
* Access checking is performed immediately on behalf of the lookup class .
2011-02-11 01:26:28 -08:00
* @param refc the class or interface from which the method is accessed
2010-04-30 23:48:23 -07:00
* @param name the field ' s name
* @param type the field ' s type
* @return a method handle which can load values from the field
2011-02-11 01:26:32 -08:00
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails , or if the field is { @code static }
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2010-04-30 23:48:23 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findGetter ( Class < ? > refc , String name , Class < ? > type ) throws NoSuchFieldException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
MemberName field = resolveOrFail ( REF_getField , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , field ) ;
2012-07-24 10:47:44 -07:00
return getDirectField ( REF_getField , refc , field ) ;
2011-06-01 23:56:47 -07:00
}
2010-04-30 23:48:23 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving write access to a non - static field .
2010-04-30 23:48:23 -07:00
* The type of the method handle will have a void return type .
2010-06-08 23:08:56 -07:00
* The method handle will take two arguments , the instance containing
2010-04-30 23:48:23 -07:00
* the field , and the value to be stored .
2010-06-08 23:08:56 -07:00
* The second argument will be of the field ' s value type .
* Access checking is performed immediately on behalf of the lookup class .
2011-02-11 01:26:28 -08:00
* @param refc the class or interface from which the method is accessed
2010-06-08 23:08:56 -07:00
* @param name the field ' s name
* @param type the field ' s type
* @return a method handle which can store values into the field
2011-02-11 01:26:32 -08:00
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails , or if the field is { @code static }
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2010-06-08 23:08:56 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findSetter ( Class < ? > refc , String name , Class < ? > type ) throws NoSuchFieldException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
MemberName field = resolveOrFail ( REF_putField , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , field ) ;
2012-07-24 10:47:44 -07:00
return getDirectField ( REF_putField , refc , field ) ;
2011-06-01 23:56:47 -07:00
}
2010-06-08 23:08:56 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving read access to a static field .
2010-06-08 23:08:56 -07:00
* The type of the method handle will have a return type of the field ' s
* value type .
* The method handle will take no arguments .
* Access checking is performed immediately on behalf of the lookup class .
2011-02-11 01:26:28 -08:00
* @param refc the class or interface from which the method is accessed
2010-06-08 23:08:56 -07:00
* @param name the field ' s name
* @param type the field ' s type
* @return a method handle which can load values from the field
2011-02-11 01:26:32 -08:00
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails , or if the field is not { @code static }
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2010-06-08 23:08:56 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findStaticGetter ( Class < ? > refc , String name , Class < ? > type ) throws NoSuchFieldException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
MemberName field = resolveOrFail ( REF_getStatic , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , field ) ;
2012-07-24 10:47:44 -07:00
return getDirectField ( REF_getStatic , refc , field ) ;
2011-06-01 23:56:47 -07:00
}
2010-06-08 23:08:56 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving write access to a static field .
2010-06-08 23:08:56 -07:00
* The type of the method handle will have a void return type .
* The method handle will take a single
* argument , of the field ' s value type , the value to be stored .
2010-04-30 23:48:23 -07:00
* Access checking is performed immediately on behalf of the lookup class .
2011-02-11 01:26:28 -08:00
* @param refc the class or interface from which the method is accessed
2010-04-30 23:48:23 -07:00
* @param name the field ' s name
* @param type the field ' s type
2010-06-08 23:08:56 -07:00
* @return a method handle which can store values into the field
2011-02-11 01:26:32 -08:00
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails , or if the field is not { @code static }
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2010-04-30 23:48:23 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle findStaticSetter ( Class < ? > refc , String name , Class < ? > type ) throws NoSuchFieldException , IllegalAccessException {
2012-07-24 10:47:44 -07:00
MemberName field = resolveOrFail ( REF_putStatic , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , field ) ;
2012-07-24 10:47:44 -07:00
return getDirectField ( REF_putStatic , refc , field ) ;
2011-06-01 23:56:47 -07:00
}
2009-05-05 22:40:09 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces an early - bound method handle for a non - static method .
2009-05-05 22:40:09 -07:00
* The receiver must have a supertype { @code defc } in which a method
* of the given name and type is accessible to the lookup class .
* The method and all its argument types must be accessible to the lookup class .
2010-01-07 16:16:45 -08:00
* The type of the method handle will be that of the method ,
* without any insertion of an additional receiver parameter .
* The given receiver will be bound into the method handle ,
* so that every call to the method handle will invoke the
* requested method on the given receiver .
2009-05-05 22:40:09 -07:00
* < p >
2011-02-11 01:26:24 -08:00
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set
* < em > and < / em > the trailing array argument is not the only argument .
* ( If the trailing array argument is the only argument ,
* the given receiver value will be bound to it . )
* < p >
* This is equivalent to the following code :
* < blockquote > < pre >
2011-05-26 17:37:36 -07:00
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
. . .
MethodHandle mh0 = lookup ( ) . { @link # findVirtual findVirtual } ( defc , name , type ) ;
2011-02-11 01:26:24 -08:00
MethodHandle mh1 = mh0 . { @link MethodHandle # bindTo bindTo } ( receiver ) ;
MethodType mt1 = mh1 . type ( ) ;
2011-05-26 17:37:36 -07:00
if ( mh0 . isVarargsCollector ( ) )
2011-02-11 01:26:24 -08:00
mh1 = mh1 . asVarargsCollector ( mt1 . parameterType ( mt1 . parameterCount ( ) - 1 ) ) ;
return mh1 ;
* < / pre > < / blockquote >
2010-01-07 16:16:45 -08:00
* where { @code defc } is either { @code receiver . getClass ( ) } or a super
* type of that class , in which the requested method is accessible
* to the lookup class .
2011-02-11 01:26:24 -08:00
* ( Note that { @code bindTo } does not preserve variable arity . )
2009-05-05 22:40:09 -07:00
* @param receiver the object from which the method is accessed
* @param name the name of the method
* @param type the type of the method , with the receiver argument omitted
* @return the desired method handle
2011-02-11 01:26:32 -08:00
* @throws NoSuchMethodException if the method does not exist
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-15 00:16:53 -08:00
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle bind ( Object receiver , String name , MethodType type ) throws NoSuchMethodException , IllegalAccessException {
2010-04-30 23:48:23 -07:00
Class < ? extends Object > refc = receiver . getClass ( ) ; // may get NPE
2012-07-24 10:47:44 -07:00
MemberName method = resolveOrFail ( REF_invokeSpecial , refc , name , type ) ;
2013-05-08 12:09:35 -07:00
checkSecurityManager ( refc , method ) ;
MethodHandle mh = getDirectMethodNoRestrict ( REF_invokeSpecial , refc , method , findBoundCallerClass ( method ) ) ;
2012-07-24 10:47:44 -07:00
return mh . bindReceiver ( receiver ) . setVarargs ( method ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-03-23 23:02:31 -07:00
* Makes a direct method handle to < i > m < / i > , if the lookup class has permission .
2009-05-05 22:40:09 -07:00
* If < i > m < / i > is non - static , the receiver argument is treated as an initial argument .
* If < i > m < / i > is virtual , overriding is respected on every call .
* Unlike the Core Reflection API , exceptions are < em > not < / em > wrapped .
* The type of the method handle will be that of the method ,
* with the receiver type prepended ( but only if it is non - static ) .
* If the method ' s { @code accessible } flag is not set ,
* access checking is performed immediately on behalf of the lookup class .
* If < i > m < / i > is not public , do not share the resulting handle with untrusted parties .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2009-05-05 22:40:09 -07:00
* @param m the reflected method
* @return a method handle which can invoke the reflected method
2011-02-11 01:26:32 -08:00
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle unreflect ( Method m ) throws IllegalAccessException {
2013-09-03 21:42:56 -07:00
if ( m . getDeclaringClass ( ) = = MethodHandle . class ) {
MethodHandle mh = unreflectForMH ( m ) ;
if ( mh ! = null ) return mh ;
}
2010-04-30 23:48:23 -07:00
MemberName method = new MemberName ( m ) ;
2012-07-24 10:47:44 -07:00
byte refKind = method . getReferenceKind ( ) ;
if ( refKind = = REF_invokeSpecial )
refKind = REF_invokeVirtual ;
2010-04-30 23:48:23 -07:00
assert ( method . isMethod ( ) ) ;
2012-07-24 10:47:44 -07:00
Lookup lookup = m . isAccessible ( ) ? IMPL_LOOKUP : this ;
2013-05-08 12:09:35 -07:00
return lookup . getDirectMethod ( refKind , method . getDeclaringClass ( ) , method , findBoundCallerClass ( method ) ) ;
2009-05-05 22:40:09 -07:00
}
2013-09-03 21:42:56 -07:00
private MethodHandle unreflectForMH ( Method m ) {
// these names require special lookups because they throw UnsupportedOperationException
if ( MemberName . isMethodHandleInvokeName ( m . getName ( ) ) )
return MethodHandleImpl . fakeMethodHandleInvoke ( new MemberName ( m ) ) ;
return null ;
}
2009-05-05 22:40:09 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle for a reflected method .
2009-05-05 22:40:09 -07:00
* It will bypass checks for overriding methods on the receiver ,
2010-04-30 23:48:23 -07:00
* as if by a { @code invokespecial } instruction from within the { @code specialCaller } .
2009-05-05 22:40:09 -07:00
* The type of the method handle will be that of the method ,
2010-04-30 23:48:23 -07:00
* with the special caller type prepended ( and < em > not < / em > the receiver of the method ) .
2009-05-05 22:40:09 -07:00
* If the method ' s { @code accessible } flag is not set ,
* access checking is performed immediately on behalf of the lookup class ,
* as if { @code invokespecial } instruction were being linked .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the method ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2009-05-05 22:40:09 -07:00
* @param m the reflected method
2010-04-30 23:48:23 -07:00
* @param specialCaller the class nominally calling the method
2009-05-05 22:40:09 -07:00
* @return a method handle which can invoke the reflected method
2011-02-11 01:26:32 -08:00
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle unreflectSpecial ( Method m , Class < ? > specialCaller ) throws IllegalAccessException {
2010-04-30 23:48:23 -07:00
checkSpecialCaller ( specialCaller ) ;
2012-07-24 10:47:44 -07:00
Lookup specialLookup = this . in ( specialCaller ) ;
MemberName method = new MemberName ( m , true ) ;
2010-04-30 23:48:23 -07:00
assert ( method . isMethod ( ) ) ;
// ignore m.isAccessible: this is a new kind of access
2013-05-08 12:09:35 -07:00
return specialLookup . getDirectMethod ( REF_invokeSpecial , method . getDeclaringClass ( ) , method , findBoundCallerClass ( method ) ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle for a reflected constructor .
2010-01-07 16:16:45 -08:00
* The type of the method handle will be that of the constructor ,
* with the return type changed to the declaring class .
2009-05-05 22:40:09 -07:00
* The method handle will perform a { @code newInstance } operation ,
* creating a new instance of the constructor ' s class on the
* arguments passed to the method handle .
* < p >
* If the constructor ' s { @code accessible } flag is not set ,
2010-01-07 16:16:45 -08:00
* access checking is performed immediately on behalf of the lookup class .
2011-02-11 01:26:24 -08:00
* < p >
* The returned method handle will have
* { @linkplain MethodHandle # asVarargsCollector variable arity } if and only if
* the constructor ' s variable arity modifier bit ( { @code 0x0080 } ) is set .
2010-04-30 23:48:23 -07:00
* @param c the reflected constructor
2009-05-05 22:40:09 -07:00
* @return a method handle which can invoke the reflected constructor
2011-02-11 01:26:32 -08:00
* @throws IllegalAccessException if access checking fails
2011-05-26 17:37:36 -07:00
* or if the method ' s variable arity modifier bit
* is set and { @code asVarargsCollector } fails
2011-02-11 01:26:32 -08:00
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* /
2012-01-18 17:34:29 -08:00
@SuppressWarnings ( " rawtypes " ) // Will be Constructor<?> after JSR 292 MR
2011-02-11 01:26:32 -08:00
public MethodHandle unreflectConstructor ( Constructor c ) throws IllegalAccessException {
2010-04-30 23:48:23 -07:00
MemberName ctor = new MemberName ( c ) ;
assert ( ctor . isConstructor ( ) ) ;
2012-07-24 10:47:44 -07:00
Lookup lookup = c . isAccessible ( ) ? IMPL_LOOKUP : this ;
return lookup . getDirectConstructor ( ctor . getDeclaringClass ( ) , ctor ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving read access to a reflected field .
2009-05-05 22:40:09 -07:00
* The type of the method handle will have a return type of the field ' s
2010-01-07 16:16:45 -08:00
* value type .
* If the field is static , the method handle will take no arguments .
* Otherwise , its single argument will be the instance containing
* the field .
2011-03-23 23:02:31 -07:00
* If the field ' s { @code accessible } flag is not set ,
2009-05-05 22:40:09 -07:00
* access checking is performed immediately on behalf of the lookup class .
* @param f the reflected field
* @return a method handle which can load values from the reflected field
2011-02-11 01:26:32 -08:00
* @throws IllegalAccessException if access checking fails
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle unreflectGetter ( Field f ) throws IllegalAccessException {
2012-07-24 10:47:44 -07:00
return unreflectField ( f , false ) ;
}
private MethodHandle unreflectField ( Field f , boolean isSetter ) throws IllegalAccessException {
MemberName field = new MemberName ( f , isSetter ) ;
assert ( isSetter
? MethodHandleNatives . refKindIsSetter ( field . getReferenceKind ( ) )
: MethodHandleNatives . refKindIsGetter ( field . getReferenceKind ( ) ) ) ;
Lookup lookup = f . isAccessible ( ) ? IMPL_LOOKUP : this ;
return lookup . getDirectField ( field . getReferenceKind ( ) , f . getDeclaringClass ( ) , field ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving write access to a reflected field .
2009-05-05 22:40:09 -07:00
* The type of the method handle will have a void return type .
2010-01-07 16:16:45 -08:00
* If the field is static , the method handle will take a single
* argument , of the field ' s value type , the value to be stored .
* Otherwise , the two arguments will be the instance containing
* the field , and the value to be stored .
2011-03-23 23:02:31 -07:00
* If the field ' s { @code accessible } flag is not set ,
2009-05-05 22:40:09 -07:00
* access checking is performed immediately on behalf of the lookup class .
* @param f the reflected field
* @return a method handle which can store values into the reflected field
2011-02-11 01:26:32 -08:00
* @throws IllegalAccessException if access checking fails
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* /
2011-02-11 01:26:32 -08:00
public MethodHandle unreflectSetter ( Field f ) throws IllegalAccessException {
2012-07-24 10:47:44 -07:00
return unreflectField ( f , true ) ;
2009-05-05 22:40:09 -07:00
}
2013-09-03 21:42:56 -07:00
/ * *
* Cracks a direct method handle created by this lookup object or a similar one .
* Security and access checks are performed to ensure that this lookup object
* is capable of reproducing the target method handle .
* This means that the cracking may fail if target is a direct method handle
* but was created by an unrelated lookup object .
* @param target a direct method handle to crack into symbolic reference components
* @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
* @exception SecurityException if a security manager is present and it
* < a href = " MethodHandles.Lookup.html#secmgr " > refuses access < / a >
* @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
* @exception NullPointerException if the target is { @code null }
* @since 1 . 8
* /
public MethodHandleInfo revealDirect ( MethodHandle target ) {
MemberName member = target . internalMemberName ( ) ;
if ( member = = null | | ( ! member . isResolved ( ) & & ! member . isMethodHandleInvoke ( ) ) )
throw newIllegalArgumentException ( " not a direct method handle " ) ;
Class < ? > defc = member . getDeclaringClass ( ) ;
byte refKind = member . getReferenceKind ( ) ;
assert ( MethodHandleNatives . refKindIsValid ( refKind ) ) ;
if ( refKind = = REF_invokeSpecial & & ! target . isInvokeSpecial ( ) )
// Devirtualized method invocation is usually formally virtual.
// To avoid creating extra MemberName objects for this common case,
// we encode this extra degree of freedom using MH.isInvokeSpecial.
refKind = REF_invokeVirtual ;
if ( refKind = = REF_invokeVirtual & & defc . isInterface ( ) )
// Symbolic reference is through interface but resolves to Object method (toString, etc.)
refKind = REF_invokeInterface ;
// Check SM permissions and member access before cracking.
try {
checkSecurityManager ( defc , member ) ;
checkAccess ( refKind , defc , member ) ;
} catch ( IllegalAccessException ex ) {
throw new IllegalArgumentException ( ex ) ;
}
// Produce the handle to the results.
return new InfoFromMemberName ( this , member , refKind ) ;
}
2010-04-30 23:48:23 -07:00
/// Helper methods, all package-private.
2009-05-05 22:40:09 -07:00
2012-07-24 10:47:44 -07:00
MemberName resolveOrFail ( byte refKind , Class < ? > refc , String name , Class < ? > type ) throws NoSuchFieldException , IllegalAccessException {
2010-04-30 23:48:23 -07:00
checkSymbolicClass ( refc ) ; // do this before attempting to resolve
2013-10-05 05:30:38 -07:00
name . getClass ( ) ; // NPE
type . getClass ( ) ; // NPE
2012-07-24 10:47:44 -07:00
return IMPL_NAMES . resolveOrFail ( refKind , new MemberName ( refc , name , type , refKind ) , lookupClassOrNull ( ) ,
2011-02-11 01:26:32 -08:00
NoSuchFieldException . class ) ;
2010-04-30 23:48:23 -07:00
}
2009-05-05 22:40:09 -07:00
2012-07-24 10:47:44 -07:00
MemberName resolveOrFail ( byte refKind , Class < ? > refc , String name , MethodType type ) throws NoSuchMethodException , IllegalAccessException {
2010-04-30 23:48:23 -07:00
checkSymbolicClass ( refc ) ; // do this before attempting to resolve
2013-10-05 05:30:38 -07:00
name . getClass ( ) ; // NPE
type . getClass ( ) ; // NPE
2012-07-24 10:47:44 -07:00
return IMPL_NAMES . resolveOrFail ( refKind , new MemberName ( refc , name , type , refKind ) , lookupClassOrNull ( ) ,
2011-02-11 01:26:32 -08:00
NoSuchMethodException . class ) ;
2010-04-30 23:48:23 -07:00
}
2009-05-05 22:40:09 -07:00
2013-10-05 05:30:38 -07:00
MemberName resolveOrFail ( byte refKind , MemberName member ) throws ReflectiveOperationException {
checkSymbolicClass ( member . getDeclaringClass ( ) ) ; // do this before attempting to resolve
member . getName ( ) . getClass ( ) ; // NPE
member . getType ( ) . getClass ( ) ; // NPE
return IMPL_NAMES . resolveOrFail ( refKind , member , lookupClassOrNull ( ) ,
ReflectiveOperationException . class ) ;
}
2011-02-11 01:26:32 -08:00
void checkSymbolicClass ( Class < ? > refc ) throws IllegalAccessException {
2013-10-05 05:30:38 -07:00
refc . getClass ( ) ; // NPE
2010-04-30 23:48:23 -07:00
Class < ? > caller = lookupClassOrNull ( ) ;
2012-05-18 20:31:28 -07:00
if ( caller ! = null & & ! VerifyAccess . isClassAccessible ( refc , caller , allowedModes ) )
2011-03-18 00:03:24 -07:00
throw new MemberName ( refc ) . makeAccessException ( " symbolic reference class is not public " , this ) ;
2010-04-30 23:48:23 -07:00
}
2013-02-22 03:00:48 -08:00
/ * *
* Find my trustable caller class if m is a caller sensitive method .
* If this lookup object has private access , then the caller class is the lookupClass .
2013-05-08 12:09:35 -07:00
* Otherwise , if m is caller - sensitive , throw IllegalAccessException .
2013-02-22 03:00:48 -08:00
* /
2013-05-08 12:09:35 -07:00
Class < ? > findBoundCallerClass ( MemberName m ) throws IllegalAccessException {
2013-02-22 03:00:48 -08:00
Class < ? > callerClass = null ;
if ( MethodHandleNatives . isCallerSensitive ( m ) ) {
2013-05-08 12:09:35 -07:00
// Only full-power lookup is allowed to resolve caller-sensitive methods
if ( isFullPowerLookup ( ) ) {
callerClass = lookupClass ;
} else {
throw new IllegalAccessException ( " Attempt to lookup caller-sensitive method using restricted lookup object " ) ;
}
2013-02-22 03:00:48 -08:00
}
return callerClass ;
}
2013-04-16 21:39:52 -07:00
2013-05-08 12:09:35 -07:00
private boolean isFullPowerLookup ( ) {
return ( allowedModes & PRIVATE ) ! = 0 ;
}
2011-05-26 17:37:36 -07:00
/ * *
* Perform necessary < a href = " MethodHandles.Lookup.html#secmgr " > access checks < / a > .
2013-02-22 03:00:48 -08:00
* Determines a trustable caller class to compare with refc , the symbolic reference class .
* If this lookup object has private access , then the caller class is the lookupClass .
2011-05-26 17:37:36 -07:00
* /
2013-05-08 12:09:35 -07:00
void checkSecurityManager ( Class < ? > refc , MemberName m ) {
2011-05-26 17:37:36 -07:00
SecurityManager smgr = System . getSecurityManager ( ) ;
if ( smgr = = null ) return ;
if ( allowedModes = = TRUSTED ) return ;
2013-04-16 21:39:52 -07:00
2011-05-26 17:37:36 -07:00
// Step 1:
2013-05-08 12:09:35 -07:00
if ( ! isFullPowerLookup ( ) | |
! VerifyAccess . classLoaderIsAncestor ( lookupClass , refc ) ) {
ReflectUtil . checkPackageAccess ( refc ) ;
}
2013-04-16 21:39:52 -07:00
2013-07-02 15:58:09 -07:00
// Step 2:
2011-05-26 17:37:36 -07:00
if ( m . isPublic ( ) ) return ;
Class < ? > defc = m . getDeclaringClass ( ) ;
2013-04-16 21:39:52 -07:00
{
2013-07-02 15:58:09 -07:00
if ( ! isFullPowerLookup ( ) ) {
smgr . checkPermission ( SecurityConstants . CHECK_MEMBER_ACCESS_PERMISSION ) ;
2013-04-16 21:39:52 -07:00
}
}
2013-07-02 15:58:09 -07:00
// Step 3:
2013-05-08 12:09:35 -07:00
if ( defc ! = refc ) {
ReflectUtil . checkPackageAccess ( defc ) ;
}
2011-05-26 17:37:36 -07:00
}
2012-07-24 10:47:44 -07:00
void checkMethod ( byte refKind , Class < ? > refc , MemberName m ) throws IllegalAccessException {
boolean wantStatic = ( refKind = = REF_invokeStatic ) ;
2010-04-30 23:48:23 -07:00
String message ;
if ( m . isConstructor ( ) )
message = " expected a method, not a constructor " ;
else if ( ! m . isMethod ( ) )
message = " expected a method " ;
else if ( wantStatic ! = m . isStatic ( ) )
message = wantStatic ? " expected a static method " : " expected a non-static method " ;
else
2012-07-24 10:47:44 -07:00
{ checkAccess ( refKind , refc , m ) ; return ; }
2011-03-18 00:03:24 -07:00
throw m . makeAccessException ( message , this ) ;
2010-04-30 23:48:23 -07:00
}
2012-07-24 10:47:44 -07:00
void checkField ( byte refKind , Class < ? > refc , MemberName m ) throws IllegalAccessException {
boolean wantStatic = ! MethodHandleNatives . refKindHasReceiver ( refKind ) ;
String message ;
if ( wantStatic ! = m . isStatic ( ) )
message = wantStatic ? " expected a static field " : " expected a non-static field " ;
else
{ checkAccess ( refKind , refc , m ) ; return ; }
throw m . makeAccessException ( message , this ) ;
}
void checkAccess ( byte refKind , Class < ? > refc , MemberName m ) throws IllegalAccessException {
assert ( m . referenceKindIsConsistentWith ( refKind ) & &
MethodHandleNatives . refKindIsValid ( refKind ) & &
( MethodHandleNatives . refKindIsField ( refKind ) = = m . isField ( ) ) ) ;
2010-04-30 23:48:23 -07:00
int allowedModes = this . allowedModes ;
if ( allowedModes = = TRUSTED ) return ;
int mods = m . getModifiers ( ) ;
2013-10-05 05:30:38 -07:00
if ( Modifier . isProtected ( mods ) & &
refKind = = REF_invokeVirtual & &
m . getDeclaringClass ( ) = = Object . class & &
m . getName ( ) . equals ( " clone " ) & &
refc . isArray ( ) ) {
// The JVM does this hack also.
// (See ClassVerifier::verify_invoke_instructions
// and LinkResolver::check_method_accessability.)
// Because the JVM does not allow separate methods on array types,
// there is no separate method for int[].clone.
// All arrays simply inherit Object.clone.
// But for access checking logic, we make Object.clone
// (normally protected) appear to be public.
// Later on, when the DirectMethodHandle is created,
// its leading argument will be restricted to the
// requested array type.
// N.B. The return type is not adjusted, because
// that is *not* the bytecode behavior.
mods ^ = Modifier . PROTECTED | Modifier . PUBLIC ;
}
2012-07-24 10:47:44 -07:00
if ( Modifier . isFinal ( mods ) & &
MethodHandleNatives . refKindIsSetter ( refKind ) )
throw m . makeAccessException ( " unexpected set of a final field " , this ) ;
2010-10-30 21:08:23 -07:00
if ( Modifier . isPublic ( mods ) & & Modifier . isPublic ( refc . getModifiers ( ) ) & & allowedModes ! = 0 )
2010-04-30 23:48:23 -07:00
return ; // common case
int requestedModes = fixmods ( mods ) ; // adjust 0 => PACKAGE
2012-07-24 10:47:44 -07:00
if ( ( requestedModes & allowedModes ) ! = 0 ) {
if ( VerifyAccess . isMemberAccessible ( refc , m . getDeclaringClass ( ) ,
mods , lookupClass ( ) , allowedModes ) )
return ;
} else {
2010-04-30 23:48:23 -07:00
// Protected members can also be checked as if they were package-private.
2012-07-24 10:47:44 -07:00
if ( ( requestedModes & PROTECTED ) ! = 0 & & ( allowedModes & PACKAGE ) ! = 0
& & VerifyAccess . isSamePackage ( m . getDeclaringClass ( ) , lookupClass ( ) ) )
return ;
}
2011-03-18 00:03:24 -07:00
throw m . makeAccessException ( accessFailedMessage ( refc , m ) , this ) ;
2010-04-30 23:48:23 -07:00
}
String accessFailedMessage ( Class < ? > refc , MemberName m ) {
Class < ? > defc = m . getDeclaringClass ( ) ;
int mods = m . getModifiers ( ) ;
2011-02-11 01:26:32 -08:00
// check the class first:
boolean classOK = ( Modifier . isPublic ( defc . getModifiers ( ) ) & &
( defc = = refc | |
Modifier . isPublic ( refc . getModifiers ( ) ) ) ) ;
if ( ! classOK & & ( allowedModes & PACKAGE ) ! = 0 ) {
2012-05-18 20:31:28 -07:00
classOK = ( VerifyAccess . isClassAccessible ( defc , lookupClass ( ) , ALL_MODES ) & &
2011-02-11 01:26:32 -08:00
( defc = = refc | |
2012-05-18 20:31:28 -07:00
VerifyAccess . isClassAccessible ( refc , lookupClass ( ) , ALL_MODES ) ) ) ;
2011-02-11 01:26:32 -08:00
}
if ( ! classOK )
2010-04-30 23:48:23 -07:00
return " class is not public " ;
if ( Modifier . isPublic ( mods ) )
return " access to public member failed " ; // (how?)
if ( Modifier . isPrivate ( mods ) )
return " member is private " ;
if ( Modifier . isProtected ( mods ) )
return " member is protected " ;
return " member is private to package " ;
}
2010-10-30 21:08:23 -07:00
private static final boolean ALLOW_NESTMATE_ACCESS = false ;
2012-07-24 10:47:44 -07:00
private void checkSpecialCaller ( Class < ? > specialCaller ) throws IllegalAccessException {
int allowedModes = this . allowedModes ;
2010-04-30 23:48:23 -07:00
if ( allowedModes = = TRUSTED ) return ;
2010-10-30 21:08:23 -07:00
if ( ( allowedModes & PRIVATE ) = = 0
| | ( specialCaller ! = lookupClass ( )
& & ! ( ALLOW_NESTMATE_ACCESS & &
VerifyAccess . isSamePackageMember ( specialCaller , lookupClass ( ) ) ) ) )
2011-03-18 00:03:24 -07:00
throw new MemberName ( specialCaller ) .
makeAccessException ( " no private access for invokespecial " , this ) ;
2010-04-30 23:48:23 -07:00
}
2012-07-24 10:47:44 -07:00
private boolean restrictProtectedReceiver ( MemberName method ) {
2010-04-30 23:48:23 -07:00
// The accessing class only has the right to use a protected member
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if ( ! method . isProtected ( ) | | method . isStatic ( )
| | allowedModes = = TRUSTED
2010-10-30 21:08:23 -07:00
| | method . getDeclaringClass ( ) = = lookupClass ( )
2011-05-17 19:48:19 -07:00
| | VerifyAccess . isSamePackage ( method . getDeclaringClass ( ) , lookupClass ( ) )
2010-10-30 21:08:23 -07:00
| | ( ALLOW_NESTMATE_ACCESS & &
VerifyAccess . isSamePackageMember ( method . getDeclaringClass ( ) , lookupClass ( ) ) ) )
2012-07-24 10:47:44 -07:00
return false ;
return true ;
2010-04-30 23:48:23 -07:00
}
2012-07-24 10:47:44 -07:00
private MethodHandle restrictReceiver ( MemberName method , MethodHandle mh , Class < ? > caller ) throws IllegalAccessException {
2010-04-30 23:48:23 -07:00
assert ( ! method . isStatic ( ) ) ;
2012-07-24 10:47:44 -07:00
// receiver type of mh is too wide; narrow to caller
if ( ! method . getDeclaringClass ( ) . isAssignableFrom ( caller ) ) {
2011-03-18 00:03:24 -07:00
throw method . makeAccessException ( " caller class must be a subclass below the method " , caller ) ;
2009-05-05 22:40:09 -07:00
}
2010-04-30 23:48:23 -07:00
MethodType rawType = mh . type ( ) ;
if ( rawType . parameterType ( 0 ) = = caller ) return mh ;
MethodType narrowType = rawType . changeParameterType ( 0 , caller ) ;
2012-07-24 10:47:44 -07:00
return mh . viewAsType ( narrowType ) ;
2010-04-30 23:48:23 -07:00
}
2013-02-22 03:00:48 -08:00
private MethodHandle getDirectMethod ( byte refKind , Class < ? > refc , MemberName method , Class < ? > callerClass ) throws IllegalAccessException {
2012-07-24 10:47:44 -07:00
return getDirectMethodCommon ( refKind , refc , method ,
( refKind = = REF_invokeSpecial | |
( MethodHandleNatives . refKindHasReceiver ( refKind ) & &
2013-02-22 03:00:48 -08:00
restrictProtectedReceiver ( method ) ) ) , callerClass ) ;
2012-07-24 10:47:44 -07:00
}
2013-02-22 03:00:48 -08:00
private MethodHandle getDirectMethodNoRestrict ( byte refKind , Class < ? > refc , MemberName method , Class < ? > callerClass ) throws IllegalAccessException {
return getDirectMethodCommon ( refKind , refc , method , false , callerClass ) ;
2012-07-24 10:47:44 -07:00
}
private MethodHandle getDirectMethodCommon ( byte refKind , Class < ? > refc , MemberName method ,
2013-02-22 03:00:48 -08:00
boolean doRestrict , Class < ? > callerClass ) throws IllegalAccessException {
2012-07-24 10:47:44 -07:00
checkMethod ( refKind , refc , method ) ;
2013-09-03 21:42:56 -07:00
assert ( ! method . isMethodHandleInvoke ( ) ) ;
2013-03-01 04:45:12 +04:00
Class < ? > refcAsSuper ;
if ( refKind = = REF_invokeSpecial & &
refc ! = lookupClass ( ) & &
2013-09-03 21:42:56 -07:00
! refc . isInterface ( ) & &
2013-03-01 04:45:12 +04:00
refc ! = ( refcAsSuper = lookupClass ( ) . getSuperclass ( ) ) & &
refc . isAssignableFrom ( lookupClass ( ) ) ) {
assert ( ! method . getName ( ) . equals ( " <init> " ) ) ; // not this code path
// Per JVMS 6.5, desc. of invokespecial instruction:
// If the method is in a superclass of the LC,
// and if our original search was above LC.super,
// repeat the search (symbolic lookup) from LC.super.
// FIXME: MemberName.resolve should handle this instead.
MemberName m2 = new MemberName ( refcAsSuper ,
method . getName ( ) ,
method . getMethodType ( ) ,
REF_invokeSpecial ) ;
m2 = IMPL_NAMES . resolveOrNull ( refKind , m2 , lookupClassOrNull ( ) ) ;
if ( m2 = = null ) throw new InternalError ( method . toString ( ) ) ;
method = m2 ;
refc = refcAsSuper ;
// redo basic checks
checkMethod ( refKind , refc , method ) ;
}
2013-02-26 11:05:26 +00:00
MethodHandle mh = DirectMethodHandle . make ( refKind , refc , method ) ;
2013-02-22 03:00:48 -08:00
mh = maybeBindCaller ( method , mh , callerClass ) ;
2012-07-24 10:47:44 -07:00
mh = mh . setVarargs ( method ) ;
if ( doRestrict )
mh = restrictReceiver ( method , mh , lookupClass ( ) ) ;
return mh ;
}
2013-02-22 03:00:48 -08:00
private MethodHandle maybeBindCaller ( MemberName method , MethodHandle mh ,
Class < ? > callerClass )
throws IllegalAccessException {
2012-09-20 14:02:55 -07:00
if ( allowedModes = = TRUSTED | | ! MethodHandleNatives . isCallerSensitive ( method ) )
return mh ;
Class < ? > hostClass = lookupClass ;
if ( ( allowedModes & PRIVATE ) = = 0 ) // caller must use full-power lookup
2013-02-22 03:00:48 -08:00
hostClass = callerClass ; // callerClass came from a security manager style stack walk
2012-09-20 14:02:55 -07:00
MethodHandle cbmh = MethodHandleImpl . bindCaller ( mh , hostClass ) ;
// Note: caller will apply varargs after this step happens.
return cbmh ;
}
2012-07-24 10:47:44 -07:00
private MethodHandle getDirectField ( byte refKind , Class < ? > refc , MemberName field ) throws IllegalAccessException {
checkField ( refKind , refc , field ) ;
MethodHandle mh = DirectMethodHandle . make ( refc , field ) ;
boolean doRestrict = ( MethodHandleNatives . refKindHasReceiver ( refKind ) & &
restrictProtectedReceiver ( field ) ) ;
if ( doRestrict )
mh = restrictReceiver ( field , mh , lookupClass ( ) ) ;
return mh ;
}
private MethodHandle getDirectConstructor ( Class < ? > refc , MemberName ctor ) throws IllegalAccessException {
assert ( ctor . isConstructor ( ) ) ;
checkAccess ( REF_newInvokeSpecial , refc , ctor ) ;
2012-09-20 14:02:55 -07:00
assert ( ! MethodHandleNatives . isCallerSensitive ( ctor ) ) ; // maybeBindCaller not relevant here
2012-07-24 10:47:44 -07:00
return DirectMethodHandle . make ( ctor ) . setVarargs ( ctor ) ;
2009-05-05 22:40:09 -07:00
}
2011-06-01 23:56:47 -07:00
/ * * Hook called from the JVM ( via MethodHandleNatives ) to link MH constants :
* /
/*non-public*/
2012-07-24 10:47:44 -07:00
MethodHandle linkMethodHandleConstant ( byte refKind , Class < ? > defc , String name , Object type ) throws ReflectiveOperationException {
2013-10-05 05:30:38 -07:00
if ( ! ( type instanceof Class | | type instanceof MethodType ) )
throw new InternalError ( " unresolved MemberName " ) ;
MemberName member = new MemberName ( refKind , defc , name , type ) ;
MethodHandle mh = LOOKASIDE_TABLE . get ( member ) ;
if ( mh ! = null ) {
checkSymbolicClass ( defc ) ;
return mh ;
}
MemberName resolved = resolveOrFail ( refKind , member ) ;
mh = getDirectMethodHandle ( refKind , defc , resolved ) ;
if ( mh instanceof DirectMethodHandle
& & canBeCached ( refKind , defc , resolved ) ) {
MemberName key = mh . internalMemberName ( ) ;
if ( key ! = null ) {
key = key . asNormalOriginal ( ) ;
}
if ( member . equals ( key ) ) { // better safe than sorry
LOOKASIDE_TABLE . put ( key , ( DirectMethodHandle ) mh ) ;
}
2012-07-24 10:47:44 -07:00
}
2013-10-05 05:30:38 -07:00
return mh ;
}
private
boolean canBeCached ( byte refKind , Class < ? > defc , MemberName member ) {
if ( refKind = = REF_invokeSpecial ) {
return false ;
}
if ( ! Modifier . isPublic ( defc . getModifiers ( ) ) | |
! Modifier . isPublic ( member . getDeclaringClass ( ) . getModifiers ( ) ) | |
! member . isPublic ( ) | |
member . isCallerSensitive ( ) ) {
return false ;
}
ClassLoader loader = defc . getClassLoader ( ) ;
if ( ! sun . misc . VM . isSystemDomainLoader ( loader ) ) {
ClassLoader sysl = ClassLoader . getSystemClassLoader ( ) ;
boolean found = false ;
while ( sysl ! = null ) {
if ( loader = = sysl ) { found = true ; break ; }
sysl = sysl . getParent ( ) ;
}
if ( ! found ) {
return false ;
}
}
try {
MemberName resolved2 = publicLookup ( ) . resolveOrFail ( refKind ,
new MemberName ( refKind , defc , member . getName ( ) , member . getType ( ) ) ) ;
checkSecurityManager ( defc , resolved2 ) ;
} catch ( ReflectiveOperationException | SecurityException ex ) {
return false ;
}
return true ;
}
private
MethodHandle getDirectMethodHandle ( byte refKind , Class < ? > defc , MemberName member ) throws ReflectiveOperationException {
2012-07-24 10:47:44 -07:00
if ( MethodHandleNatives . refKindIsField ( refKind ) ) {
2013-10-05 05:30:38 -07:00
return getDirectField ( refKind , defc , member ) ;
2012-07-24 10:47:44 -07:00
} else if ( MethodHandleNatives . refKindIsMethod ( refKind ) ) {
2013-10-05 05:30:38 -07:00
return getDirectMethod ( refKind , defc , member , lookupClass ) ;
2012-07-24 10:47:44 -07:00
} else if ( refKind = = REF_newInvokeSpecial ) {
2013-10-05 05:30:38 -07:00
return getDirectConstructor ( defc , member ) ;
2011-06-01 23:56:47 -07:00
}
// oops
2013-10-05 05:30:38 -07:00
throw newIllegalArgumentException ( " bad MethodHandle constant # " + member ) ;
2011-06-01 23:56:47 -07:00
}
2013-10-05 05:30:38 -07:00
static ConcurrentHashMap < MemberName , DirectMethodHandle > LOOKASIDE_TABLE = new ConcurrentHashMap < > ( ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving read access to elements of an array .
2009-05-05 22:40:09 -07:00
* The type of the method handle will have a return type of the array ' s
* element type . Its first argument will be the array type ,
* and the second will be { @code int } .
* @param arrayClass an array type
* @return a method handle which can load values from the given array type
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* @throws IllegalArgumentException if arrayClass is not an array type
* /
public static
MethodHandle arrayElementGetter ( Class < ? > arrayClass ) throws IllegalArgumentException {
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeArrayElementAccessor ( arrayClass , false ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle giving write access to elements of an array .
2009-05-05 22:40:09 -07:00
* The type of the method handle will have a void return type .
* Its last argument will be the array ' s element type .
* The first and second arguments will be the array type and int .
2013-06-27 19:02:02 -07:00
* @param arrayClass the class of an array
2009-05-05 22:40:09 -07:00
* @return a method handle which can store values into the array type
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if the argument is null
2009-05-05 22:40:09 -07:00
* @throws IllegalArgumentException if arrayClass is not an array type
* /
public static
MethodHandle arrayElementSetter ( Class < ? > arrayClass ) throws IllegalArgumentException {
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeArrayElementAccessor ( arrayClass , true ) ;
2009-05-05 22:40:09 -07:00
}
/// method handle invocation (reflective style)
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which will invoke any method handle of the
2011-05-26 17:37:36 -07:00
* given { @code type } , with a given number of trailing arguments replaced by
* a single trailing { @code Object [ ] } array .
2010-01-07 16:16:45 -08:00
* The resulting invoker will be a method handle with the following
* arguments :
* < ul >
* < li > a single { @code MethodHandle } target
2011-05-26 17:37:36 -07:00
* < li > zero or more leading values ( counted by { @code leadingArgCount } )
* < li > an { @code Object [ ] } array containing trailing arguments
2010-01-07 16:16:45 -08:00
* < / ul >
2010-10-30 21:08:23 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* The invoker will invoke its target like a call to { @link MethodHandle # invoke invoke } with
2010-10-30 21:08:23 -07:00
* the indicated { @code type } .
* That is , if the target is exactly of the given { @code type } , it will behave
2011-02-11 01:26:28 -08:00
* like { @code invokeExact } ; otherwise it behave as if { @link MethodHandle # asType asType }
2010-10-30 21:08:23 -07:00
* is used to convert the target to the required { @code type } .
* < p >
* The type of the returned invoker will not be the given { @code type } , but rather
2011-05-26 17:37:36 -07:00
* will have all parameters except the first { @code leadingArgCount }
* replaced by a single array of type { @code Object [ ] } , which will be
* the final parameter .
2010-10-30 21:08:23 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* Before invoking its target , the invoker will spread the final array , apply
2010-10-30 21:08:23 -07:00
* reference casts as necessary , and unbox and widen primitive arguments .
2013-10-05 05:30:39 -07:00
* If , when the invoker is called , the supplied array argument does
* not have the correct number of elements , the invoker will throw
* an { @link IllegalArgumentException } instead of invoking the target .
2010-01-07 16:16:45 -08:00
* < p >
* This method is equivalent to the following code ( though it may be more efficient ) :
* < p > < blockquote > < pre >
2011-05-12 19:27:33 -07:00
MethodHandle invoker = MethodHandles . invoker ( type ) ;
2011-05-26 17:37:36 -07:00
int spreadArgCount = type . parameterCount ( ) - leadingArgCount ;
2011-02-11 01:26:24 -08:00
invoker = invoker . asSpreader ( Object [ ] . class , spreadArgCount ) ;
return invoker ;
2010-01-07 16:16:45 -08:00
* < / pre > < / blockquote >
2011-02-11 01:26:28 -08:00
* < p >
* This method throws no reflective or security exceptions .
2009-05-05 22:40:09 -07:00
* @param type the desired target type
2011-05-26 17:37:36 -07:00
* @param leadingArgCount number of fixed arguments , to be passed unchanged to the target
2009-05-05 22:40:09 -07:00
* @return a method handle suitable for invoking any method handle of the given type
2011-05-26 17:37:36 -07:00
* @throws NullPointerException if { @code type } is null
* @throws IllegalArgumentException if { @code leadingArgCount } is not in
2013-10-05 05:30:39 -07:00
* the range from 0 to { @code type . parameterCount ( ) } inclusive ,
* or if the resulting method handle ' s type would have
* < a href = " MethodHandle.html#maxarity " > too many parameters < / a >
2009-05-05 22:40:09 -07:00
* /
static public
2011-05-26 17:37:36 -07:00
MethodHandle spreadInvoker ( MethodType type , int leadingArgCount ) {
if ( leadingArgCount < 0 | | leadingArgCount > type . parameterCount ( ) )
throw new IllegalArgumentException ( " bad argument count " + leadingArgCount ) ;
return type . invokers ( ) . spreadInvoker ( leadingArgCount ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a special < em > invoker method handle < / em > which can be used to
2011-05-12 19:27:33 -07:00
* invoke any method handle of the given type , as if by { @link MethodHandle # invokeExact invokeExact } .
2011-02-11 01:26:28 -08:00
* The resulting invoker will have a type which is
2009-05-05 22:40:09 -07:00
* exactly equal to the desired type , except that it will accept
* an additional leading argument of type { @code MethodHandle } .
* < p >
2010-01-07 16:16:45 -08:00
* This method is equivalent to the following code ( though it may be more efficient ) :
* < p > < blockquote > < pre >
2011-02-11 01:26:28 -08:00
publicLookup ( ) . findVirtual ( MethodHandle . class , " invokeExact " , type )
2010-01-07 16:16:45 -08:00
* < / pre > < / blockquote >
2011-02-11 01:26:28 -08:00
*
* < p style = " font-size:smaller; " >
* < em > Discussion : < / em >
* Invoker method handles can be useful when working with variable method handles
* of unknown types .
* For example , to emulate an { @code invokeExact } call to a variable method
* handle { @code M } , extract its type { @code T } ,
* look up the invoker method { @code X } for { @code T } ,
2011-05-12 19:27:33 -07:00
* and call the invoker method , as { @code X . invoke ( T , A . . . ) } .
2011-02-11 01:26:28 -08:00
* ( It would not work to call { @code X . invokeExact } , since the type { @code T }
* is unknown . )
* If spreading , collecting , or other argument transformations are required ,
* they can be applied once to the invoker { @code X } and reused on many { @code M }
* method handle values , as long as they are compatible with the type of { @code X } .
* < p >
* < em > ( Note : The invoker method is not available via the Core Reflection API .
2011-05-26 17:37:36 -07:00
* An attempt to call { @linkplain java . lang . reflect . Method # invoke java . lang . reflect . Method . invoke }
2011-05-12 19:27:33 -07:00
* on the declared { @code invokeExact } or { @code invoke } method will raise an
2011-02-11 01:26:28 -08:00
* { @link java . lang . UnsupportedOperationException UnsupportedOperationException } . ) < / em >
* < p >
* This method throws no reflective or security exceptions .
2009-05-05 22:40:09 -07:00
* @param type the desired target type
* @return a method handle suitable for invoking any method handle of the given type
2013-10-05 05:30:39 -07:00
* @throws IllegalArgumentException if the resulting method handle ' s type would have
* < a href = " MethodHandle.html#maxarity " > too many parameters < / a >
2009-05-05 22:40:09 -07:00
* /
static public
MethodHandle exactInvoker ( MethodType type ) {
2011-03-18 00:03:24 -07:00
return type . invokers ( ) . exactInvoker ( ) ;
2009-05-05 22:40:09 -07:00
}
2011-02-11 01:26:28 -08:00
/ * *
* Produces a special < em > invoker method handle < / em > which can be used to
2011-05-12 19:27:33 -07:00
* invoke any method handle compatible with the given type , as if by { @link MethodHandle # invoke invoke } .
2011-02-11 01:26:28 -08:00
* The resulting invoker will have a type which is
* exactly equal to the desired type , except that it will accept
* an additional leading argument of type { @code MethodHandle } .
* < p >
2011-05-26 17:37:36 -07:00
* Before invoking its target , if the target differs from the expected type ,
* the invoker will apply reference casts as
2011-05-12 19:27:33 -07:00
* necessary and box , unbox , or widen primitive values , as if by { @link MethodHandle # asType asType } .
* Similarly , the return value will be converted as necessary .
* If the target is a { @linkplain MethodHandle # asVarargsCollector variable arity method handle } ,
* the required arity conversion will be made , again as if by { @link MethodHandle # asType asType } .
2011-02-11 01:26:28 -08:00
* < p >
2011-05-26 17:37:36 -07:00
* A { @linkplain MethodType # genericMethodType general method type } ,
* mentions only { @code Object } arguments and return values .
* An invoker for such a type is capable of calling any method handle
* of the same arity as the general type .
* < p >
2011-02-11 01:26:28 -08:00
* This method is equivalent to the following code ( though it may be more efficient ) :
* < p > < blockquote > < pre >
2011-05-12 19:27:33 -07:00
publicLookup ( ) . findVirtual ( MethodHandle . class , " invoke " , type )
2011-02-11 01:26:28 -08:00
* < / pre > < / blockquote >
* < p >
* This method throws no reflective or security exceptions .
* @param type the desired target type
* @return a method handle suitable for invoking any method handle convertible to the given type
2013-10-05 05:30:39 -07:00
* @throws IllegalArgumentException if the resulting method handle ' s type would have
* < a href = " MethodHandle.html#maxarity " > too many parameters < / a >
2011-02-11 01:26:28 -08:00
* /
static public
2011-05-12 19:27:33 -07:00
MethodHandle invoker ( MethodType type ) {
return type . invokers ( ) . generalInvoker ( ) ;
}
2012-07-24 10:47:44 -07:00
static /*non-public*/
MethodHandle basicInvoker ( MethodType type ) {
return type . form ( ) . basicInvoker ( ) ;
2009-05-05 22:40:09 -07:00
}
2012-07-24 10:47:44 -07:00
/// method handle modification (creation from other method handles)
2009-05-05 22:40:09 -07:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which adapts the type of the
2011-05-26 17:37:36 -07:00
* given method handle to a new type by pairwise argument and return type conversion .
2010-10-30 21:08:23 -07:00
* The original type and new type must have the same number of arguments .
* The resulting method handle is guaranteed to report a type
* which is equal to the desired new type .
* < p >
* If the original type and new type are equal , returns target .
* < p >
2011-05-26 17:37:36 -07:00
* The same conversions are allowed as for { @link MethodHandle # asType MethodHandle . asType } ,
2010-10-30 21:08:23 -07:00
* and some additional conversions are also applied if those conversions fail .
2011-05-26 17:37:36 -07:00
* Given types < em > T0 < / em > , < em > T1 < / em > , one of the following conversions is applied
* if possible , before or instead of any conversions done by { @code asType } :
2010-10-30 21:08:23 -07:00
* < ul >
2011-05-26 17:37:36 -07:00
* < li > If < em > T0 < / em > and < em > T1 < / em > are references , and < em > T1 < / em > is an interface type ,
* then the value of type < em > T0 < / em > is passed as a < em > T1 < / em > without a cast .
2010-10-30 21:08:23 -07:00
* ( This treatment of interfaces follows the usage of the bytecode verifier . )
2011-05-26 17:37:36 -07:00
* < li > If < em > T0 < / em > is boolean and < em > T1 < / em > is another primitive ,
* the boolean is converted to a byte value , 1 for true , 0 for false .
2010-10-30 21:08:23 -07:00
* ( This treatment follows the usage of the bytecode verifier . )
2011-05-26 17:37:36 -07:00
* < li > If < em > T1 < / em > is boolean and < em > T0 < / em > is another primitive ,
* < em > T0 < / em > is converted to byte via Java casting conversion ( JLS 5 . 5 ) ,
* and the low order bit of the result is tested , as if by { @code ( x & 1 ) ! = 0 } .
* < li > If < em > T0 < / em > and < em > T1 < / em > are primitives other than boolean ,
* then a Java casting conversion ( JLS 5 . 5 ) is applied .
* ( Specifically , < em > T0 < / em > will convert to < em > T1 < / em > by
* widening and / or narrowing . )
* < li > If < em > T0 < / em > is a reference and < em > T1 < / em > a primitive , an unboxing
* conversion will be applied at runtime , possibly followed
* by a Java casting conversion ( JLS 5 . 5 ) on the primitive value ,
* possibly followed by a conversion from byte to boolean by testing
* the low - order bit .
* < li > If < em > T0 < / em > is a reference and < em > T1 < / em > a primitive ,
* and if the reference is null at runtime , a zero value is introduced .
2010-10-30 21:08:23 -07:00
* < / ul >
* @param target the method handle to invoke after arguments are retyped
* @param newType the expected type of the new method handle
2011-05-26 17:37:36 -07:00
* @return a method handle which delegates to the target after performing
2010-10-30 21:08:23 -07:00
* any necessary argument conversions , and arranges for any
* necessary return value conversions
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if either argument is null
2010-10-30 21:08:23 -07:00
* @throws WrongMethodTypeException if the conversion cannot be made
* @see MethodHandle # asType
* /
public static
MethodHandle explicitCastArguments ( MethodHandle target , MethodType newType ) {
2012-07-24 10:47:44 -07:00
if ( ! target . type ( ) . isCastableTo ( newType ) ) {
throw new WrongMethodTypeException ( " cannot explicitly cast " + target + " to " + newType ) ;
}
return MethodHandleImpl . makePairwiseConvert ( target , newType , 2 ) ;
2010-10-30 21:08:23 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which adapts the calling sequence of the
2009-05-05 22:40:09 -07:00
* given method handle to a new type , by reordering the arguments .
2010-10-30 21:08:23 -07:00
* The resulting method handle is guaranteed to report a type
2009-05-05 22:40:09 -07:00
* which is equal to the desired new type .
* < p >
* The given array controls the reordering .
* Call { @code # I } the number of incoming parameters ( the value
* { @code newType . parameterCount ( ) } , and call { @code # O } the number
* of outgoing parameters ( the value { @code target . type ( ) . parameterCount ( ) } ) .
* Then the length of the reordering array must be { @code # O } ,
* and each element must be a non - negative number less than { @code # I } .
* For every { @code N } less than { @code # O } , the { @code N } - th
* outgoing argument will be taken from the { @code I } - th incoming
* argument , where { @code I } is { @code reorder [ N ] } .
* < p >
2010-10-30 21:08:23 -07:00
* No argument or return value conversions are applied .
* The type of each incoming argument , as determined by { @code newType } ,
2011-05-26 17:37:36 -07:00
* must be identical to the type of the corresponding outgoing parameter
* or parameters in the target method handle .
2010-10-30 21:08:23 -07:00
* The return type of { @code newType } must be identical to the return
* type of the original target .
* < p >
2009-05-05 22:40:09 -07:00
* The reordering array need not specify an actual permutation .
* An incoming argument will be duplicated if its index appears
* more than once in the array , and an incoming argument will be dropped
* if its index does not appear in the array .
2010-10-30 21:08:23 -07:00
* As in the case of { @link # dropArguments ( MethodHandle , int , List ) dropArguments } ,
* incoming arguments which are not mentioned in the reordering array
* are may be any type , as determined only by { @code newType } .
2013-06-10 12:58:32 +01:00
* < blockquote > < pre > { @code
2011-05-26 17:37:36 -07:00
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
. . .
MethodType intfn1 = methodType ( int . class , int . class ) ;
MethodType intfn2 = methodType ( int . class , int . class , int . class ) ;
2013-06-27 19:02:02 -07:00
MethodHandle sub = . . . ( int x , int y ) - > ( x - y ) . . . ;
2010-10-30 21:08:23 -07:00
assert ( sub . type ( ) . equals ( intfn2 ) ) ;
2011-05-26 17:37:36 -07:00
MethodHandle sub1 = permuteArguments ( sub , intfn2 , 0 , 1 ) ;
MethodHandle rsub = permuteArguments ( sub , intfn2 , 1 , 0 ) ;
2010-10-30 21:08:23 -07:00
assert ( ( int ) rsub . invokeExact ( 1 , 100 ) = = 99 ) ;
2013-06-27 19:02:02 -07:00
MethodHandle add = . . . ( int x , int y ) - > ( x + y ) . . . ;
2010-10-30 21:08:23 -07:00
assert ( add . type ( ) . equals ( intfn2 ) ) ;
2011-05-26 17:37:36 -07:00
MethodHandle twice = permuteArguments ( add , intfn1 , 0 , 0 ) ;
2010-10-30 21:08:23 -07:00
assert ( twice . type ( ) . equals ( intfn1 ) ) ;
assert ( ( int ) twice . invokeExact ( 21 ) = = 42 ) ;
2013-06-10 12:58:32 +01:00
* } < / pre > < / blockquote >
2009-05-05 22:40:09 -07:00
* @param target the method handle to invoke after arguments are reordered
* @param newType the expected type of the new method handle
2011-05-26 17:37:36 -07:00
* @param reorder an index array which controls the reordering
* @return a method handle which delegates to the target after it
2010-10-30 21:08:23 -07:00
* drops unused arguments and moves and / or duplicates the other arguments
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if any argument is null
2011-05-26 17:37:36 -07:00
* @throws IllegalArgumentException if the index array length is not equal to
* the arity of the target , or if any index array element
* not a valid index for a parameter of { @code newType } ,
* or if two corresponding parameter types in
* { @code target . type ( ) } and { @code newType } are not identical ,
2009-05-05 22:40:09 -07:00
* /
public static
2010-10-30 21:08:23 -07:00
MethodHandle permuteArguments ( MethodHandle target , MethodType newType , int . . . reorder ) {
2012-07-24 10:47:44 -07:00
checkReorder ( reorder , newType , target . type ( ) ) ;
return target . permuteArguments ( newType , reorder ) ;
2009-05-05 22:40:09 -07:00
}
private static void checkReorder ( int [ ] reorder , MethodType newType , MethodType oldType ) {
2011-05-12 19:27:49 -07:00
if ( newType . returnType ( ) ! = oldType . returnType ( ) )
throw newIllegalArgumentException ( " return types do not match " ,
oldType , newType ) ;
2009-05-05 22:40:09 -07:00
if ( reorder . length = = oldType . parameterCount ( ) ) {
int limit = newType . parameterCount ( ) ;
boolean bad = false ;
2011-05-12 19:27:49 -07:00
for ( int j = 0 ; j < reorder . length ; j + + ) {
int i = reorder [ j ] ;
2009-05-05 22:40:09 -07:00
if ( i < 0 | | i > = limit ) {
bad = true ; break ;
}
2011-05-12 19:27:49 -07:00
Class < ? > src = newType . parameterType ( i ) ;
Class < ? > dst = oldType . parameterType ( j ) ;
if ( src ! = dst )
throw newIllegalArgumentException ( " parameter types do not match after reorder " ,
oldType , newType ) ;
2009-05-05 22:40:09 -07:00
}
if ( ! bad ) return ;
}
2011-05-12 19:27:49 -07:00
throw newIllegalArgumentException ( " bad reorder array: " + Arrays . toString ( reorder ) ) ;
2009-05-05 22:40:09 -07:00
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle of the requested return type which returns the given
2010-10-30 21:08:23 -07:00
* constant value every time it is invoked .
* < p >
* Before the method handle is returned , the passed - in value is converted to the requested type .
* If the requested type is primitive , widening primitive conversions are attempted ,
* else reference conversions are attempted .
2011-05-26 17:37:36 -07:00
* < p > The returned method handle is equivalent to { @code identity ( type ) . bindTo ( value ) } .
2010-10-30 21:08:23 -07:00
* @param type the return type of the desired method handle
* @param value the value to return
* @return a method handle of the given return type and no arguments , which always returns the given value
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if the { @code type } argument is null
* @throws ClassCastException if the value cannot be converted to the required return type
* @throws IllegalArgumentException if the given type is { @code void . class }
2010-10-30 21:08:23 -07:00
* /
public static
MethodHandle constant ( Class < ? > type , Object value ) {
if ( type . isPrimitive ( ) ) {
2011-02-11 01:26:28 -08:00
if ( type = = void . class )
throw newIllegalArgumentException ( " void type " ) ;
2010-10-30 21:08:23 -07:00
Wrapper w = Wrapper . forPrimitiveType ( type ) ;
2011-05-12 19:27:49 -07:00
return insertArguments ( identity ( type ) , 0 , w . convert ( value , type ) ) ;
2010-10-30 21:08:23 -07:00
} else {
return identity ( type ) . bindTo ( type . cast ( value ) ) ;
}
}
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which returns its sole argument when invoked .
* @param type the type of the sole parameter and return value of the desired method handle
* @return a unary method handle which accepts and returns the given type
* @throws NullPointerException if the argument is null
* @throws IllegalArgumentException if the given type is { @code void . class }
2010-10-30 21:08:23 -07:00
* /
public static
MethodHandle identity ( Class < ? > type ) {
2011-02-11 01:26:28 -08:00
if ( type = = void . class )
throw newIllegalArgumentException ( " void type " ) ;
2011-03-18 00:03:24 -07:00
else if ( type = = Object . class )
return ValueConversions . identity ( ) ;
else if ( type . isPrimitive ( ) )
return ValueConversions . identity ( Wrapper . forPrimitiveType ( type ) ) ;
else
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeReferenceIdentity ( type ) ;
2010-10-30 21:08:23 -07:00
}
/ * *
2011-05-26 17:37:36 -07:00
* Provides a target method handle with one or more < em > bound arguments < / em >
* in advance of the method handle ' s invocation .
* The formal parameters to the target corresponding to the bound
* arguments are called < em > bound parameters < / em > .
* Returns a new method handle which saves away the bound arguments .
* When it is invoked , it receives arguments for any non - bound parameters ,
* binds the saved arguments to their corresponding parameters ,
* and calls the original target .
* < p >
2010-01-07 16:16:45 -08:00
* The type of the new method handle will drop the types for the bound
* parameters from the original target type , since the new method handle
* will no longer require those arguments to be supplied by its callers .
2009-05-05 22:40:09 -07:00
* < p >
2010-01-07 16:16:45 -08:00
* Each given argument object must match the corresponding bound parameter type .
* If a bound parameter type is a primitive , the argument object
* must be a wrapper , and will be unboxed to produce the primitive value .
2009-05-05 22:40:09 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* The { @code pos } argument selects which parameters are to be bound .
* It may range between zero and < i > N - L < / i > ( inclusively ) ,
* where < i > N < / i > is the arity of the target method handle
* and < i > L < / i > is the length of the values array .
2009-05-05 22:40:09 -07:00
* @param target the method handle to invoke after the argument is inserted
* @param pos where to insert the argument ( zero for the first )
2010-01-07 16:16:45 -08:00
* @param values the series of arguments to insert
2010-10-30 21:08:23 -07:00
* @return a method handle which inserts an additional argument ,
2009-05-05 22:40:09 -07:00
* before calling the original method handle
2011-05-26 17:37:36 -07:00
* @throws NullPointerException if the target or the { @code values } array is null
2010-10-30 21:08:23 -07:00
* @see MethodHandle # bindTo
2009-05-05 22:40:09 -07:00
* /
public static
2010-01-07 16:16:45 -08:00
MethodHandle insertArguments ( MethodHandle target , int pos , Object . . . values ) {
int insCount = values . length ;
2009-05-05 22:40:09 -07:00
MethodType oldType = target . type ( ) ;
int outargs = oldType . parameterCount ( ) ;
2010-01-07 16:16:45 -08:00
int inargs = outargs - insCount ;
if ( inargs < 0 )
throw newIllegalArgumentException ( " too many values to insert " ) ;
if ( pos < 0 | | pos > inargs )
2009-05-05 22:40:09 -07:00
throw newIllegalArgumentException ( " no argument type to append " ) ;
2010-01-07 16:16:45 -08:00
MethodHandle result = target ;
for ( int i = 0 ; i < insCount ; i + + ) {
Object value = values [ i ] ;
2012-07-24 10:47:44 -07:00
Class < ? > ptype = oldType . parameterType ( pos + i ) ;
if ( ptype . isPrimitive ( ) ) {
char btype = 'I' ;
Wrapper w = Wrapper . forPrimitiveType ( ptype ) ;
switch ( w ) {
case LONG : btype = 'J' ; break ;
case FLOAT : btype = 'F' ; break ;
case DOUBLE : btype = 'D' ; break ;
2010-01-07 16:16:45 -08:00
}
2012-07-24 10:47:44 -07:00
// perform unboxing and/or primitive conversion
value = w . convert ( value , ptype ) ;
result = result . bindArgument ( pos , btype , value ) ;
continue ;
}
value = ptype . cast ( value ) ; // throw CCE if needed
if ( pos = = 0 ) {
result = result . bindReceiver ( value ) ;
} else {
result = result . bindArgument ( pos , 'L' , value ) ;
2010-01-07 16:16:45 -08:00
}
2009-05-05 22:40:09 -07:00
}
2010-01-07 16:16:45 -08:00
return result ;
}
2009-05-05 22:40:09 -07:00
/ * *
2011-05-26 17:37:36 -07:00
* Produces a method handle which will discard some dummy arguments
* before calling some other specified < i > target < / i > method handle .
* The type of the new method handle will be the same as the target ' s type ,
* except it will also include the dummy argument types ,
* at some given position .
2009-05-05 22:40:09 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* The { @code pos } argument may range between zero and < i > N < / i > ,
* where < i > N < / i > is the arity of the target .
* If { @code pos } is zero , the dummy arguments will precede
* the target ' s real arguments ; if { @code pos } is < i > N < / i >
* they will come after .
2010-01-07 16:16:45 -08:00
* < p >
* < b > Example : < / b >
* < p > < blockquote > < pre >
2011-03-23 23:02:31 -07:00
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
2010-12-16 15:59:27 -08:00
. . .
MethodHandle cat = lookup ( ) . findVirtual ( String . class ,
" concat " , methodType ( String . class , String . class ) ) ;
assertEquals ( " xy " , ( String ) cat . invokeExact ( " x " , " y " ) ) ;
2011-03-23 23:02:31 -07:00
MethodType bigType = cat . type ( ) . insertParameterTypes ( 0 , int . class , String . class ) ;
MethodHandle d0 = dropArguments ( cat , 0 , bigType . parameterList ( ) . subList ( 0 , 2 ) ) ;
assertEquals ( bigType , d0 . type ( ) ) ;
assertEquals ( " yz " , ( String ) d0 . invokeExact ( 123 , " x " , " y " , " z " ) ) ;
* < / pre > < / blockquote >
* < p >
* This method is also equivalent to the following code :
* < p > < blockquote > < pre >
* { @link # dropArguments ( MethodHandle , int , Class . . . ) dropArguments } ( target , pos , valueTypes . toArray ( new Class [ 0 ] ) )
2010-01-07 16:16:45 -08:00
* < / pre > < / blockquote >
2010-10-30 21:08:23 -07:00
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type ( s ) of the argument ( s ) to drop
* @param pos position of first argument to drop ( zero for the leftmost )
* @return a method handle which drops arguments of the given types ,
2009-05-05 22:40:09 -07:00
* before calling the original method handle
2011-05-26 17:37:36 -07:00
* @throws NullPointerException if the target is null ,
2011-02-11 01:26:28 -08:00
* or if the { @code valueTypes } list or any of its elements is null
2011-05-26 17:37:36 -07:00
* @throws IllegalArgumentException if any element of { @code valueTypes } is { @code void . class } ,
* or if { @code pos } is negative or greater than the arity of the target ,
* or if the new method handle ' s type would have too many parameters
2009-05-05 22:40:09 -07:00
* /
public static
2010-01-07 16:16:45 -08:00
MethodHandle dropArguments ( MethodHandle target , int pos , List < Class < ? > > valueTypes ) {
2011-05-26 17:37:36 -07:00
MethodType oldType = target . type ( ) ; // get NPE
2012-07-24 10:47:44 -07:00
int dropped = valueTypes . size ( ) ;
MethodType . checkSlotCount ( dropped ) ;
if ( dropped = = 0 ) return target ;
2009-05-05 22:40:09 -07:00
int outargs = oldType . parameterCount ( ) ;
2012-07-24 10:47:44 -07:00
int inargs = outargs + dropped ;
2009-05-05 22:40:09 -07:00
if ( pos < 0 | | pos > = inargs )
throw newIllegalArgumentException ( " no argument type to remove " ) ;
2012-07-24 10:47:44 -07:00
ArrayList < Class < ? > > ptypes = new ArrayList < > ( oldType . parameterList ( ) ) ;
2010-01-07 16:16:45 -08:00
ptypes . addAll ( pos , valueTypes ) ;
MethodType newType = MethodType . methodType ( oldType . returnType ( ) , ptypes ) ;
2012-07-24 10:47:44 -07:00
return target . dropArguments ( newType , pos , dropped ) ;
2009-05-05 22:40:09 -07:00
}
2010-10-30 21:08:23 -07:00
/ * *
2011-05-26 17:37:36 -07:00
* Produces a method handle which will discard some dummy arguments
* before calling some other specified < i > target < / i > method handle .
* The type of the new method handle will be the same as the target ' s type ,
* except it will also include the dummy argument types ,
* at some given position .
2011-03-23 23:02:31 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* The { @code pos } argument may range between zero and < i > N < / i > ,
* where < i > N < / i > is the arity of the target .
* If { @code pos } is zero , the dummy arguments will precede
* the target ' s real arguments ; if { @code pos } is < i > N < / i >
* they will come after .
2011-03-23 23:02:31 -07:00
* < p >
* < b > Example : < / b >
* < p > < blockquote > < pre >
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
. . .
MethodHandle cat = lookup ( ) . findVirtual ( String . class ,
" concat " , methodType ( String . class , String . class ) ) ;
assertEquals ( " xy " , ( String ) cat . invokeExact ( " x " , " y " ) ) ;
MethodHandle d0 = dropArguments ( cat , 0 , String . class ) ;
assertEquals ( " yz " , ( String ) d0 . invokeExact ( " x " , " y " , " z " ) ) ;
MethodHandle d1 = dropArguments ( cat , 1 , String . class ) ;
assertEquals ( " xz " , ( String ) d1 . invokeExact ( " x " , " y " , " z " ) ) ;
MethodHandle d2 = dropArguments ( cat , 2 , String . class ) ;
assertEquals ( " xy " , ( String ) d2 . invokeExact ( " x " , " y " , " z " ) ) ;
MethodHandle d12 = dropArguments ( cat , 1 , int . class , boolean . class ) ;
assertEquals ( " xz " , ( String ) d12 . invokeExact ( " x " , 12 , true , " z " ) ) ;
* < / pre > < / blockquote >
* < p >
* This method is also equivalent to the following code :
* < p > < blockquote > < pre >
2010-10-30 21:08:23 -07:00
* { @link # dropArguments ( MethodHandle , int , List ) dropArguments } ( target , pos , Arrays . asList ( valueTypes ) )
2011-03-23 23:02:31 -07:00
* < / pre > < / blockquote >
2010-10-30 21:08:23 -07:00
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type ( s ) of the argument ( s ) to drop
* @param pos position of first argument to drop ( zero for the leftmost )
* @return a method handle which drops arguments of the given types ,
* before calling the original method handle
2011-05-26 17:37:36 -07:00
* @throws NullPointerException if the target is null ,
2011-02-11 01:26:28 -08:00
* or if the { @code valueTypes } array or any of its elements is null
2011-05-26 17:37:36 -07:00
* @throws IllegalArgumentException if any element of { @code valueTypes } is { @code void . class } ,
* or if { @code pos } is negative or greater than the arity of the target ,
2013-10-05 05:30:39 -07:00
* or if the new method handle ' s type would have
* < a href = " MethodHandle.html#maxarity " > too many parameters < / a >
2010-10-30 21:08:23 -07:00
* /
2010-01-07 16:16:45 -08:00
public static
MethodHandle dropArguments ( MethodHandle target , int pos , Class < ? > . . . valueTypes ) {
return dropArguments ( target , pos , Arrays . asList ( valueTypes ) ) ;
}
/ * *
2011-05-26 17:37:36 -07:00
* Adapts a target method handle by pre - processing
2010-01-07 16:16:45 -08:00
* one or more of its arguments , each with its own unary filter function ,
* and then calling the target with each pre - processed argument
* replaced by the result of its corresponding filter function .
* < p >
* The pre - processing is performed by one or more method handles ,
2010-10-30 21:08:23 -07:00
* specified in the elements of the { @code filters } array .
2011-05-26 17:37:36 -07:00
* The first element of the filter array corresponds to the { @code pos }
* argument of the target , and so on in sequence .
* < p >
* Null arguments in the array are treated as identity functions ,
* and the corresponding arguments left unchanged .
2011-02-11 01:26:28 -08:00
* ( If there are no non - null elements in the array , the original target is returned . )
2010-10-30 21:08:23 -07:00
* Each filter is applied to the corresponding argument of the adapter .
2010-01-07 16:16:45 -08:00
* < p >
* If a filter { @code F } applies to the { @code N } th argument of
2011-05-26 17:37:36 -07:00
* the target , then { @code F } must be a method handle which
2010-01-07 16:16:45 -08:00
* takes exactly one argument . The type of { @code F } ' s sole argument
* replaces the corresponding argument type of the target
* in the resulting adapted method handle .
* The return type of { @code F } must be identical to the corresponding
* parameter type of the target .
* < p >
2010-10-30 21:08:23 -07:00
* It is an error if there are elements of { @code filters }
2011-05-26 17:37:36 -07:00
* ( null or not )
2010-01-07 16:16:45 -08:00
* which do not correspond to argument positions in the target .
2010-10-30 21:08:23 -07:00
* < b > Example : < / b >
* < p > < blockquote > < pre >
2011-03-23 23:02:31 -07:00
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
2010-10-30 21:08:23 -07:00
. . .
MethodHandle cat = lookup ( ) . findVirtual ( String . class ,
" concat " , methodType ( String . class , String . class ) ) ;
MethodHandle upcase = lookup ( ) . findVirtual ( String . class ,
" toUpperCase " , methodType ( String . class ) ) ;
2010-12-16 15:59:27 -08:00
assertEquals ( " xy " , ( String ) cat . invokeExact ( " x " , " y " ) ) ;
2010-10-30 21:08:23 -07:00
MethodHandle f0 = filterArguments ( cat , 0 , upcase ) ;
2010-12-16 15:59:27 -08:00
assertEquals ( " Xy " , ( String ) f0 . invokeExact ( " x " , " y " ) ) ; // Xy
2010-10-30 21:08:23 -07:00
MethodHandle f1 = filterArguments ( cat , 1 , upcase ) ;
2010-12-16 15:59:27 -08:00
assertEquals ( " xY " , ( String ) f1 . invokeExact ( " x " , " y " ) ) ; // xY
2010-10-30 21:08:23 -07:00
MethodHandle f2 = filterArguments ( cat , 0 , upcase , upcase ) ;
2010-12-16 15:59:27 -08:00
assertEquals ( " XY " , ( String ) f2 . invokeExact ( " x " , " y " ) ) ; // XY
2011-05-26 17:37:36 -07:00
* < / pre > < / blockquote >
* < p > Here is pseudocode for the resulting adapter :
* < blockquote > < pre >
* V target ( P . . . p , A [ i ] . . . a [ i ] , B . . . b ) ;
* A [ i ] filter [ i ] ( V [ i ] ) ;
* T adapter ( P . . . p , V [ i ] . . . v [ i ] , B . . . b ) {
* return target ( p . . . , f [ i ] ( v [ i ] ) . . . , b . . . ) ;
* }
2010-01-07 16:16:45 -08:00
* < / pre > < / blockquote >
2011-02-11 01:26:28 -08:00
*
2010-01-07 16:16:45 -08:00
* @param target the method handle to invoke after arguments are filtered
2010-10-30 21:08:23 -07:00
* @param pos the position of the first argument to filter
2010-01-07 16:16:45 -08:00
* @param filters method handles to call initially on filtered arguments
* @return method handle which incorporates the specified argument filtering logic
2011-05-26 17:37:36 -07:00
* @throws NullPointerException if the target is null
2011-02-11 01:26:28 -08:00
* or if the { @code filters } array is null
* @throws IllegalArgumentException if a non - null element of { @code filters }
2011-05-26 17:37:36 -07:00
* does not match a corresponding argument type of target as described above ,
2013-10-05 05:30:39 -07:00
* or if the { @code pos + filters . length } is greater than { @code target . type ( ) . parameterCount ( ) } ,
* or if the resulting method handle ' s type would have
* < a href = " MethodHandle.html#maxarity " > too many parameters < / a >
2010-01-07 16:16:45 -08:00
* /
public static
2010-10-30 21:08:23 -07:00
MethodHandle filterArguments ( MethodHandle target , int pos , MethodHandle . . . filters ) {
2010-01-07 16:16:45 -08:00
MethodType targetType = target . type ( ) ;
MethodHandle adapter = target ;
2011-05-12 19:27:49 -07:00
MethodType adapterType = null ;
assert ( ( adapterType = targetType ) ! = null ) ;
2010-10-30 21:08:23 -07:00
int maxPos = targetType . parameterCount ( ) ;
2011-02-11 01:26:28 -08:00
if ( pos + filters . length > maxPos )
throw newIllegalArgumentException ( " too many filters " ) ;
int curPos = pos - 1 ; // pre-incremented
2010-01-07 16:16:45 -08:00
for ( MethodHandle filter : filters ) {
2011-02-11 01:26:28 -08:00
curPos + = 1 ;
if ( filter = = null ) continue ; // ignore null elements of filters
2011-05-12 19:27:49 -07:00
adapter = filterArgument ( adapter , curPos , filter ) ;
assert ( ( adapterType = adapterType . changeParameterType ( curPos , filter . type ( ) . parameterType ( 0 ) ) ) ! = null ) ;
2010-01-07 16:16:45 -08:00
}
2011-05-12 19:27:49 -07:00
assert ( adapterType . equals ( adapter . type ( ) ) ) ;
2010-01-07 16:16:45 -08:00
return adapter ;
}
2011-05-12 19:27:49 -07:00
/*non-public*/ static
MethodHandle filterArgument ( MethodHandle target , int pos , MethodHandle filter ) {
MethodType targetType = target . type ( ) ;
MethodType filterType = filter . type ( ) ;
if ( filterType . parameterCount ( ) ! = 1
| | filterType . returnType ( ) ! = targetType . parameterType ( pos ) )
throw newIllegalArgumentException ( " target and filter types do not match " , targetType , filterType ) ;
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeCollectArguments ( target , filter , pos , false ) ;
2011-05-12 19:27:49 -07:00
}
2012-08-17 13:42:25 -07:00
// FIXME: Make this public in M1.
/*non-public*/ static
MethodHandle collectArguments ( MethodHandle target , int pos , MethodHandle collector ) {
MethodType targetType = target . type ( ) ;
MethodType filterType = collector . type ( ) ;
if ( filterType . returnType ( ) ! = void . class & &
filterType . returnType ( ) ! = targetType . parameterType ( pos ) )
throw newIllegalArgumentException ( " target and filter types do not match " , targetType , filterType ) ;
return MethodHandleImpl . makeCollectArguments ( target , collector , pos , false ) ;
}
2010-12-16 15:59:27 -08:00
/ * *
2011-05-26 17:37:36 -07:00
* Adapts a target method handle by post - processing
* its return value ( if any ) with a filter ( another method handle ) .
* The result of the filter is returned from the adapter .
2010-10-30 21:08:23 -07:00
* < p >
2011-05-26 17:37:36 -07:00
* If the target returns a value , the filter must accept that value as
* its only argument .
* If the target returns void , the filter must accept no arguments .
* < p >
* The return type of the filter
2010-10-30 21:08:23 -07:00
* replaces the return type of the target
* in the resulting adapted method handle .
2011-05-26 17:37:36 -07:00
* The argument type of the filter ( if any ) must be identical to the
2010-10-30 21:08:23 -07:00
* return type of the target .
* < b > Example : < / b >
* < p > < blockquote > < pre >
2011-03-23 23:02:31 -07:00
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
2010-10-30 21:08:23 -07:00
. . .
MethodHandle cat = lookup ( ) . findVirtual ( String . class ,
" concat " , methodType ( String . class , String . class ) ) ;
MethodHandle length = lookup ( ) . findVirtual ( String . class ,
" length " , methodType ( int . class ) ) ;
System . out . println ( ( String ) cat . invokeExact ( " x " , " y " ) ) ; // xy
MethodHandle f0 = filterReturnValue ( cat , length ) ;
System . out . println ( ( int ) f0 . invokeExact ( " x " , " y " ) ) ; // 2
2011-05-26 17:37:36 -07:00
* < / pre > < / blockquote >
* < p > Here is pseudocode for the resulting adapter :
* < blockquote > < pre >
* V target ( A . . . ) ;
* T filter ( V ) ;
* T adapter ( A . . . a ) {
* V v = target ( a . . . ) ;
* return filter ( v ) ;
* }
* // and if the target has a void return:
* void target2 ( A . . . ) ;
* T filter2 ( ) ;
* T adapter2 ( A . . . a ) {
* target2 ( a . . . ) ;
* return filter2 ( ) ;
* }
* // and if the filter has a void return:
* V target3 ( A . . . ) ;
* void filter3 ( V ) ;
* void adapter3 ( A . . . a ) {
* V v = target3 ( a . . . ) ;
* filter3 ( v ) ;
* }
2010-10-30 21:08:23 -07:00
* < / pre > < / blockquote >
* @param target the method handle to invoke before filtering the return value
* @param filter method handle to call on the return value
* @return method handle which incorporates the specified return value filtering logic
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if either argument is null
2011-05-26 17:37:36 -07:00
* @throws IllegalArgumentException if the argument list of { @code filter }
* does not match the return type of target as described above
2010-10-30 21:02:30 -07:00
* /
2010-10-30 21:08:23 -07:00
public static
2010-10-30 21:02:30 -07:00
MethodHandle filterReturnValue ( MethodHandle target , MethodHandle filter ) {
MethodType targetType = target . type ( ) ;
MethodType filterType = filter . type ( ) ;
2011-05-12 19:27:49 -07:00
Class < ? > rtype = targetType . returnType ( ) ;
int filterValues = filterType . parameterCount ( ) ;
if ( filterValues = = 0
? ( rtype ! = void . class )
: ( rtype ! = filterType . parameterType ( 0 ) ) )
throw newIllegalArgumentException ( " target and filter types do not match " , target , filter ) ;
2011-02-11 01:26:28 -08:00
// result = fold( lambda(retval, arg...) { filter(retval) },
// lambda( arg...) { target(arg...) } )
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeCollectArguments ( filter , target , 0 , false ) ;
2010-10-30 21:02:30 -07:00
}
2010-01-07 16:16:45 -08:00
/ * *
2011-05-26 17:37:36 -07:00
* Adapts a target method handle by pre - processing
2010-01-07 16:16:45 -08:00
* some of its arguments , and then calling the target with
2011-05-26 17:37:36 -07:00
* the result of the pre - processing , inserted into the original
* sequence of arguments .
2010-01-07 16:16:45 -08:00
* < p >
2011-05-26 17:37:36 -07:00
* The pre - processing is performed by { @code combiner } , a second method handle .
* Of the arguments passed to the adapter , the first { @code N } arguments
* are copied to the combiner , which is then called .
* ( Here , { @code N } is defined as the parameter count of the combiner . )
* After this , control passes to the target , with any result
* from the combiner inserted before the original { @code N } incoming
* arguments .
* < p >
* If the combiner returns a value , the first parameter type of the target
* must be identical with the return type of the combiner , and the next
* { @code N } parameter types of the target must exactly match the parameters
* of the combiner .
* < p >
* If the combiner has a void return , no result will be inserted ,
* and the first { @code N } parameter types of the target
* must exactly match the parameters of the combiner .
2010-01-07 16:16:45 -08:00
* < p >
* The resulting adapter is the same type as the target , except that the
2011-05-26 17:37:36 -07:00
* first parameter type is dropped ,
* if it corresponds to the result of the combiner .
2010-01-07 16:16:45 -08:00
* < p >
2010-10-30 21:08:23 -07:00
* ( Note that { @link # dropArguments ( MethodHandle , int , List ) dropArguments } can be used to remove any arguments
2011-05-26 17:37:36 -07:00
* that either the combiner or the target does not wish to receive .
2010-01-07 16:16:45 -08:00
* If some of the incoming arguments are destined only for the combiner ,
2011-02-11 01:26:28 -08:00
* consider using { @link MethodHandle # asCollector asCollector } instead , since those
2010-01-07 16:16:45 -08:00
* arguments will not need to be live on the stack on entry to the
* target . )
2011-05-26 17:37:36 -07:00
* < b > Example : < / b >
* < p > < blockquote > < pre >
import static java.lang.invoke.MethodHandles.* ;
import static java.lang.invoke.MethodType.* ;
. . .
MethodHandle trace = publicLookup ( ) . findVirtual ( java . io . PrintStream . class ,
" println " , methodType ( void . class , String . class ) )
. bindTo ( System . out ) ;
MethodHandle cat = lookup ( ) . findVirtual ( String . class ,
" concat " , methodType ( String . class , String . class ) ) ;
assertEquals ( " boojum " , ( String ) cat . invokeExact ( " boo " , " jum " ) ) ;
MethodHandle catTrace = foldArguments ( cat , trace ) ;
// also prints "boo":
assertEquals ( " boojum " , ( String ) catTrace . invokeExact ( " boo " , " jum " ) ) ;
* < / pre > < / blockquote >
2010-01-07 16:16:45 -08:00
* < p > Here is pseudocode for the resulting adapter :
* < blockquote > < pre >
2011-05-26 17:37:36 -07:00
* // there are N arguments in A...
2010-01-07 16:16:45 -08:00
* T target ( V , A [ N ] . . . , B . . . ) ;
* V combiner ( A . . . ) ;
* T adapter ( A . . . a , B . . . b ) {
* V v = combiner ( a . . . ) ;
* return target ( v , a . . . , b . . . ) ;
* }
2011-05-26 17:37:36 -07:00
* // and if the combiner has a void return:
* T target2 ( A [ N ] . . . , B . . . ) ;
* void combiner2 ( A . . . ) ;
* T adapter2 ( A . . . a , B . . . b ) {
* combiner2 ( a . . . ) ;
* return target2 ( a . . . , b . . . ) ;
* }
2010-01-07 16:16:45 -08:00
* < / pre > < / blockquote >
* @param target the method handle to invoke after arguments are combined
* @param combiner method handle to call initially on the incoming arguments
* @return method handle which incorporates the specified argument folding logic
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if either argument is null
2011-05-26 17:37:36 -07:00
* @throws IllegalArgumentException if { @code combiner } ' s return type
* is non - void and not the same as the first argument type of
* the target , or if the initial { @code N } argument types
* of the target
* ( skipping one matching the { @code combiner } ' s return type )
2010-01-07 16:16:45 -08:00
* are not identical with the argument types of { @code combiner }
* /
public static
MethodHandle foldArguments ( MethodHandle target , MethodHandle combiner ) {
2011-05-26 17:37:36 -07:00
int pos = 0 ;
2010-01-07 16:16:45 -08:00
MethodType targetType = target . type ( ) ;
MethodType combinerType = combiner . type ( ) ;
2011-05-26 17:37:36 -07:00
int foldPos = pos ;
2010-01-07 16:16:45 -08:00
int foldArgs = combinerType . parameterCount ( ) ;
2011-05-12 19:27:49 -07:00
int foldVals = combinerType . returnType ( ) = = void . class ? 0 : 1 ;
int afterInsertPos = foldPos + foldVals ;
boolean ok = ( targetType . parameterCount ( ) > = afterInsertPos + foldArgs ) ;
if ( ok & & ! ( combinerType . parameterList ( )
. equals ( targetType . parameterList ( ) . subList ( afterInsertPos ,
afterInsertPos + foldArgs ) ) ) )
2010-10-30 21:02:30 -07:00
ok = false ;
2011-05-12 19:27:49 -07:00
if ( ok & & foldVals ! = 0 & & ! combinerType . returnType ( ) . equals ( targetType . parameterType ( 0 ) ) )
2010-10-30 21:02:30 -07:00
ok = false ;
2010-01-07 16:16:45 -08:00
if ( ! ok )
throw misMatchedTypes ( " target and combiner types " , targetType , combinerType ) ;
2011-05-12 19:27:49 -07:00
MethodType newType = targetType . dropParameterTypes ( foldPos , afterInsertPos ) ;
2012-07-24 10:47:44 -07:00
return MethodHandleImpl . makeCollectArguments ( target , combiner , foldPos , true ) ;
2010-01-07 16:16:45 -08:00
}
2009-05-05 22:40:09 -07:00
/ * *
2011-03-23 23:02:31 -07:00
* Makes a method handle which adapts a target method handle ,
2009-05-05 22:40:09 -07:00
* by guarding it with a test , a boolean - valued method handle .
* If the guard fails , a fallback handle is called instead .
* All three method handles must have the same corresponding
* argument and return types , except that the return type
2010-01-07 16:16:45 -08:00
* of the test must be boolean , and the test is allowed
* to have fewer arguments than the other two method handles .
2009-05-05 22:40:09 -07:00
* < p > Here is pseudocode for the resulting adapter :
* < blockquote > < pre >
* boolean test ( A . . . ) ;
2010-01-07 16:16:45 -08:00
* T target ( A . . . , B . . . ) ;
* T fallback ( A . . . , B . . . ) ;
* T adapter ( A . . . a , B . . . b ) {
2009-05-05 22:40:09 -07:00
* if ( test ( a . . . ) )
2010-01-07 16:16:45 -08:00
* return target ( a . . . , b . . . ) ;
2009-05-05 22:40:09 -07:00
* else
2010-01-07 16:16:45 -08:00
* return fallback ( a . . . , b . . . ) ;
2009-05-05 22:40:09 -07:00
* }
* < / pre > < / blockquote >
2010-12-16 15:59:27 -08:00
* Note that the test arguments ( { @code a . . . } in the pseudocode ) cannot
* be modified by execution of the test , and so are passed unchanged
* from the caller to the target or fallback as appropriate .
2009-05-05 22:40:09 -07:00
* @param test method handle used for test , must return boolean
* @param target method handle to call if test passes
* @param fallback method handle to call if test fails
* @return method handle which incorporates the specified if / then / else logic
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if any argument is null
2009-05-05 22:40:09 -07:00
* @throws IllegalArgumentException if { @code test } does not return boolean ,
* or if all three method types do not match ( with the return
2011-05-26 17:37:36 -07:00
* type of { @code test } changed to match that of the target ) .
2009-05-05 22:40:09 -07:00
* /
public static
MethodHandle guardWithTest ( MethodHandle test ,
MethodHandle target ,
MethodHandle fallback ) {
2010-01-07 16:16:45 -08:00
MethodType gtype = test . type ( ) ;
MethodType ttype = target . type ( ) ;
MethodType ftype = fallback . type ( ) ;
2010-12-16 15:59:27 -08:00
if ( ! ttype . equals ( ftype ) )
2010-01-07 16:16:45 -08:00
throw misMatchedTypes ( " target and fallback types " , ttype , ftype ) ;
2010-12-16 15:59:27 -08:00
if ( gtype . returnType ( ) ! = boolean . class )
throw newIllegalArgumentException ( " guard type is not a predicate " + gtype ) ;
List < Class < ? > > targs = ttype . parameterList ( ) ;
List < Class < ? > > gargs = gtype . parameterList ( ) ;
if ( ! targs . equals ( gargs ) ) {
int gpc = gargs . size ( ) , tpc = targs . size ( ) ;
if ( gpc > = tpc | | ! targs . subList ( 0 , gpc ) . equals ( gargs ) )
2010-01-07 16:16:45 -08:00
throw misMatchedTypes ( " target and test types " , ttype , gtype ) ;
2010-12-16 15:59:27 -08:00
test = dropArguments ( test , gpc , targs . subList ( gpc , tpc ) ) ;
gtype = test . type ( ) ;
2010-01-07 16:16:45 -08:00
}
2011-03-18 00:03:24 -07:00
return MethodHandleImpl . makeGuardWithTest ( test , target , fallback ) ;
2009-05-05 22:40:09 -07:00
}
2010-01-07 16:16:45 -08:00
static RuntimeException misMatchedTypes ( String what , MethodType t1 , MethodType t2 ) {
return newIllegalArgumentException ( what + " must match: " + t1 + " != " + t2 ) ;
}
2009-05-05 22:40:09 -07:00
/ * *
2011-03-23 23:02:31 -07:00
* Makes a method handle which adapts a target method handle ,
2010-01-07 16:16:45 -08:00
* by running it inside an exception handler .
* If the target returns normally , the adapter returns that value .
* If an exception matching the specified type is thrown , the fallback
* handle is called instead on the exception , plus the original arguments .
2009-05-05 22:40:09 -07:00
* < p >
2010-12-16 15:59:27 -08:00
* The target and handler must have the same corresponding
* argument and return types , except that handler may omit trailing arguments
* ( similarly to the predicate in { @link # guardWithTest guardWithTest } ) .
* Also , the handler must have an extra leading parameter of { @code exType } or a supertype .
2009-05-05 22:40:09 -07:00
* < p > Here is pseudocode for the resulting adapter :
* < blockquote > < pre >
2010-12-16 15:59:27 -08:00
* T target ( A . . . , B . . . ) ;
2010-01-07 16:16:45 -08:00
* T handler ( ExType , A . . . ) ;
2010-12-16 15:59:27 -08:00
* T adapter ( A . . . a , B . . . b ) {
2010-01-07 16:16:45 -08:00
* try {
2010-12-16 15:59:27 -08:00
* return target ( a . . . , b . . . ) ;
2010-01-07 16:16:45 -08:00
* } catch ( ExType ex ) {
* return handler ( ex , a . . . ) ;
* }
2009-05-05 22:40:09 -07:00
* }
* < / pre > < / blockquote >
2010-12-16 15:59:27 -08:00
* Note that the saved arguments ( { @code a . . . } in the pseudocode ) cannot
* be modified by execution of the target , and so are passed unchanged
* from the caller to the handler , if the handler is invoked .
* < p >
* The target and handler must return the same type , even if the handler
* always throws . ( This might happen , for instance , because the handler
* is simulating a { @code finally } clause ) .
* To create such a throwing handler , compose the handler creation logic
* with { @link # throwException throwException } ,
* in order to create a method handle of the correct return type .
2010-01-07 16:16:45 -08:00
* @param target method handle to call
* @param exType the type of exception which the handler will catch
* @param handler method handle to call if a matching exception is thrown
* @return method handle which incorporates the specified try / catch logic
2011-02-11 01:26:28 -08:00
* @throws NullPointerException if any argument is null
2010-01-07 16:16:45 -08:00
* @throws IllegalArgumentException if { @code handler } does not accept
* the given exception type , or if the method handle types do
* not match in their return types and their
* corresponding parameters
2009-05-05 22:40:09 -07:00
* /
public static
2010-01-07 16:16:45 -08:00
MethodHandle catchException ( MethodHandle target ,
Class < ? extends Throwable > exType ,
MethodHandle handler ) {
2010-12-16 15:59:27 -08:00
MethodType ttype = target . type ( ) ;
MethodType htype = handler . type ( ) ;
if ( htype . parameterCount ( ) < 1 | |
! htype . parameterType ( 0 ) . isAssignableFrom ( exType ) )
throw newIllegalArgumentException ( " handler does not accept exception type " + exType ) ;
if ( htype . returnType ( ) ! = ttype . returnType ( ) )
throw misMatchedTypes ( " target and handler return types " , ttype , htype ) ;
List < Class < ? > > targs = ttype . parameterList ( ) ;
List < Class < ? > > hargs = htype . parameterList ( ) ;
hargs = hargs . subList ( 1 , hargs . size ( ) ) ; // omit leading parameter from handler
if ( ! targs . equals ( hargs ) ) {
int hpc = hargs . size ( ) , tpc = targs . size ( ) ;
if ( hpc > = tpc | | ! targs . subList ( 0 , hpc ) . equals ( hargs ) )
throw misMatchedTypes ( " target and handler types " , ttype , htype ) ;
2011-05-17 19:48:14 -07:00
handler = dropArguments ( handler , 1 + hpc , targs . subList ( hpc , tpc ) ) ;
2010-12-16 15:59:27 -08:00
htype = handler . type ( ) ;
}
2011-03-18 00:03:24 -07:00
return MethodHandleImpl . makeGuardWithCatch ( target , exType , handler ) ;
2009-05-05 22:40:09 -07:00
}
2010-01-07 16:16:45 -08:00
/ * *
2011-02-11 01:26:28 -08:00
* Produces a method handle which will throw exceptions of the given { @code exType } .
2010-01-07 16:16:45 -08:00
* The method handle will accept a single argument of { @code exType } ,
* and immediately throw it as an exception .
* The method type will nominally specify a return of { @code returnType } .
* The return type may be anything convenient : It doesn ' t matter to the
* method handle ' s behavior , since it will never return normally .
2013-06-27 19:02:02 -07:00
* @param returnType the return type of the desired method handle
* @param exType the parameter type of the desired method handle
2011-02-11 01:26:28 -08:00
* @return method handle which can throw the given exceptions
* @throws NullPointerException if either argument is null
2010-01-07 16:16:45 -08:00
* /
public static
MethodHandle throwException ( Class < ? > returnType , Class < ? extends Throwable > exType ) {
2012-07-24 10:47:44 -07:00
if ( ! Throwable . class . isAssignableFrom ( exType ) )
throw new ClassCastException ( exType . getName ( ) ) ;
2011-03-18 00:03:24 -07:00
return MethodHandleImpl . throwException ( MethodType . methodType ( returnType , exType ) ) ;
2010-01-07 16:16:45 -08:00
}
2009-05-05 22:40:09 -07:00
}