Class MethodHandles.Lookup
- Enclosing class:
MethodHandles
A lookup class which needs to create method handles will call
MethodHandles.lookup to create a factory for itself.
When the Lookup factory object is created, the identity of the lookup class is
determined, and securely stored in the Lookup object.
The lookup class (or its delegates) may then use factory methods
on the 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.
Lookup Factory Methods
The factory methods on aLookup object correspond to all major
use cases for methods, constructors, and fields.
Each method handle created by a factory method is the functional
equivalent of a particular bytecode behavior.
(Bytecode behaviors are described in section 5.4.3.5 of
the Java Virtual Machine Specification.)
Here is a summary of the correspondence between these factory methods and
the behavior of the resulting method handles:
| lookup expression | member | bytecode behavior |
|---|---|---|
lookup.findGetter(C.class,"f",FT.class) |
FT f; | (T) this.f; |
lookup.findStaticGetter(C.class,"f",FT.class) |
staticFT f; | (FT) C.f; |
lookup.findSetter(C.class,"f",FT.class) |
FT f; | this.f = x; |
lookup.findStaticSetter(C.class,"f",FT.class) |
staticFT f; | C.f = arg; |
lookup.findVirtual(C.class,"m",MT) |
T m(A*); | (T) this.m(arg*); |
lookup.findStatic(C.class,"m",MT) |
staticT m(A*); | (T) C.m(arg*); |
lookup.findSpecial(C.class,"m",MT,this.class) |
T m(A*); | (T) super.m(arg*); |
lookup.findConstructor(C.class,MT) |
C(A*); | new C(arg*); |
lookup.unreflectGetter(aField) |
(static)?FT f; | (FT) aField.get(thisOrNull); |
lookup.unreflectSetter(aField) |
(static)?FT f; | aField.set(thisOrNull, arg); |
lookup.unreflect(aMethod) |
(static)?T m(A*); | (T) aMethod.invoke(thisOrNull, arg*); |
lookup.unreflectConstructor(aConstructor) |
C(A*); | (C) aConstructor.newInstance(arg*); |
lookup.unreflectSpecial(aMethod,this.class) |
T m(A*); | (T) super.m(arg*); |
lookup.findClass("C") |
class C { ... } | C.class; |
C is the class or interface being searched for a member,
documented as a parameter named refc in the lookup methods.
The method type MT is composed from the return type T
and the sequence of argument types A*.
The constructor also has a sequence of argument types A* and
is deemed to return the newly-created object of type C.
Both MT and the field type FT are documented as a parameter named type.
The formal parameter this stands for the self-reference of type C;
if it is present, it is always the leading argument to the method handle invocation.
(In the case of some protected members, this may be
restricted in type to the lookup class; see below.)
The name arg stands for all the other method handle arguments.
In the code examples for the Core Reflection API, the name thisOrNull
stands for a null reference if the accessed method or field is static,
and this otherwise.
The names aMethod, aField, and aConstructor stand
for reflective objects corresponding to the given members declared in type C.
The bytecode behavior for a findClass operation is a load of a constant class,
as if by ldc CONSTANT_Class.
The behavior is represented, not as a method handle, but directly as a Class constant.
In cases where the given member is of variable arity (i.e., a method or constructor) the returned method handle will also be of variable arity. In all other cases, the returned method handle will be of fixed arity.
Discussion: The equivalence between looked-up method handles and underlying class members and bytecode behaviors can break down in a few ways:
- If
Cis 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. - Likewise, if
TorMTis not symbolically accessible from the lookup class's loader, the lookup can still succeed. For example, lookups forMethodHandle.invokeExactandMethodHandle.invokewill always succeed, regardless of requested type. - If the looked-up method has a
very large arity,
the method handle creation may fail with an
IllegalArgumentException, due to the method handle type having too many parameters.
Access checking
Access checks are applied in the factory methods ofLookup,
when a method handle is created.
This is a key difference from the Core Reflection API, since
java.lang.reflect.Method.invoke
performs access checking against every caller, on every call.
All access checks start from a Lookup object, which
compares its recorded lookup class against all requests to
create method handles.
A single Lookup object can be used to create any number
of access-checked method handles, all checked against a single
lookup class.
A Lookup object can be shared with other trusted code,
such as a metaobject protocol.
A shared Lookup object delegates the capability
to create method handles on private members of the lookup class.
Even if privileged code uses the Lookup object,
the access checking is confined to the privileges of the
original lookup class.
A lookup can fail, because
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, or
because the lookup object is not trusted enough to access the member.
In the case of a field setter function on a final field,
finality enforcement is treated as a kind of access control,
and the lookup will fail, except in special cases of
Lookup.unreflectSetter.
In any of these cases, a ReflectiveOperationException will be
thrown from the attempted lookup. The exact class will be one of
the following:
- NoSuchMethodException — if a method is requested but does not exist
- NoSuchFieldException — if a field is requested but does not exist
- IllegalAccessException — if the member exists but an access check fails
In general, the conditions under which a method handle may be
looked up for a method M are no more restrictive than the conditions
under which the lookup class could have compiled, verified, and resolved a call to M.
Where the JVM would raise exceptions like NoSuchMethodError,
a method handle lookup will generally raise a corresponding
checked exception, such as NoSuchMethodException.
And the effect of invoking the method handle resulting from the lookup
is exactly equivalent
to executing the compiled, verified, and resolved call to M.
The same point is true of fields and constructors.
Discussion:
Access checks only apply to named and reflected methods,
constructors, and fields.
Other method handle creation methods, such as
MethodHandle.asType,
do not require any access checks, and are used
independently of any Lookup object.
If the desired member is protected, the usual JVM rules apply,
including the requirement that the lookup class must 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
this parameter from C
(which will necessarily be a superclass of the lookup class)
to the lookup class itself.
The JVM imposes a similar requirement on invokespecial instruction,
that the receiver argument must match both the resolved method and
the current class. Again, this requirement is enforced by narrowing the
type of the leading parameter to the resulting method handle.
(See the Java Virtual Machine Specification, section 4.10.1.9.)
The JVM represents constructors and static initializer blocks as internal methods
with special names ("<init>" and "<clinit>").
The internal syntax of invocation instructions allows them to refer to such internal
methods as if they were normal methods, but the JVM bytecode verifier rejects them.
A lookup of such an internal method will produce a NoSuchMethodException.
If the relationship between nested types is expressed directly through the
NestHost and NestMembers attributes
(see the Java Virtual Machine Specification, sections 4.7.28 and 4.7.29),
then the associated Lookup object provides direct access to
the lookup class and all of its nestmates
(see Class.getNestHost).
Otherwise, access between nested classes is obtained by the Java compiler creating
a wrapper method to access a private method of another class in the same nest.
For example, a nested class C.D
can access private members within other related classes such as
C, C.D.E, or C.B,
but the Java compiler may need to generate wrapper methods in
those related classes. In such cases, a Lookup object on
C.E would be unable to access those private members.
A workaround for this limitation is the Lookup.in method,
which can transform a lookup on C.E into one on any of those other
classes, without special elevation of privilege.
The accesses permitted to a given lookup object may be limited,
according to its set of lookupModes,
to a subset of members normally accessible to the lookup class.
For example, the publicLookup
method produces a lookup object which is only allowed to access
public members in public classes of exported packages.
The caller sensitive method lookup
produces a lookup object with full capabilities relative to
its caller class, to emulate all supported bytecode behaviors.
Also, the Lookup.in method may produce a lookup object
with fewer access modes than the original lookup object.
Discussion of private and module access:
We say that a lookup has private access
if its lookup modes
include the possibility of accessing private members
(which includes the private members of nestmates).
As documented in the relevant methods elsewhere,
only lookups with private access possess the following capabilities:
- access private fields, methods, and constructors of the lookup class and its nestmates
- create method handles which
emulate invokespecialinstructions - create
delegated lookup objectswhich have private access to other classes within the same package member
Similarly, a lookup with module access ensures that the original lookup creator was a member in the same module as the lookup class.
Private and module access are independently determined modes; a lookup may have either or both or neither. A lookup which possesses both access modes is said to possess full privilege access.
A lookup with original access ensures that this lookup is created by the original lookup class and the bootstrap method invoked by the VM. Such a lookup with original access also has private and module access which has the following additional capability:
- create method handles which invoke caller sensitive methods,
such as
Class.forName - obtain the class data associated with the lookup class
Each of these permissions is a consequence of the fact that a lookup object with private access can be securely traced back to an originating class, whose bytecode behaviors and Java language access permissions can be reliably determined and emulated by method handles.
Cross-module lookups
When a lookup class in one moduleM1 accesses a class in another module
M2, extra access checking is performed beyond the access mode bits.
A Lookup with PUBLIC mode and a lookup class in M1
can access public types in M2 when M2 is readable to M1
and when the type is in a package of M2 that is exported to
at least M1.
A Lookup on C can also teleport to a target class
via Lookup.in and MethodHandles.privateLookupIn methods.
Teleporting across modules will always record the original lookup class as
the previous lookup class
and drops MODULE access.
If the target class is in the same module as the lookup class C,
then the target class becomes the new lookup class
and there is no change to the previous lookup class.
If the target class is in a different module from M1 (C's module),
C becomes the new previous lookup class
and the target class becomes the new lookup class.
In that case, if there was already a previous lookup class in M0,
and it differs from M1 and M2, then the resulting lookup
drops all privileges.
For example,
Lookup lookup = MethodHandles.lookup(); // in class C
Lookup lookup2 = lookup.in(D.class);
MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
The MethodHandles.lookup() factory method produces a Lookup object
with null previous lookup class.
lookup.in(D.class) transforms the lookup on class C
to class D without elevation of privileges.
If C and D are in the same module,
lookup2 records D as the new lookup class and keeps the
same previous lookup class as the original lookup, or
null if not present.
When a Lookup teleports from a class
in one nest to another nest, PRIVATE access is dropped.
When a Lookup teleports from a class in one package to
another package, PACKAGE access is dropped.
When a Lookup teleports from a class in one module to another module,
MODULE access is dropped.
Teleporting across modules drops the ability to access non-exported classes
in both the module of the new lookup class and the module of the old lookup class
and the resulting Lookup remains only PUBLIC access.
A Lookup can teleport back and forth to a class in the module of
the lookup class and the module of the previous class lookup.
Teleporting across modules can only decrease access but cannot increase it.
Teleporting to some third module drops all accesses.
In the above example, if C and D are in different modules,
lookup2 records D as its lookup class and
C as its previous lookup class and lookup2 has only
PUBLIC access. lookup2 can teleport to other class in
C's module and D's module.
If class E is in a third module, lookup2.in(E.class) creates
a Lookup on E with no access and lookup2's lookup
class D is recorded as its previous lookup class.
Teleporting across modules restricts access to the public types that both the lookup class and the previous lookup class can equally access (see below).
MethodHandles.privateLookupIn(T.class, lookup)
can be used to teleport a lookup from class C to class T
and produce a new Lookup with private access
if the lookup class is allowed to do deep reflection on T.
The lookup must have MODULE and PRIVATE access
to call privateLookupIn.
A lookup on C in module M1 is allowed to do deep reflection
on all classes in M1. If T is in M1, privateLookupIn
produces a new Lookup on T with full capabilities.
A lookup on C is also allowed
to do deep reflection on T in another module M2 if
M1 reads M2 and M2 opens
the package containing T to at least M1.
T becomes the new lookup class and C becomes the new previous
lookup class and MODULE access is dropped from the resulting Lookup.
The resulting Lookup can be used to do member lookup or teleport
to another lookup class by calling Lookup::in. But
it cannot be used to obtain another private Lookup by calling
privateLookupIn
because it has no MODULE access.
The Lookup object returned by privateLookupIn is allowed to
define classes in the runtime package
of T. Extreme caution should be taken when opening a package
to another module as such defined classes have the same full privilege
access as other members in M2.
Cross-module access checks
ALookup with PUBLIC or with UNCONDITIONAL mode
allows cross-module access. The access checking is performed with respect
to both the lookup class and the previous lookup class if present.
A Lookup with UNCONDITIONAL mode can access public type
in all modules when the type is in a package that is exported unconditionally.
If a Lookup on LC in M1 has no previous lookup class,
the lookup with PUBLIC mode can access all public types in modules
that are readable to M1 and the type is in a package that is exported
at least to M1.
If a Lookup on LC in M1 has a previous lookup class
PLC on M0, the lookup with PUBLIC mode can access
the intersection of all public types that are accessible to M1
with all public types that are accessible to M0. M0
reads M1 and hence the set of accessible types includes:
- unconditional-exported packages from
M1 - unconditional-exported packages from
M0ifM1readsM0 -
unconditional-exported packages from a third module
M2if bothM0andM1readM2 - qualified-exported packages from
M1toM0 - qualified-exported packages from
M0toM1ifM1readsM0 -
qualified-exported packages from a third module
M2to bothM0andM1if bothM0andM1readM2
Access modes
The table below shows the access modes of aLookup produced by
any of the following factory or transformation methods:
MethodHandles::lookupMethodHandles::publicLookupMethodHandles::privateLookupInLookup::inLookup::dropLookupMode
| Lookup object | original | protected | private | package | module | public |
|---|---|---|---|---|---|---|
CL = MethodHandles.lookup() in C |
ORI | PRO | PRI | PAC | MOD | 1R |
CL.in(C1) same package |
PAC | MOD | 1R | |||
CL.in(C1) same module |
MOD | 1R | ||||
CL.in(D) different module |
2R | |||||
CL.in(D).in(C) hop back to module |
2R | |||||
PRI1 = privateLookupIn(C1,CL) |
PRO | PRI | PAC | MOD | 1R | |
PRI1a = privateLookupIn(C,PRI1) |
PRO | PRI | PAC | MOD | 1R | |
PRI1.in(C1) same package |
PAC | MOD | 1R | |||
PRI1.in(C1) different package |
MOD | 1R | ||||
PRI1.in(D) different module |
2R | |||||
PRI1.dropLookupMode(PROTECTED) |
PRI | PAC | MOD | 1R | ||
PRI1.dropLookupMode(PRIVATE) |
PAC | MOD | 1R | |||
PRI1.dropLookupMode(PACKAGE) |
MOD | 1R | ||||
PRI1.dropLookupMode(MODULE) |
1R | |||||
PRI1.dropLookupMode(PUBLIC) |
none | |||||
PRI2 = privateLookupIn(D,CL) |
PRO | PRI | PAC | 2R | ||
privateLookupIn(D,PRI1) |
PRO | PRI | PAC | 2R | ||
privateLookupIn(C,PRI2) fails |
IAE | |||||
PRI2.in(D2) same package |
PAC | 2R | ||||
PRI2.in(D2) different package |
2R | |||||
PRI2.in(C1) hop back to module |
2R | |||||
PRI2.in(E) hop to third module |
none | |||||
PRI2.dropLookupMode(PROTECTED) |
PRI | PAC | 2R | |||
PRI2.dropLookupMode(PRIVATE) |
PAC | 2R | ||||
PRI2.dropLookupMode(PACKAGE) |
2R | |||||
PRI2.dropLookupMode(MODULE) |
2R | |||||
PRI2.dropLookupMode(PUBLIC) |
none | |||||
CL.dropLookupMode(PROTECTED) |
PRI | PAC | MOD | 1R | ||
CL.dropLookupMode(PRIVATE) |
PAC | MOD | 1R | |||
CL.dropLookupMode(PACKAGE) |
MOD | 1R | ||||
CL.dropLookupMode(MODULE) |
1R | |||||
CL.dropLookupMode(PUBLIC) |
none | |||||
PUB = publicLookup() |
U | |||||
PUB.in(D) different module |
U | |||||
PUB.in(D).in(E) third module |
U | |||||
PUB.dropLookupMode(UNCONDITIONAL) |
none | |||||
privateLookupIn(C1,PUB) fails |
IAE | |||||
ANY.in(X), for inaccessible X |
none |
Notes:
- Class
Cand classC1are in moduleM1, butDandD2are in moduleM2, andEis in moduleM3.Xstands for class which is inaccessible to the lookup.ANYstands for any of the example lookups. ORIindicatesORIGINALbit set,PROindicatesPROTECTEDbit set,PRIindicatesPRIVATEbit set,PACindicatesPACKAGEbit set,MODindicatesMODULEbit set,1Rand2RindicatePUBLICbit set,UindicatesUNCONDITIONALbit set,IAEindicatesIllegalAccessExceptionthrown.- Public access comes in three kinds:
- unconditional (
U): the lookup assumes readability. The lookup hasnullprevious lookup class. - one-module-reads (
1R): the module access checking is performed with respect to the lookup class. The lookup hasnullprevious lookup class. - two-module-reads (
2R): the module access checking is performed with respect to the lookup class and the previous lookup class. The lookup has a non-null previous lookup class which is in a different module from the current lookup class.
- unconditional (
- Any attempt to reach a third module loses all access.
- If a target class
Xis not accessible toLookup::inall access modes are dropped.
Caller sensitive methods
A small number of Java methods have a special property called caller sensitivity. A caller-sensitive method can behave differently depending on the identity of its immediate caller.If a method handle for a caller-sensitive method is requested, the general rules for bytecode behaviors apply, but they take account of the lookup class in a special way. The resulting method handle behaves as if it were called from an instruction contained in the lookup class, so that the caller-sensitive method detects the lookup class. (By contrast, the invoker of the method handle is disregarded.) Thus, in the case of caller-sensitive methods, different lookup classes may give rise to differently behaving method handles.
In cases where the lookup object is
publicLookup(),
or some other lookup object without the
original access,
the lookup class is disregarded.
In such cases, no caller-sensitive method handle can be created,
access is forbidden, and the lookup fails with an
IllegalAccessException.
Discussion:
For example, the caller-sensitive method
Class.forName(x)
can return varying classes or throw varying exceptions,
depending on the class loader of the class that calls it.
A public lookup of Class.forName will fail, because
there is no reasonable way to determine its bytecode behavior.
If an application caches method handles for broad sharing,
it should use publicLookup() to create them.
If there is a lookup of Class.forName, it will fail,
and the application must take appropriate action in that case.
It may be that a later lookup, perhaps during the invocation of a
bootstrap method, can incorporate the specific identity
of the caller, making the method accessible.
The function MethodHandles.lookup is caller sensitive
so that there can be a secure foundation for lookups.
Nearly all other methods in the JSR 292 API rely on lookup
objects to check access requests.
- Since:
- 1.7
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumThe set of class options that specify whether a hidden class created byLookup::defineHiddenClassmethod is dynamically added as a new member to the nest of a lookup class and/or whether a hidden class has a strong relationship with the class loader marked as its defining loader. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intA single-bit mask representingmoduleaccess, which may contribute to the result oflookupModes.static final intA single-bit mask representingoriginalaccess which may contribute to the result oflookupModes.static final intA single-bit mask representingpackageaccess (default access), which may contribute to the result oflookupModes.static final intA single-bit mask representingprivateaccess, which may contribute to the result oflookupModes.static final intA single-bit mask representingprotectedaccess, which may contribute to the result oflookupModes.static final intA single-bit mask representingpublicaccess, which may contribute to the result oflookupModes.static final intA single-bit mask representingunconditionalaccess which may contribute to the result oflookupModes. -
Method Summary
Modifier and TypeMethodDescription<T> Class<T> accessClass(Class<T> targetClass) Determines if a class can be accessed from the lookup context defined by thisLookupobject.bind(Object receiver, String name, MethodType type) Produces an early-bound method handle for a non-static method.Class<?> defineClass(byte[] bytes) Creates and links a class or interface frombyteswith the same class loader and in the same runtime package and protection domain as this lookup's lookup class as if callingClassLoader::defineClass.defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption... options) Creates a hidden class or interface frombytes, returning aLookupon the newly created class or interface.defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options) Creates a hidden class or interface frombyteswith associated class data, returning aLookupon the newly created class or interface.dropLookupMode(int modeToDrop) Creates a lookup on the same lookup class which this lookup object finds members, but with a lookup mode that has lost the given lookup mode.<T> Class<T> ensureInitialized(Class<T> targetClass) Ensures thattargetClasshas been initialized.Class<?> Looks up a class by name from the lookup context defined by thisLookupobject, as if resolved by anldcinstruction.findConstructor(Class<?> refc, MethodType type) Produces a method handle which creates an object and initializes it, using the constructor of the specified type.findGetter(Class<?> refc, String name, Class<?> type) Produces a method handle giving read access to a non-static field.findSetter(Class<?> refc, String name, Class<?> type) Produces a method handle giving write access to a non-static field.findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) Produces an early-bound method handle for a virtual method.findStatic(Class<?> refc, String name, MethodType type) Produces a method handle for a static method.findStaticGetter(Class<?> refc, String name, Class<?> type) Produces a method handle giving read access to a static field.findStaticSetter(Class<?> refc, String name, Class<?> type) Produces a method handle giving write access to a static field.findStaticVarHandle(Class<?> decl, String name, Class<?> type) Produces a VarHandle giving access to a static fieldnameof typetypedeclared in a class of typedecl.findVarHandle(Class<?> recv, String name, Class<?> type) Produces a VarHandle giving access to a non-static fieldnameof typetypedeclared in a class of typerecv.findVirtual(Class<?> refc, String name, MethodType type) Produces a method handle for a virtual method.booleanReturnstrueif this lookup has full privilege access, i.e.booleanDeprecated.Creates a lookup on the specified new lookup class.Class<?> Tells which class is performing the lookup.intTells which access-protection classes of members this lookup object can produce.Class<?> Reports a lookup class in another module that this lookup object was previously teleported from, ornull.revealDirect(MethodHandle target) Cracks a direct method handle created by this lookup object or a similar one.toString()Displays the name of the class from which lookups are to be made, followed by "/" and the name of the previous lookup class if present.Makes a direct method handle to m, if the lookup class has permission.Produces a method handle for a reflected constructor.Produces a method handle giving read access to a reflected field.Produces a method handle giving write access to a reflected field.unreflectSpecial(Method m, Class<?> specialCaller) Produces a method handle for a reflected method.Produces a VarHandle giving access to a reflected fieldfof typeTdeclared in a class of typeR.
-
Field Details
-
PUBLIC
public static final int PUBLICA single-bit mask representingpublicaccess, which may contribute to the result oflookupModes. The value,0x01, happens to be the same as the value of thepublicmodifier bit.A
Lookupwith this lookup mode performs cross-module access check with respect to the lookup class and previous lookup class if present.- See Also:
-
PRIVATE
public static final int PRIVATEA single-bit mask representingprivateaccess, which may contribute to the result oflookupModes. The value,0x02, happens to be the same as the value of theprivatemodifier bit.- See Also:
-
PROTECTED
public static final int PROTECTEDA single-bit mask representingprotectedaccess, which may contribute to the result oflookupModes. The value,0x04, happens to be the same as the value of theprotectedmodifier bit.- See Also:
-
PACKAGE
public static final int PACKAGEA single-bit mask representingpackageaccess (default access), which may contribute to the result oflookupModes. The value is0x08, which does not correspond meaningfully to any particular modifier bit.- See Also:
-
MODULE
public static final int MODULEA single-bit mask representingmoduleaccess, which may contribute to the result oflookupModes. The value is0x10, which does not correspond meaningfully to any particular modifier bit. In conjunction with thePUBLICmodifier bit, aLookupwith this lookup mode can access all public types in the module of the lookup class and public types in packages exported by other modules to the module of the lookup class.If this lookup mode is set, the previous lookup class is always
null.- Since:
- 9
- See Also:
-
UNCONDITIONAL
public static final int UNCONDITIONALA single-bit mask representingunconditionalaccess which may contribute to the result oflookupModes. The value is0x20, which does not correspond meaningfully to any particular modifier bit. ALookupwith this lookup mode assumes readability. This lookup mode can access all public members of public types of all modules when the type is in a package that isexported unconditionally.If this lookup mode is set, the previous lookup class is always
null.- Since:
- 9
- See Also:
-
ORIGINAL
public static final int ORIGINALA single-bit mask representingoriginalaccess which may contribute to the result oflookupModes. The value is0x40, which does not correspond meaningfully to any particular modifier bit.If this lookup mode is set, the
Lookupobject must be created by the original lookup class by callingMethodHandles.lookup()method or by a bootstrap method invoked by the VM. TheLookupobject with this lookup mode has full privilege access.- Since:
- 16
- See Also:
-
-
Method Details
-
lookupClass
Tells which class is performing the lookup. It is this class against which checks are performed for visibility and access permissions.If this lookup object has a previous lookup class, access checks are performed against both the lookup class and the previous lookup class.
The class implies a maximum level of access permission, but the permissions may be additionally limited by the bitmask
lookupModes, which controls whether non-public members can be accessed.- Returns:
- the lookup class, on behalf of which this lookup object finds members
- See Also:
-
previousLookupClass
Reports a lookup class in another module that this lookup object was previously teleported from, ornull.A
Lookupobject produced by the factory methods, such as thelookup()andpublicLookup()method, hasnullprevious lookup class. ALookupobject has a non-null previous lookup class when this lookup was teleported from an old lookup class in one module to a new lookup class in another module.- Returns:
- the lookup class in another module that this lookup object was
previously teleported from, or
null - Since:
- 14
- See Also:
-
lookupModes
public int lookupModes()Tells which access-protection classes of members this lookup object can produce. The result is a bit-mask of the bits PUBLIC (0x01), PRIVATE (0x02), PROTECTED (0x04), PACKAGE (0x08), MODULE (0x10), UNCONDITIONAL (0x20), and ORIGINAL (0x40).A freshly-created lookup object on the caller's class has all possible bits set, except
UNCONDITIONAL. A lookup object on a new lookup class created from a previous lookup object may have some mode bits set to zero. Mode bits can also be directly cleared. Once cleared, mode bits cannot be restored from the downgraded lookup object. 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.- Returns:
- the lookup modes, which limit the kinds of access performed by this lookup object
- See Also:
-
in
Creates a lookup on the specified new lookup class. The resulting object will report the specified class as its ownlookupClass.However, the resulting
Lookupobject is guaranteed to have no more access capabilities than the original. In particular, access capabilities can be lost as follows:- If the new lookup class is different from the old lookup class,
i.e.
ORIGINALaccess is lost. - If the new lookup class is in a different module from the old one,
i.e.
MODULEaccess is lost. - If the new lookup class is in a different package
than the old one, protected and default (package) members will not be accessible,
i.e.
PROTECTEDandPACKAGEaccess are lost. - If the new lookup class is not within the same package member
as the old one, private members will not be accessible, and protected members
will not be accessible by virtue of inheritance,
i.e.
PRIVATEaccess is lost. (Protected members may continue to be accessible because of package sharing.) - If the new lookup class is not accessible to this lookup, then no members, not even public members, will be accessible i.e. all access modes are lost.
- If the new lookup class, the old lookup class and the previous lookup class are all in different modules i.e. teleporting to a third module, all access modes are lost.
The new previous lookup class is chosen as follows:
- If the new lookup object has
UNCONDITIONALbit, the new previous lookup class isnull. - If the new lookup class is in the same module as the old lookup class, the new previous lookup class is the old previous lookup class.
- If the new lookup class is in a different module from the old lookup class, the new previous lookup class is the old lookup class.
The resulting lookup's capabilities for loading classes (used during
findClass(java.lang.String)invocations) are determined by the lookup class' loader, which may change due to this operation.- Parameters:
requestedLookupClass- the desired lookup class for the new lookup object- Returns:
- a lookup object which reports the desired lookup class, or the same object if there is no change
- Throws:
IllegalArgumentException- ifrequestedLookupClassis a primitive type or void or array classNullPointerException- if the argument is null- See Also:
- If the new lookup class is different from the old lookup class,
i.e.
-
dropLookupMode
Creates a lookup on the same lookup class which this lookup object finds members, but with a lookup mode that has lost the given lookup mode. The lookup mode to drop is one ofPUBLIC,MODULE,PACKAGE,PROTECTED,PRIVATE,ORIGINAL, orUNCONDITIONAL.If this lookup is a public lookup, this lookup has
UNCONDITIONALmode set and it has no other mode set. When droppingUNCONDITIONALon a public lookup then the resulting lookup has no access.If this lookup is not a public lookup, then the following applies regardless of its lookup modes.
PROTECTEDandORIGINALare always dropped and so the resulting lookup mode will never have these access capabilities. When droppingPACKAGEthen the resulting lookup will not havePACKAGEorPRIVATEaccess. When droppingMODULEthen the resulting lookup will not haveMODULE,PACKAGE, orPRIVATEaccess. When droppingPUBLICthen the resulting lookup has no access.- API Note:
- A lookup with
PACKAGEbut notPRIVATEmode can safely delegate non-public access within the package of the lookup class without conferring private access. A lookup withMODULEbut notPACKAGEmode can safely delegatePUBLICaccess within the module of the lookup class without conferring package access. A lookup with a previous lookup class (andPUBLICbut notMODULEmode) can safely delegate access to public classes accessible to both the module of the lookup class and the module of the previous lookup class. - Parameters:
modeToDrop- the lookup mode to drop- Returns:
- a lookup object which lacks the indicated mode, or the same object if there is no change
- Throws:
IllegalArgumentException- ifmodeToDropis not one ofPUBLIC,MODULE,PACKAGE,PROTECTED,PRIVATE,ORIGINALorUNCONDITIONAL- Since:
- 9
- See Also:
-
defineClass
Creates and links a class or interface frombyteswith the same class loader and in the same runtime package and protection domain as this lookup's lookup class as if callingClassLoader::defineClass.The lookup modes for this lookup must include
PACKAGEaccess as default (package) members will be accessible to the class. ThePACKAGElookup mode serves to authenticate that the lookup object was created by a caller in the runtime package (or derived from a lookup originally created by suitably privileged code to a target class in the runtime package).The
bytesparameter is the class bytes of a valid class file (as defined by the The Java Virtual Machine Specification) with a class name in the same package as the lookup class.This method does not run the class initializer. The class initializer may run at a later time, as detailed in section 12.4 of the The Java Language Specification.
- Parameters:
bytes- the class bytes- Returns:
- the
Classobject for the class - Throws:
IllegalAccessException- if this lookup does not havePACKAGEaccessClassFormatError- ifbytesis not aClassFilestructureIllegalArgumentException- ifbytesdenotes a class in a different package than the lookup class orbytesis not a class or interface (ACC_MODULEflag is set in the value of theaccess_flagsitem)VerifyError- if the newly created class cannot be verifiedLinkageError- if the newly created class cannot be linked for any other reasonNullPointerException- ifbytesisnull- Since:
- 9
- See Also:
-
defineHiddenClass
public MethodHandles.Lookup defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption... options) throws IllegalAccessException Creates a hidden class or interface frombytes, returning aLookupon the newly created class or interface.Ordinarily, a class or interface
Cis created by a class loader, which either definesCdirectly or delegates to another class loader. A class loader definesCdirectly by invokingClassLoader::defineClass, which causes the Java Virtual Machine to deriveCfrom a purported representation inclassfile format. In situations where use of a class loader is undesirable, a class or interfaceCcan be created by this method instead. This method is capable of definingC, and thereby creating it, without invokingClassLoader::defineClass. Instead, this method definesCas if by arranging for the Java Virtual Machine to derive a nonarray class or interfaceCfrom a purported representation inclassfile format using the following rules:- The lookup modes for this
Lookupmust include full privilege access. This level of access is needed to createCin the module of the lookup class of thisLookup. - The purported representation in
bytesmust be aClassFilestructure (JVMS 4.1) of a supported major and minor version. The major and minor version may differ from theclassfile version of the lookup class of thisLookup. - The value of
this_classmust be a valid index in theconstant_pooltable, and the entry at that index must be a validCONSTANT_Class_infostructure. LetNbe the binary name encoded in internal form that is specified by this structure.Nmust denote a class or interface in the same package as the lookup class. - Let
CNbe the stringN + "." + <suffix>, where<suffix>is an unqualified name.Let
newBytesbe theClassFilestructure given bybyteswith an additional entry in theconstant_pooltable, indicating aCONSTANT_Utf8_infostructure forCN, and where theCONSTANT_Class_infostructure indicated bythis_classrefers to the newCONSTANT_Utf8_infostructure.Let
Lbe the defining class loader of the lookup class of thisLookup.Cis derived with nameCN, class loaderL, and purported representationnewBytesas if by the rules of JVMS 5.3.5, with the following adjustments:- The constant indicated by
this_classis permitted to specify a name that includes a single"."character, even though this is not a valid binary class or interface name in internal form. - The Java Virtual Machine marks
Las the defining class loader ofC, but no class loader is recorded as an initiating class loader ofC. -
Cis considered to have the same runtime package, module and protection domain as the lookup class of thisLookup. - Let
GNbe the binary name obtained by takingN(a binary name encoded in internal form) and replacing ASCII forward slashes with ASCII periods. For the instance ofClassrepresentingC:-
Class.getName()returns the stringGN + "/" + <suffix>, even though this is not a valid binary class or interface name. -
Class.descriptorString()returns the string"L" + N + "." + <suffix> + ";", even though this is not a valid type descriptor name. -
Class.describeConstable()returns an empty optional asCcannot be described in nominal form.
-
- The constant indicated by
After
Cis derived, it is linked by the Java Virtual Machine. Linkage occurs as specified in JVMS 5.4.3, with the following adjustments:- During verification, whenever it is necessary to load the class named
CN, the attempt succeeds, producing classC. No request is made of any class loader. - On any attempt to resolve the entry in the run-time constant pool indicated
by
this_class, the symbolic reference is considered to be resolved toCand resolution always succeeds immediately.
If the
initializeparameter istrue, thenCis initialized by the Java Virtual Machine.The newly created class or interface
Cserves as the lookup class of theLookupobject returned by this method.Cis hidden in the sense that no other class or interface can refer toCvia a constant pool entry. That is, a hidden class or interface cannot be named as a supertype, a field type, a method parameter type, or a method return type by any other class. This is because a hidden class or interface does not have a binary name, so there is no internal form available to record in any class's constant pool. A hidden class or interface is not discoverable byClass.forName(String, boolean, ClassLoader),ClassLoader.loadClass(String, boolean), orfindClass(String), and is not modifiable by Java agents or tool agents using the JVM Tool Interface.A class or interface created by a class loader has a strong relationship with that class loader. That is, every
Classobject contains a reference to theClassLoaderthat defined it. This means that a class created by a class loader may be unloaded if and only if its defining loader is not reachable and thus may be reclaimed by a garbage collector (JLS 12.7). By default, however, a hidden class or interface may be unloaded even if the class loader that is marked as its defining loader is reachable. This behavior is useful when a hidden class or interface serves multiple classes defined by arbitrary class loaders. In other cases, a hidden class or interface may be linked to a single class (or a small number of classes) with the same defining loader as the hidden class or interface. In such cases, where the hidden class or interface must be coterminous with a normal class or interface, theSTRONGoption may be passed inoptions. This arranges for a hidden class to have the same strong relationship with the class loader marked as its defining loader, as a normal class or interface has with its own defining loader. IfSTRONGis not used, then the invoker ofdefineHiddenClassmay still prevent a hidden class or interface from being unloaded by ensuring that theClassobject is reachable.The unloading characteristics are set for each hidden class when it is defined, and cannot be changed later. An advantage of allowing hidden classes to be unloaded independently of the class loader marked as their defining loader is that a very large number of hidden classes may be created by an application. In contrast, if
STRONGis used, then the JVM may run out of memory, just as if normal classes were created by class loaders.Classes and interfaces in a nest are allowed to have mutual access to their private members. The nest relationship is determined by the
NestHostattribute (JVMS 4.7.28) and theNestMembersattribute (JVMS 4.7.29) in aclassfile. By default, a hidden class belongs to a nest consisting only of itself because a hidden class has no binary name. TheNESTMATEoption can be passed inoptionsto create a hidden class or interfaceCas a member of a nest. The nest to whichCbelongs is not based on anyNestHostattribute in theClassFilestructure from whichCwas derived. Instead, the following rules determine the nest host ofC:- If the nest host of the lookup class of this
Lookuphas previously been determined, then letHbe the nest host of the lookup class. Otherwise, the nest host of the lookup class is determined using the algorithm in JVMS 5.4.4, yieldingH. - The nest host of
Cis determined to beH, the nest host of the lookup class.
A hidden class or interface may be serializable, but this requires a custom serialization mechanism in order to ensure that instances are properly serialized and deserialized. The default serialization mechanism supports only classes and interfaces that are discoverable by their class name.
- Parameters:
bytes- the bytes that make up the class data, in the format of a validclassfile as defined by The Java Virtual Machine Specification.initialize- iftruethe class will be initialized.options- class options- Returns:
- the
Lookupobject on the hidden class, with original and full privilege access - Throws:
IllegalAccessException- if thisLookupdoes not have full privilege accessClassFormatError- ifbytesis not aClassFilestructureUnsupportedClassVersionError- ifbytesis not of a supported major or minor versionIllegalArgumentException- ifbytesdenotes a class in a different package than the lookup class orbytesis not a class or interface (ACC_MODULEflag is set in the value of theaccess_flagsitem)IncompatibleClassChangeError- if the class or interface named as the direct superclass ofCis in fact an interface, or if any of the classes or interfaces named as direct superinterfaces ofCare not in fact interfacesClassCircularityError- if any of the superclasses or superinterfaces ofCisCitselfVerifyError- if the newly created class cannot be verifiedLinkageError- if the newly created class cannot be linked for any other reasonNullPointerException- if any parameter isnull- See Java Language Specification:
-
12.7 Unloading of Classes and Interfaces
- See Java Virtual Machine Specification:
-
4.2.1 Binary Class and Interface Names
4.2.2 Unqualified Names
4.7.28 TheNestHostAttribute
4.7.29 TheNestMembersAttribute
5.4.3.1 Class and Interface Resolution
5.4.4 Access Control
5.3.5 Deriving aClassfrom aclassFile Representation
5.4 Linking
5.5 Initialization - Since:
- 15
- See Also:
- The lookup modes for this
-
defineHiddenClassWithClassData
public MethodHandles.Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options) throws IllegalAccessException Creates a hidden class or interface frombyteswith associated class data, returning aLookupon the newly created class or interface.This method is equivalent to calling
defineHiddenClass(bytes, initialize, options)as if the hidden class is injected with a private static final unnamed field which is initialized with the givenclassDataat the first instruction of the class initializer. The newly created class is linked by the Java Virtual Machine.The
MethodHandles::classDataandMethodHandles::classDataAtmethods can be used to retrieve theclassData.- API Note:
- A framework can create a hidden class with class data with one or more
objects and load the class data as dynamically-computed constant(s)
via a bootstrap method.
Class datais accessible only to the lookup object created by the newly defined hidden class but inaccessible to other members in the same nest (unlike private static fields that are accessible to nestmates). Care should be taken w.r.t. mutability for example when passing an array or other mutable structure through the class data. Changing any value stored in the class data at runtime may lead to unpredictable behavior. If the class data is aList, it is good practice to make it unmodifiable for example viaList::of. - Parameters:
bytes- the class bytesclassData- pre-initialized class datainitialize- iftruethe class will be initialized.options- class options- Returns:
- the
Lookupobject on the hidden class, with original and full privilege access - Throws:
IllegalAccessException- if thisLookupdoes not have full privilege accessClassFormatError- ifbytesis not aClassFilestructureUnsupportedClassVersionError- ifbytesis not of a supported major or minor versionIllegalArgumentException- ifbytesdenotes a class in a different package than the lookup class orbytesis not a class or interface (ACC_MODULEflag is set in the value of theaccess_flagsitem)IncompatibleClassChangeError- if the class or interface named as the direct superclass ofCis in fact an interface, or if any of the classes or interfaces named as direct superinterfaces ofCare not in fact interfacesClassCircularityError- if any of the superclasses or superinterfaces ofCisCitselfVerifyError- if the newly created class cannot be verifiedLinkageError- if the newly created class cannot be linked for any other reasonNullPointerException- if any parameter isnull- See Java Language Specification:
-
12.7 Unloading of Classes and Interfaces
- See Java Virtual Machine Specification:
-
4.2.1 Binary Class and Interface Names
4.2.2 Unqualified Names
4.7.28 TheNestHostAttribute
4.7.29 TheNestMembersAttribute
5.4.3.1 Class and Interface Resolution
5.4.4 Access Control
5.3.5 Deriving aClassfrom aclassFile Representation
5.4 Linking
5.5 Initialization - Since:
- 16
- See Also:
-
toString
Displays the name of the class from which lookups are to be made, followed by "/" and the name of the previous lookup class if present. (The name is the one reported byClass.getName.) If there are restrictions on the access permitted to this lookup, this is indicated by adding a suffix to the class name, consisting of a slash and a keyword. The keyword represents the strongest allowed access, and is chosen as follows:- If no access is allowed, the suffix is "/noaccess".
- If only unconditional access is allowed, the suffix is "/publicLookup".
- If only public access to types in exported packages is allowed, the suffix is "/public".
- If only public and module access are allowed, the suffix is "/module".
- If public and package access are allowed, the suffix is "/package".
- If public, package, and private access are allowed, the suffix is "/private".
MethodHandles.lookup. Objects created byLookup.inalways have restricted access, and will display a suffix.(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.)
-
findStatic
public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException Produces a method handle for a static method. The type of the method handle will be that of the method. (Since static methods do not take receivers, there is no additional receiver argument inserted into the method handle type, as there would be withfindVirtualorfindSpecial.) The method and all its argument types must be accessible to the lookup object.The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set.If the returned method handle is invoked, the method's class will be initialized, if it has not already been initialized.
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_asList = publicLookup().findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());- Parameters:
refc- the class from which the method is accessedname- the name of the methodtype- the type of the method- Returns:
- the desired method handle
- Throws:
NoSuchMethodException- if the method does not existIllegalAccessException- if access checking fails, or if the method is notstatic, or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null
-
findVirtual
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException Produces a method handle for a virtual method. The type of the method handle will be that of the method, with the receiver type (usuallyrefc) prepended. The method and all its argument types must be accessible to the lookup object.When called, the handle will treat the first argument as a receiver and, for non-private methods, dispatch on the receiver's type to determine which method implementation to enter. For private methods the named method in
refcwill be invoked on the receiver. (The dispatching action is identical with that performed by aninvokevirtualorinvokeinterfaceinstruction.)The first argument will be of type
refcif the lookup class has full privileges to access the member. Otherwise the member must beprotectedand the first argument will be restricted in type to the lookup class.The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set.Because of the general equivalence between
invokevirtualinstructions and method handles produced byfindVirtual, if the class isMethodHandleand the name string isinvokeExactorinvoke, the resulting method handle is equivalent to one produced byMethodHandles.exactInvokerorMethodHandles.invokerwith the sametypeargument.If the class is
VarHandleand the name string corresponds to the name of a signature-polymorphic access mode method, the resulting method handle is equivalent to one produced byMethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType)with the access mode corresponding to the name string and with the sametypearguments.Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_concat = publicLookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class, "hashCode", methodType(int.class)); MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class, "hashCode", methodType(int.class)); assertEquals("xy", (String) MH_concat.invokeExact("x", "y")); assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy")); assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy")); // interface method: MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class, "subSequence", methodType(CharSequence.class, int.class, int.class)); assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString()); // constructor "internal method" must be accessed differently: MethodType MT_newString = methodType(void.class); //()V for new String() try { assertEquals("impossible", lookup() .findVirtual(String.class, "<init>", MT_newString)); } catch (NoSuchMethodException ex) { } // OK MethodHandle MH_newString = publicLookup() .findConstructor(String.class, MT_newString); assertEquals("", (String) MH_newString.invokeExact());- Parameters:
refc- the class or interface from which the method is accessedname- the name of the methodtype- the type of the method, with the receiver argument omitted- Returns:
- the desired method handle
- Throws:
NoSuchMethodException- if the method does not existIllegalAccessException- if access checking fails, or if the method isstatic, or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null
-
findConstructor
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException Produces a method handle which creates an object and initializes it, using 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 object.The requested type must have a return type of
void. (This is consistent with the JVM's treatment of constructor type descriptors.)The returned method handle will have variable arity if and only if the constructor's variable arity modifier bit (
0x0080) is set.If the returned method handle is invoked, the constructor's class will be initialized, if it has not already been initialized.
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_newArrayList = publicLookup().findConstructor( ArrayList.class, methodType(void.class, Collection.class)); Collection orig = Arrays.asList("x", "y"); Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig); assert(orig != copy); assertEquals(orig, copy); // a variable-arity constructor: MethodHandle MH_newProcessBuilder = publicLookup().findConstructor( ProcessBuilder.class, methodType(void.class, String[].class)); ProcessBuilder pb = (ProcessBuilder) MH_newProcessBuilder.invoke("x", "y", "z"); assertEquals("[x, y, z]", pb.command().toString());- Parameters:
refc- the class or interface from which the method is accessedtype- the type of the method, with the receiver argument omitted, and a void return type- Returns:
- the desired method handle
- Throws:
NoSuchMethodException- if the constructor does not existIllegalAccessException- if access checking fails or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null
-
findClass
Looks up a class by name from the lookup context defined by thisLookupobject, as if resolved by anldcinstruction. Such a resolution, as specified in JVMS 5.4.3.1, attempts to locate and load the class, and then determines whether the class is accessible to this lookup object.For a class or an interface, the name is the binary name. For an array class of
ndimensions, the name begins withnoccurrences of'['and followed by the element type as encoded in the table specified inClass.getName().The lookup context here is determined by the lookup class, its class loader, and the lookup modes.
- Parameters:
targetName- the binary name of the class or the string representing an array class- Returns:
- the requested class.
- Throws:
LinkageError- if the linkage failsClassNotFoundException- if the class cannot be loaded by the lookup class' loader.IllegalAccessException- if the class is not accessible, using the allowed access modes.NullPointerException- iftargetNameis null- See Java Virtual Machine Specification:
-
5.4.3.1 Class and Interface Resolution
- Since:
- 9
-
ensureInitialized
Ensures thattargetClasshas been initialized. The class to be initialized must be accessible to thisLookupobject. This method causestargetClassto be initialized if it has not been already initialized, as specified in JVMS 5.5.This method returns when
targetClassis fully initialized, or whentargetClassis being initialized by the current thread.- Type Parameters:
T- the type of the class to be initialized- Parameters:
targetClass- the class to be initialized- Returns:
targetClassthat has been initialized, or that is being initialized by the current thread.- Throws:
IllegalArgumentException- iftargetClassis a primitive type orvoidor array classIllegalAccessException- iftargetClassis not accessible to this lookupExceptionInInitializerError- if the class initialization provoked by this method fails- See Java Virtual Machine Specification:
-
5.5 Initialization
- Since:
- 15
-
accessClass
Determines if a class can be accessed from the lookup context defined by thisLookupobject. The static initializer of the class is not run. IftargetClassis an array class,targetClassis accessible if the element type of the array class is accessible. Otherwise,targetClassis determined as accessible as follows.If
targetClassis in the same module as the lookup class, the lookup class isLCin moduleM1and the previous lookup class is in moduleM0ornullif not present,targetClassis accessible if and only if one of the following is true:- If this lookup has
PRIVATEaccess,targetClassisLCor other class in the same nest ofLC. - If this lookup has
PACKAGEaccess,targetClassis in the same runtime package ofLC. - If this lookup has
MODULEaccess,targetClassis a public type inM1. - If this lookup has
PUBLICaccess,targetClassis a public type in a package exported byM1to at leastM0if the previous lookup class is present; otherwise,targetClassis a public type in a package exported byM1unconditionally.
Otherwise, if this lookup has
UNCONDITIONALaccess, this lookup can access public types in all modules when the type is in a package that is exported unconditionally.Otherwise,
targetClassis in a different module fromlookupClass, and if this lookup does not havePUBLICaccess,lookupClassis inaccessible.Otherwise, if this lookup has no previous lookup class,
M1is the module containinglookupClassandM2is the module containingtargetClass, thentargetClassis accessible if and only ifM1readsM2, andtargetClassis public and in a package exported byM2at least toM1.
Otherwise, if this lookup has a previous lookup class,
M1andM2are as before, andM0is the module containing the previous lookup class, thentargetClassis accessible if and only if one of the following is true:targetClassis inM0andM1readsM0and the type is in a package that is exported to at leastM1.targetClassis inM1andM0readsM1and the type is in a package that is exported to at leastM0.targetClassis in a third moduleM2and bothM0andM1readsM2and the type is in a package that is exported to at least bothM0andM2.
Otherwise,
targetClassis not accessible.- Type Parameters:
T- the type of the class to be access-checked- Parameters:
targetClass- the class to be access-checked- Returns:
targetClassthat has been access-checked- Throws:
IllegalAccessException- if the class is not accessible from the lookup class and previous lookup class, if present, using the allowed access modes.NullPointerException- iftargetClassisnull- Since:
- 9
- See Also:
- If this lookup has
-
findSpecial
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException Produces an early-bound method handle for a virtual method. It will bypass checks for overriding methods on the receiver, as if called from aninvokespecialinstruction from within the explicitly specifiedspecialCaller. The type of the method handle will be that of the method, with a suitably restricted receiver type prepended. (The receiver type will bespecialCalleror a subtype.) The method and all its argument types must be accessible to the lookup object.Before method resolution, if the explicitly specified caller class is not identical with the lookup class, or if this lookup object does not have private access privileges, the access fails.
The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set.(Note: JVM internal methods named "<init>" are not visible to this API, even though the
invokespecialinstruction can refer to them in special circumstances. UsefindConstructorto access instance initialization methods in a safe manner.)Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... static class Listie extends ArrayList { public String toString() { return "[wee Listie]"; } static Lookup lookup() { return MethodHandles.lookup(); } } ... // no access to constructor via invokeSpecial: MethodHandle MH_newListie = Listie.lookup() .findConstructor(Listie.class, methodType(void.class)); Listie l = (Listie) MH_newListie.invokeExact(); try { assertEquals("impossible", Listie.lookup().findSpecial( Listie.class, "<init>", methodType(void.class), Listie.class)); } catch (NoSuchMethodException ex) { } // OK // access to super and self methods via invokeSpecial: MethodHandle MH_super = Listie.lookup().findSpecial( ArrayList.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_this = Listie.lookup().findSpecial( Listie.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_duper = Listie.lookup().findSpecial( Object.class, "toString" , methodType(String.class), Listie.class); assertEquals("[]", (String) MH_super.invokeExact(l)); assertEquals(""+l, (String) MH_this.invokeExact(l)); assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method try { assertEquals("inaccessible", Listie.lookup().findSpecial( String.class, "toString", methodType(String.class), Listie.class)); } catch (IllegalAccessException ex) { } // OK Listie subl = new Listie() { public String toString() { return "[subclass]"; } }; assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method- Parameters:
refc- the class or interface from which the method is accessedname- the name of the method (which must not be "<init>")type- the type of the method, with the receiver argument omittedspecialCaller- the proposed calling class to perform theinvokespecial- Returns:
- the desired method handle
- Throws:
NoSuchMethodException- if the method does not existIllegalAccessException- if access checking fails, or if the method isstatic, or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null
-
findGetter
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a method handle giving read access to a non-static field. The type of the method handle will have a return type of the field's value type. The method handle's single argument will be the instance containing the field. Access checking is performed immediately on behalf of the lookup class.- Parameters:
refc- the class or interface from which the method is accessedname- the field's nametype- the field's type- Returns:
- a method handle which can load values from the field
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field isstaticNullPointerException- if any argument is null- See Also:
-
findSetter
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a method handle giving write access to a non-static field. The type of the method handle will have a void return type. The method handle will take two arguments, the instance containing the field, and the value to be stored. The second argument will be of the field's value type. Access checking is performed immediately on behalf of the lookup class.- Parameters:
refc- the class or interface from which the method is accessedname- the field's nametype- the field's type- Returns:
- a method handle which can store values into the field
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field isstaticorfinalNullPointerException- if any argument is null- See Also:
-
findVarHandle
public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a VarHandle giving access to a non-static fieldnameof typetypedeclared in a class of typerecv. The VarHandle's variable type istypeand it has one coordinate type,recv.Access checking is performed immediately on behalf of the lookup class.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
- if the field is declared
final, then the write, atomic update, numeric atomic update, and bitwise atomic update access modes are unsupported. - if the field type is anything other than
byte,short,char,int,long,float, ordoublethen numeric atomic update access modes are unsupported. - if the field type is anything other than
boolean,byte,short,char,intorlongthen bitwise atomic update access modes are unsupported.
If the field is declared
volatilethen the returned VarHandle will override access to the field (effectively ignore thevolatiledeclaration) in accordance to its specified access modes.If the field type is
floatordoublethen numeric and atomic update access modes compare values using their bitwise representation (seeFloat.floatToRawIntBits(float)andDouble.doubleToRawLongBits(double), respectively).- API Note:
- Bitwise comparison of
floatvalues ordoublevalues, as performed by the numeric and atomic update access modes, differ from the primitive==operator and theFloat.equals(java.lang.Object)andDouble.equals(java.lang.Object)methods, specifically with respect to comparing NaN values or comparing-0.0with+0.0. Care should be taken when performing a compare and set or a compare and exchange operation with such values since the operation may unexpectedly fail. There are many possible NaN values that are considered to beNaNin Java, although no IEEE 754 floating-point operation provided by Java can distinguish between them. Operation failure can occur if the expected or witness value is a NaN value and it is transformed (perhaps in a platform specific manner) into another NaN value, and thus has a different bitwise representation (seeFloat.intBitsToFloat(int)orDouble.longBitsToDouble(long)for more details). The values-0.0and+0.0have different bitwise representations but are considered equal when using the primitive==operator. Operation failure can occur if, for example, a numeric algorithm computes an expected value to be say-0.0and previously computed the witness value to be say+0.0. - Parameters:
recv- the receiver class, of typeR, that declares the non-static fieldname- the field's nametype- the field's type, of typeT- Returns:
- a VarHandle giving access to non-static fields.
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field isstaticNullPointerException- if any argument is null- Since:
- 9
- if the field is declared
-
findStaticGetter
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a method handle giving read access to a static field. 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.If the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
- Parameters:
refc- the class or interface from which the method is accessedname- the field's nametype- the field's type- Returns:
- a method handle which can load values from the field
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field is notstaticNullPointerException- if any argument is null
-
findStaticSetter
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a method handle giving write access to a static field. 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. Access checking is performed immediately on behalf of the lookup class.If the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
- Parameters:
refc- the class or interface from which the method is accessedname- the field's nametype- the field's type- Returns:
- a method handle which can store values into the field
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field is notstaticor isfinalNullPointerException- if any argument is null
-
findStaticVarHandle
public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException Produces a VarHandle giving access to a static fieldnameof typetypedeclared in a class of typedecl. The VarHandle's variable type istypeand it has no coordinate types.Access checking is performed immediately on behalf of the lookup class.
If the returned VarHandle is operated on, the declaring class will be initialized, if it has not already been initialized.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
- if the field is declared
final, then the write, atomic update, numeric atomic update, and bitwise atomic update access modes are unsupported. - if the field type is anything other than
byte,short,char,int,long,float, ordouble, then numeric atomic update access modes are unsupported. - if the field type is anything other than
boolean,byte,short,char,intorlongthen bitwise atomic update access modes are unsupported.
If the field is declared
volatilethen the returned VarHandle will override access to the field (effectively ignore thevolatiledeclaration) in accordance to its specified access modes.If the field type is
floatordoublethen numeric and atomic update access modes compare values using their bitwise representation (seeFloat.floatToRawIntBits(float)andDouble.doubleToRawLongBits(double), respectively).- API Note:
- Bitwise comparison of
floatvalues ordoublevalues, as performed by the numeric and atomic update access modes, differ from the primitive==operator and theFloat.equals(java.lang.Object)andDouble.equals(java.lang.Object)methods, specifically with respect to comparing NaN values or comparing-0.0with+0.0. Care should be taken when performing a compare and set or a compare and exchange operation with such values since the operation may unexpectedly fail. There are many possible NaN values that are considered to beNaNin Java, although no IEEE 754 floating-point operation provided by Java can distinguish between them. Operation failure can occur if the expected or witness value is a NaN value and it is transformed (perhaps in a platform specific manner) into another NaN value, and thus has a different bitwise representation (seeFloat.intBitsToFloat(int)orDouble.longBitsToDouble(long)for more details). The values-0.0and+0.0have different bitwise representations but are considered equal when using the primitive==operator. Operation failure can occur if, for example, a numeric algorithm computes an expected value to be say-0.0and previously computed the witness value to be say+0.0. - Parameters:
decl- the class that declares the static fieldname- the field's nametype- the field's type, of typeT- Returns:
- a VarHandle giving access to a static field
- Throws:
NoSuchFieldException- if the field does not existIllegalAccessException- if access checking fails, or if the field is notstaticNullPointerException- if any argument is null- Since:
- 9
- if the field is declared
-
bind
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException Produces an early-bound method handle for a non-static method. The receiver must have a supertypedefcin 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 object. 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.The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set and 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.)This is almost equivalent to the following code, with some differences noted below:
whereimport static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle mh0 = lookup().findVirtual(defc, name, type); MethodHandle mh1 = mh0.bindTo(receiver); mh1 = mh1.withVarargs(mh0.isVarargsCollector()); return mh1;defcis eitherreceiver.getClass()or a super type of that class, in which the requested method is accessible to the lookup class. (Unlikebind,bindTodoes not preserve variable arity. Also,bindTomay throw aClassCastExceptionin instances wherebindwould throw anIllegalAccessException, as in the case where the member isprotectedand the receiver is restricted byfindVirtualto the lookup class.)- Parameters:
receiver- the object from which the method is accessedname- the name of the methodtype- the type of the method, with the receiver argument omitted- Returns:
- the desired method handle
- Throws:
NoSuchMethodException- if the method does not existIllegalAccessException- if access checking fails or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null- See Also:
-
unreflect
Makes a direct method handle to m, if the lookup class has permission. If m is non-static, the receiver argument is treated as an initial argument. If m is virtual, overriding is respected on every call. Unlike the Core Reflection API, exceptions are not 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'saccessibleflag is not set, access checking is performed immediately on behalf of the lookup class. If m is not public, do not share the resulting handle with untrusted parties.The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set.If m is static, and if the returned method handle is invoked, the method's class will be initialized, if it has not already been initialized.
- Parameters:
m- the reflected method- Returns:
- a method handle which can invoke the reflected method
- Throws:
IllegalAccessException- if access checking fails or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if the argument is null
-
unreflectSpecial
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException Produces a method handle for a reflected method. It will bypass checks for overriding methods on the receiver, as if called from aninvokespecialinstruction from within the explicitly specifiedspecialCaller. The type of the method handle will be that of the method, with a suitably restricted receiver type prepended. (The receiver type will bespecialCalleror a subtype.) If the method'saccessibleflag is not set, access checking is performed immediately on behalf of the lookup class, as ifinvokespecialinstruction were being linked.Before method resolution, if the explicitly specified caller class is not identical with the lookup class, or if this lookup object does not have private access privileges, the access fails.
The returned method handle will have variable arity if and only if the method's variable arity modifier bit (
0x0080) is set.- Parameters:
m- the reflected methodspecialCaller- the class nominally calling the method- Returns:
- a method handle which can invoke the reflected method
- Throws:
IllegalAccessException- if access checking fails, or if the method isstatic, or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if any argument is null
-
unreflectConstructor
Produces a method handle for a reflected constructor. The type of the method handle will be that of the constructor, with the return type changed to the declaring class. The method handle will perform anewInstanceoperation, creating a new instance of the constructor's class on the arguments passed to the method handle.If the constructor's
accessibleflag is not set, access checking is performed immediately on behalf of the lookup class.The returned method handle will have variable arity if and only if the constructor's variable arity modifier bit (
0x0080) is set.If the returned method handle is invoked, the constructor's class will be initialized, if it has not already been initialized.
- Parameters:
c- the reflected constructor- Returns:
- a method handle which can invoke the reflected constructor
- Throws:
IllegalAccessException- if access checking fails or if the method's variable arity modifier bit is set andasVarargsCollectorfailsNullPointerException- if the argument is null
-
unreflectGetter
Produces a method handle giving read access to a reflected field. The type of the method handle will have a return type of the field's value type. If the field isstatic, the method handle will take no arguments. Otherwise, its single argument will be the instance containing the field. If theFieldobject'saccessibleflag is not set, access checking is performed immediately on behalf of the lookup class.If the field is static, and if the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
- Parameters:
f- the reflected field- Returns:
- a method handle which can load values from the reflected field
- Throws:
IllegalAccessException- if access checking failsNullPointerException- if the argument is null
-
unreflectSetter
Produces a method handle giving write access to a reflected field. The type of the method handle will have a void return type. If the field isstatic, 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. If theFieldobject'saccessibleflag is not set, access checking is performed immediately on behalf of the lookup class.If the field is
final, write access will not be allowed and access checking will fail, except under certain narrow circumstances documented forField.set. A method handle is returned only if a corresponding call to theFieldobject'ssetmethod could return normally. In particular, fields which are bothstaticandfinalmay never be set.If the field is
static, and if the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.- Parameters:
f- the reflected field- Returns:
- a method handle which can store values into the reflected field
- Throws:
IllegalAccessException- if access checking fails, or if the field isfinaland write access is not enabled on theFieldobjectNullPointerException- if the argument is null
-
unreflectVarHandle
Produces a VarHandle giving access to a reflected fieldfof typeTdeclared in a class of typeR. The VarHandle's variable type isT. If the field is non-static the VarHandle has one coordinate type,R. Otherwise, the field is static, and the VarHandle has no coordinate types.Access checking is performed immediately on behalf of the lookup class, regardless of the value of the field's
accessibleflag.If the field is static, and if the returned VarHandle is operated on, the field's declaring class will be initialized, if it has not already been initialized.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
- if the field is declared
final, then the write, atomic update, numeric atomic update, and bitwise atomic update access modes are unsupported. - if the field type is anything other than
byte,short,char,int,long,float, ordoublethen numeric atomic update access modes are unsupported. - if the field type is anything other than
boolean,byte,short,char,intorlongthen bitwise atomic update access modes are unsupported.
If the field is declared
volatilethen the returned VarHandle will override access to the field (effectively ignore thevolatiledeclaration) in accordance to its specified access modes.If the field type is
floatordoublethen numeric and atomic update access modes compare values using their bitwise representation (seeFloat.floatToRawIntBits(float)andDouble.doubleToRawLongBits(double), respectively).- API Note:
- Bitwise comparison of
floatvalues ordoublevalues, as performed by the numeric and atomic update access modes, differ from the primitive==operator and theFloat.equals(java.lang.Object)andDouble.equals(java.lang.Object)methods, specifically with respect to comparing NaN values or comparing-0.0with+0.0. Care should be taken when performing a compare and set or a compare and exchange operation with such values since the operation may unexpectedly fail. There are many possible NaN values that are considered to beNaNin Java, although no IEEE 754 floating-point operation provided by Java can distinguish between them. Operation failure can occur if the expected or witness value is a NaN value and it is transformed (perhaps in a platform specific manner) into another NaN value, and thus has a different bitwise representation (seeFloat.intBitsToFloat(int)orDouble.longBitsToDouble(long)for more details). The values-0.0and+0.0have different bitwise representations but are considered equal when using the primitive==operator. Operation failure can occur if, for example, a numeric algorithm computes an expected value to be say-0.0and previously computed the witness value to be say+0.0. - Parameters:
f- the reflected field, with a field of typeT, and a declaring class of typeR- Returns:
- a VarHandle giving access to non-static fields or a static field
- Throws:
IllegalAccessException- if access checking failsNullPointerException- if the argument is null- Since:
- 9
- if the field is declared
-
revealDirect
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. This can happen if the method handle is caller sensitive and was created by a lookup object for a different class.- Parameters:
target- a direct method handle to crack into symbolic reference components- Returns:
- a symbolic reference which can be used to reconstruct this method handle from this lookup object
- Throws:
IllegalArgumentException- if the target is not a direct method handle or if access checking failsNullPointerException- if the target isnull- Since:
- 1.8
- See Also:
-
hasPrivateAccess
Deprecated.This method was originally designed to testPRIVATEaccess that implies full privilege access butMODULEaccess has since become independent ofPRIVATEaccess. It is recommended to callhasFullPrivilegeAccess()instead.Returnstrueif this lookup hasPRIVATEandMODULEaccess.- Returns:
trueif this lookup hasPRIVATEandMODULEaccess.- Since:
- 9
-
hasFullPrivilegeAccess
public boolean hasFullPrivilegeAccess()Returnstrueif this lookup has full privilege access, i.e.PRIVATEandMODULEaccess. ALookupobject must have full privilege access in order to access all members that are allowed to the lookup class.- Returns:
trueif this lookup has full privilege access.- Since:
- 14
- See Also:
-
PRIVATEaccess that implies full privilege access butMODULEaccess has since become independent ofPRIVATEaccess.