MethodHandles.Lookup (Java SE 9 & JDK 9 ) (original) (raw)


public static final class MethodHandles.Lookup
extends Object
A lookup object is a factory for creating method handles, when the creation requires access checking. Method handles do not perform access checks when they are called, but rather when they are created. Therefore, method handle access restrictions must be enforced when a method handle is created. The caller class against which those restrictions are enforced is known as the lookup class.
A lookup class which needs to create method handles will callMethodHandles.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 a Lookup 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 method behaviors

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; (T) 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.unreflect(aMethod) (static)?T m(A*); (T) aMethod.invoke(thisOrNull, arg*);
lookup.findClass("C") class C { ... } C.class;
Here, the type 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.
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:

Access checking

Access checks are applied in the factory methods of Lookup, when a method handle is created. This is a key difference from the Core Reflection API, sincejava.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 any of these cases, a ReflectiveOperationException will be thrown from the attempted lookup. The exact class will be one of the following:

Security manager interactions

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 Class object is available. Such cross-loader references are also possible with the Core Reflection API, and are impossible to bytecode instructions such as invokestatic or getfield. There is a security manager API to allow applications to check such cross-loader references. These checks apply to both the MethodHandles.Lookup API and the Core Reflection API (as found on Class).
If a security manager is present, member and class lookups are subject to additional checks. From one to three calls are made to the security manager. Any of these calls can refuse access by throwing aSecurityException. Define smgr as the security manager,lookc as the lookup class of the current lookup object,refc as the containing class in which the member is being sought, and defc as the class in which the member is actually defined. (If a class or other type is being accessed, the refc and defc values are the class itself.) The value lookc is defined as not present if the current lookup object does not haveprivate access. The calls are made according to the following rules:

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 ispublicLookup(), or some other lookup object withoutprivate 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 anIllegalAccessException.
Discussion: For example, the caller-sensitive methodClass.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.