A lookup class which needs to create method handles will call {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself.When the {@code Lookup} factory object is created, the identity of the lookup class isdetermined, and securely stored in the {@code Lookup} object.The lookup class (or its delegates) may then use factory methods on the {@code Lookup} object to create method handles for access-checked members.This includes all methods, constructors, and fields which are allowed to the lookup class, even private ones.
In cases where the given member is of variable arity (i.e., a method or constructor) the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}. In all other cases, the returned method handle will be of fixed arity.
Discussion: The equivalence between looked-up method handles and underlying class members and bytecode behaviors can break down in a few ways:
All access checks start from a {@code Lookup} object, whichcompares its recorded lookup class against all requests to create method handles. A single {@code Lookup} object can be used to create any numberof access-checked method handles, all checked against a single lookup class.
A {@code Lookup} object can be shared with other trusted code,such as a metaobject protocol. A shared {@code Lookup} object delegates the capabilityto create method handles on private members of the lookup class. Even if privileged code uses the {@code Lookup} object,the access checking is confined to the privileges of the original lookup class.
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 {@code ReflectiveOperationException} will bethrown from the attempted lookup. The exact class will be one of the following:
In general, the conditions under which a method handle may be looked up for a method {@code M} are no more restrictive than the conditionsunder which the lookup class could have compiled, verified, and resolved a call to {@code M}. Where the JVM would raise exceptions like {@code NoSuchMethodError}, a method handle lookup will generally raise a corresponding checked exception, such as {@code 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 {@code 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 {@link MethodHandle#asType MethodHandle.asType}, do not require any access checks, and are used independently of any {@code Lookup} object.
If the desired member is {@code protected}, the usual JVM rules apply, including the requirement that the lookup class must be either be in the same package as the desired member, or must inherit that member. (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.) In addition, if the desired member is a non-static field or method in a different package, the resulting method handle may only be applied to objects of the lookup class or one of its subclasses. This requirement is enforced by narrowing the type of the leading {@code this} parameter from {@code C}(which will necessarily be a superclass of the lookup class) to the lookup class itself.
The JVM imposes a similar requirement on {@code 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 ( {@code " In some cases, access between nested classes is obtained by the Java compiler by creating an wrapper method to access a private method of another class in the same top-level declaration. For example, a nested class {@code C.D}can access private members within other related classes such as {@code C}, {@code C.D.E}, or {@code C.B}, but the Java compiler may need to generate wrapper methods in those related classes. In such cases, a {@code Lookup} object on{@code C.E} would be unable to those private members.A workaround for this limitation is the {@link Lookup#in Lookup.in} method,which can transform a lookup on {@code C.E} into one on any of those otherclasses, without special elevation of privilege. The accesses permitted to a given lookup object may be limited, according to its set of {@link #lookupModes lookupModes}, to a subset of members normally accessible to the lookup class. For example, the {@link MethodHandles#publicLookup publicLookup}method produces a lookup object which is only allowed to access public members in public classes. The caller sensitive method {@link MethodHandles#lookup lookup}produces a lookup object with full capabilities relative to its caller class, to emulate all supported bytecode behaviors. Also, the {@link Lookup#in Lookup.in} method may produce a lookup objectwith fewer access modes than the original lookup object. Discussion of private access: We say that a lookup has private access if its {@linkplain #lookupModes lookup modes}include the possibility of accessing {@code private} members.As documented in the relevant methods elsewhere, only lookups with private access possess the following capabilities: 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. If a security manager is present, member 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 a {@link java.lang.SecurityException SecurityException}. Define {@code smgr} as the security manager,{@code lookc} as the lookup class of the current lookup object,{@code refc} as the containing class in which the memberis being sought, and {@code defc} as the class in which themember is actually defined. The value {@code lookc} is defined as not presentif the current lookup object does not have private access. The calls are made according to the following rules: 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 {@link MethodHandles#publicLookup() publicLookup()}, or some other lookup object without private 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 {@code IllegalAccessException}. Discussion: For example, the caller-sensitive method {@link java.lang.Class#forName(String) 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 {@code Class.forName} will fail, becausethere is no reasonable way to determine its bytecode behavior. If an application caches method handles for broad sharing, it should use {@code publicLookup()} to create them.If there is a lookup of {@code 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 {@code MethodHandles.lookup} is caller sensitiveso 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.
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 {@code Class} object isavailable. Such cross-loader references are also possible with the Core Reflection API, and are impossible to bytecode instructions such as {@code invokestatic} or {@code getfield}. There is a {@linkplain java.lang.SecurityManager security manager API}to allow applications to check such cross-loader references. These checks apply to both the {@code MethodHandles.Lookup} APIand the Core Reflection API (as found on {@link java.lang.Class Class}).
Security checks are performed after other access checks have passed. Therefore, the above rules presuppose a member that is public, or else that is being accessed from a lookup class that has rights to access the member. 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.
|
|