jaroslav@1646: /* jaroslav@1646: * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. jaroslav@1646: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@1646: * jaroslav@1646: * This code is free software; you can redistribute it and/or modify it jaroslav@1646: * under the terms of the GNU General Public License version 2 only, as jaroslav@1646: * published by the Free Software Foundation. Oracle designates this jaroslav@1646: * particular file as subject to the "Classpath" exception as provided jaroslav@1646: * by Oracle in the LICENSE file that accompanied this code. jaroslav@1646: * jaroslav@1646: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@1646: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@1646: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@1646: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@1646: * accompanied this code). jaroslav@1646: * jaroslav@1646: * You should have received a copy of the GNU General Public License version jaroslav@1646: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@1646: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@1646: * jaroslav@1646: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@1646: * or visit www.oracle.com if you need additional information or have any jaroslav@1646: * questions. jaroslav@1646: */ jaroslav@1646: package java.lang.invoke; jaroslav@1646: jaroslav@1646: import java.io.Serializable; jaroslav@1646: import java.lang.reflect.Method; jaroslav@1646: import java.security.AccessController; jaroslav@1646: import java.security.PrivilegedActionException; jaroslav@1646: import java.security.PrivilegedExceptionAction; jaroslav@1646: import java.util.Objects; jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Serialized form of a lambda expression. The properties of this class jaroslav@1646: * represent the information that is present at the lambda factory site, including jaroslav@1646: * static metafactory arguments such as the identity of the primary functional jaroslav@1646: * interface method and the identity of the implementation method, as well as jaroslav@1646: * dynamic metafactory arguments such as values captured from the lexical scope jaroslav@1646: * at the time of lambda capture. jaroslav@1646: * jaroslav@1646: *

Implementors of serializable lambdas, such as compilers or language jaroslav@1646: * runtime libraries, are expected to ensure that instances deserialize properly. jaroslav@1646: * One means to do so is to ensure that the {@code writeReplace} method returns jaroslav@1646: * an instance of {@code SerializedLambda}, rather than allowing default jaroslav@1646: * serialization to proceed. jaroslav@1646: * jaroslav@1646: *

{@code SerializedLambda} has a {@code readResolve} method that looks for jaroslav@1646: * a (possibly private) static method called jaroslav@1646: * {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes jaroslav@1646: * that with itself as the first argument, and returns the result. Lambda classes jaroslav@1646: * implementing {@code $deserializeLambda$} are responsible for validating jaroslav@1646: * that the properties of the {@code SerializedLambda} are consistent with a jaroslav@1646: * lambda actually captured by that class. jaroslav@1646: * jaroslav@1646: * @see LambdaMetafactory jaroslav@1646: */ jaroslav@1646: public final class SerializedLambda implements Serializable { jaroslav@1646: private static final long serialVersionUID = 8025925345765570181L; jaroslav@1646: private final Class capturingClass; jaroslav@1646: private final String functionalInterfaceClass; jaroslav@1646: private final String functionalInterfaceMethodName; jaroslav@1646: private final String functionalInterfaceMethodSignature; jaroslav@1646: private final String implClass; jaroslav@1646: private final String implMethodName; jaroslav@1646: private final String implMethodSignature; jaroslav@1646: private final int implMethodKind; jaroslav@1646: private final String instantiatedMethodType; jaroslav@1646: private final Object[] capturedArgs; jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Create a {@code SerializedLambda} from the low-level information present jaroslav@1646: * at the lambda factory site. jaroslav@1646: * jaroslav@1646: * @param capturingClass The class in which the lambda expression appears jaroslav@1646: * @param functionalInterfaceClass Name, in slash-delimited form, of static jaroslav@1646: * type of the returned lambda object jaroslav@1646: * @param functionalInterfaceMethodName Name of the functional interface jaroslav@1646: * method for the present at the jaroslav@1646: * lambda factory site jaroslav@1646: * @param functionalInterfaceMethodSignature Signature of the functional jaroslav@1646: * interface method present at jaroslav@1646: * the lambda factory site jaroslav@1646: * @param implMethodKind Method handle kind for the implementation method jaroslav@1646: * @param implClass Name, in slash-delimited form, for the class holding jaroslav@1646: * the implementation method jaroslav@1646: * @param implMethodName Name of the implementation method jaroslav@1646: * @param implMethodSignature Signature of the implementation method jaroslav@1646: * @param instantiatedMethodType The signature of the primary functional jaroslav@1646: * interface method after type variables jaroslav@1646: * are substituted with their instantiation jaroslav@1646: * from the capture site jaroslav@1646: * @param capturedArgs The dynamic arguments to the lambda factory site, jaroslav@1646: * which represent variables captured by jaroslav@1646: * the lambda jaroslav@1646: */ jaroslav@1646: public SerializedLambda(Class capturingClass, jaroslav@1646: String functionalInterfaceClass, jaroslav@1646: String functionalInterfaceMethodName, jaroslav@1646: String functionalInterfaceMethodSignature, jaroslav@1646: int implMethodKind, jaroslav@1646: String implClass, jaroslav@1646: String implMethodName, jaroslav@1646: String implMethodSignature, jaroslav@1646: String instantiatedMethodType, jaroslav@1646: Object[] capturedArgs) { jaroslav@1646: this.capturingClass = capturingClass; jaroslav@1646: this.functionalInterfaceClass = functionalInterfaceClass; jaroslav@1646: this.functionalInterfaceMethodName = functionalInterfaceMethodName; jaroslav@1646: this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; jaroslav@1646: this.implMethodKind = implMethodKind; jaroslav@1646: this.implClass = implClass; jaroslav@1646: this.implMethodName = implMethodName; jaroslav@1646: this.implMethodSignature = implMethodSignature; jaroslav@1646: this.instantiatedMethodType = instantiatedMethodType; jaroslav@1646: this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the name of the class that captured this lambda. jaroslav@1646: * @return the name of the class that captured this lambda jaroslav@1646: */ jaroslav@1646: public String getCapturingClass() { jaroslav@1646: return capturingClass.getName().replace('.', '/'); jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the name of the invoked type to which this jaroslav@1646: * lambda has been converted jaroslav@1646: * @return the name of the functional interface class to which jaroslav@1646: * this lambda has been converted jaroslav@1646: */ jaroslav@1646: public String getFunctionalInterfaceClass() { jaroslav@1646: return functionalInterfaceClass; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the name of the primary method for the functional interface jaroslav@1646: * to which this lambda has been converted. jaroslav@1646: * @return the name of the primary methods of the functional interface jaroslav@1646: */ jaroslav@1646: public String getFunctionalInterfaceMethodName() { jaroslav@1646: return functionalInterfaceMethodName; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the signature of the primary method for the functional jaroslav@1646: * interface to which this lambda has been converted. jaroslav@1646: * @return the signature of the primary method of the functional jaroslav@1646: * interface jaroslav@1646: */ jaroslav@1646: public String getFunctionalInterfaceMethodSignature() { jaroslav@1646: return functionalInterfaceMethodSignature; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the name of the class containing the implementation jaroslav@1646: * method. jaroslav@1646: * @return the name of the class containing the implementation jaroslav@1646: * method jaroslav@1646: */ jaroslav@1646: public String getImplClass() { jaroslav@1646: return implClass; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the name of the implementation method. jaroslav@1646: * @return the name of the implementation method jaroslav@1646: */ jaroslav@1646: public String getImplMethodName() { jaroslav@1646: return implMethodName; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the signature of the implementation method. jaroslav@1646: * @return the signature of the implementation method jaroslav@1646: */ jaroslav@1646: public String getImplMethodSignature() { jaroslav@1646: return implMethodSignature; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the method handle kind (see {@link MethodHandleInfo}) of jaroslav@1646: * the implementation method. jaroslav@1646: * @return the method handle kind of the implementation method jaroslav@1646: */ jaroslav@1646: public int getImplMethodKind() { jaroslav@1646: return implMethodKind; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the signature of the primary functional interface method jaroslav@1646: * after type variables are substituted with their instantiation jaroslav@1646: * from the capture site. jaroslav@1646: * @return the signature of the primary functional interface method jaroslav@1646: * after type variable processing jaroslav@1646: */ jaroslav@1646: public final String getInstantiatedMethodType() { jaroslav@1646: return instantiatedMethodType; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get the count of dynamic arguments to the lambda capture site. jaroslav@1646: * @return the count of dynamic arguments to the lambda capture site jaroslav@1646: */ jaroslav@1646: public int getCapturedArgCount() { jaroslav@1646: return capturedArgs.length; jaroslav@1646: } jaroslav@1646: jaroslav@1646: /** jaroslav@1646: * Get a dynamic argument to the lambda capture site. jaroslav@1646: * @param i the argument to capture jaroslav@1646: * @return a dynamic argument to the lambda capture site jaroslav@1646: */ jaroslav@1646: public Object getCapturedArg(int i) { jaroslav@1646: return capturedArgs[i]; jaroslav@1646: } jaroslav@1646: jaroslav@1646: private Object readResolve() throws ReflectiveOperationException { jaroslav@1646: try { jaroslav@1646: Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction() { jaroslav@1646: @Override jaroslav@1646: public Method run() throws Exception { jaroslav@1646: Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); jaroslav@1646: m.setAccessible(true); jaroslav@1646: return m; jaroslav@1646: } jaroslav@1646: }); jaroslav@1646: jaroslav@1646: return deserialize.invoke(null, this); jaroslav@1646: } jaroslav@1646: catch (PrivilegedActionException e) { jaroslav@1646: Exception cause = e.getException(); jaroslav@1646: if (cause instanceof ReflectiveOperationException) jaroslav@1646: throw (ReflectiveOperationException) cause; jaroslav@1646: else if (cause instanceof RuntimeException) jaroslav@1646: throw (RuntimeException) cause; jaroslav@1646: else jaroslav@1646: throw new RuntimeException("Exception in SerializedLambda.readResolve", e); jaroslav@1646: } jaroslav@1646: } jaroslav@1646: jaroslav@1646: @Override jaroslav@1646: public String toString() { jaroslav@1646: String implKind=MethodHandleInfo.referenceKindToString(implMethodKind); jaroslav@1646: return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + jaroslav@1646: "%s=%s %s.%s:%s, %s=%s, %s=%d]", jaroslav@1646: "capturingClass", capturingClass, jaroslav@1646: "functionalInterfaceMethod", functionalInterfaceClass, jaroslav@1646: functionalInterfaceMethodName, jaroslav@1646: functionalInterfaceMethodSignature, jaroslav@1646: "implementation", jaroslav@1646: implKind, jaroslav@1646: implClass, implMethodName, implMethodSignature, jaroslav@1646: "instantiatedMethodType", instantiatedMethodType, jaroslav@1646: "numCaptured", capturedArgs.length); jaroslav@1646: } jaroslav@1646: }