      1 /*
      2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 package java.lang.invoke;
     26
     27 import java.io.Serializable;
     28 import java.io.InvalidObjectException;
     29 import java.io.ObjectStreamException;
     30 import java.lang.reflect.Method;
     31 import java.security.AccessController;
     32 import java.security.PrivilegedActionException;
     33 import java.security.PrivilegedExceptionAction;
     34 import java.util.Objects;
     35
     36 /**
     37  * Serialized form of a lambda expression.  The properties of this class
     38  * represent the information that is present at the lambda factory site, including
     39  * static metafactory arguments such as the identity of the primary functional
     40  * interface method and the identity of the implementation method, as well as
     41  * dynamic metafactory arguments such as values captured from the lexical scope
     42  * at the time of lambda capture.
     43  *
     44  * <p>Implementors of serializable lambdas, such as compilers or language
     45  * runtime libraries, are expected to ensure that instances deserialize properly.
     46  * One means to do so is to ensure that the {@code writeReplace} method returns
     47  * an instance of {@code SerializedLambda}, rather than allowing default
     48  * serialization to proceed.
     49  *
     50  * <p>{@code SerializedLambda} has a {@code readResolve} method that looks for
     51  * a (possibly private) static method called
     52  * {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes
     53  * that with itself as the first argument, and returns the result.  Lambda classes
     54  * implementing {@code $deserializeLambda$} are responsible for validating
     55  * that the properties of the {@code SerializedLambda} are consistent with a
     56  * lambda actually captured by that class.
     57  *
     58  * <p>The identity of a function object produced by deserializing the serialized
     59  * form is unpredictable, and therefore identity-sensitive operations (such as
     60  * reference equality, object locking, and {@code System.identityHashCode()} may
     61  * produce different results in different implementations, or even upon
     62  * different deserializations in the same implementation.
     63  *
     64  * @see LambdaMetafactory
     65  * @since 1.8
     66  */
     67 public final class SerializedLambda implements Serializable {
     68     @java.io.Serial
     69     private static final long serialVersionUID = 8025925345765570181L;
     70     private final Class<?> capturingClass;
     71     private final String functionalInterfaceClass;
     72     private final String functionalInterfaceMethodName;
     73     private final String functionalInterfaceMethodSignature;
     74     private final String implClass;
     75     private final String implMethodName;
     76     private final String implMethodSignature;
     77     private final int implMethodKind;
     78     private final String instantiatedMethodType;
     79     @SuppressWarnings("serial") // Not statically typed as Serializable
     80     private final Object[] capturedArgs;
     81
     82     /**
     83      * Create a {@code SerializedLambda} from the low-level information present
     84      * at the lambda factory site.
     85      *
     86      * @param capturingClass The class in which the lambda expression appears
     87      * @param functionalInterfaceClass Name, in slash-delimited form, of static
     88      *                                 type of the returned lambda object
     89      * @param functionalInterfaceMethodName Name of the functional interface
     90      *                                      method for the present at the
     91      *                                      lambda factory site
     92      * @param functionalInterfaceMethodSignature Signature of the functional
     93      *                                           interface method present at
     94      *                                           the lambda factory site
     95      * @param implMethodKind Method handle kind for the implementation method
     96      * @param implClass Name, in slash-delimited form, for the class holding
     97      *                  the implementation method
     98      * @param implMethodName Name of the implementation method
     99      * @param implMethodSignature Signature of the implementation method
    100      * @param instantiatedMethodType The signature of the primary functional
    101      *                               interface method after type variables
    102      *                               are substituted with their instantiation
    103      *                               from the capture site
    104      * @param capturedArgs The dynamic arguments to the lambda factory site,
    105      *                     which represent variables captured by
    106      *                     the lambda
    107      */
    108     public SerializedLambda(Class<?> capturingClass,
    109                             String functionalInterfaceClass,
    110                             String functionalInterfaceMethodName,
    111                             String functionalInterfaceMethodSignature,
    112                             int implMethodKind,
    113                             String implClass,
    114                             String implMethodName,
    115                             String implMethodSignature,
    116                             String instantiatedMethodType,
    117                             Object[] capturedArgs) {
    118         this.capturingClass = capturingClass;
    119         this.functionalInterfaceClass = functionalInterfaceClass;
    120         this.functionalInterfaceMethodName = functionalInterfaceMethodName;
    121         this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
    122         this.implMethodKind = implMethodKind;
    123         this.implClass = implClass;
    124         this.implMethodName = implMethodName;
    125         this.implMethodSignature = implMethodSignature;
    126         this.instantiatedMethodType = instantiatedMethodType;
    127         this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
    128     }
    129
    130     /**
    131      * Get the name of the class that captured this lambda.
    132      * @return the name of the class that captured this lambda
    133      */
    134     public String getCapturingClass() {
    135         return capturingClass.getName().replace('.', '/');
    136     }
    137
    138     /**
    139      * Get the name of the invoked type to which this
    140      * lambda has been converted
    141      * @return the name of the functional interface class to which
    142      * this lambda has been converted
    143      */
    144     public String getFunctionalInterfaceClass() {
    145         return functionalInterfaceClass;
    146     }
    147
    148     /**
    149      * Get the name of the primary method for the functional interface
    150      * to which this lambda has been converted.
    151      * @return the name of the primary methods of the functional interface
    152      */
    153     public String getFunctionalInterfaceMethodName() {
    154         return functionalInterfaceMethodName;
    155     }
    156
    157     /**
    158      * Get the signature of the primary method for the functional
    159      * interface to which this lambda has been converted.
    160      * @return the signature of the primary method of the functional
    161      * interface
    162      */
    163     public String getFunctionalInterfaceMethodSignature() {
    164         return functionalInterfaceMethodSignature;
    165     }
    166
    167     /**
    168      * Get the name of the class containing the implementation
    169      * method.
    170      * @return the name of the class containing the implementation
    171      * method
    172      */
    173     public String getImplClass() {
    174         return implClass;
    175     }
    176
    177     /**
    178      * Get the name of the implementation method.
    179      * @return the name of the implementation method
    180      */
    181     public String getImplMethodName() {
    182         return implMethodName;
    183     }
    184
    185     /**
    186      * Get the signature of the implementation method.
    187      * @return the signature of the implementation method
    188      */
    189     public String getImplMethodSignature() {
    190         return implMethodSignature;
    191     }
    192
    193     /**
    194      * Get the method handle kind (see {@link MethodHandleInfo}) of
    195      * the implementation method.
    196      * @return the method handle kind of the implementation method
    197      */
    198     public int getImplMethodKind() {
    199         return implMethodKind;
    200     }
    201
    202     /**
    203      * Get the signature of the primary functional interface method
    204      * after type variables are substituted with their instantiation
    205      * from the capture site.
    206      * @return the signature of the primary functional interface method
    207      * after type variable processing
    208      */
    209     public final String getInstantiatedMethodType() {
    210         return instantiatedMethodType;
    211     }
    212
    213     /**
    214      * Get the count of dynamic arguments to the lambda capture site.
    215      * @return the count of dynamic arguments to the lambda capture site
    216      */
    217     public int getCapturedArgCount() {
    218         return capturedArgs.length;
    219     }
    220
    221     /**
    222      * Get a dynamic argument to the lambda capture site.
    223      * @param i the argument to capture
    224      * @return a dynamic argument to the lambda capture site
    225      */
    226     public Object getCapturedArg(int i) {
    227         return capturedArgs[i];
    228     }
    229
    230     @java.io.Serial
    231     private Object readResolve() throws ObjectStreamException {
    232         try {
    233             Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<>() {
    234                 @Override
    235                 public Method run() throws Exception {
    236                     Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
    237                     m.setAccessible(true);
    238                     return m;
    239                 }
    240             });
    241
    242             return deserialize.invoke(null, this);
    243         } catch (ReflectiveOperationException roe) {
    244             ObjectStreamException ose = new InvalidObjectException("ReflectiveOperationException during deserialization");
    245             ose.initCause(roe);
    246             throw ose;
    247         } catch (PrivilegedActionException e) {
    248             Exception cause = e.getException();
    249             if (cause instanceof RuntimeException)
    250                 throw (RuntimeException) cause;
    251             else
    252                 throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
    253         }
    254     }
    255
    256     @Override
    257     public String toString() {
    258         String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
    259         return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
    260                              "%s=%s %s.%s:%s, %s=%s, %s=%d]",
    261                              "capturingClass", capturingClass,
    262                              "functionalInterfaceMethod", functionalInterfaceClass,
    263                                functionalInterfaceMethodName,
    264                                functionalInterfaceMethodSignature,
    265                              "implementation",
    266                                implKind,
    267                                implClass, implMethodName, implMethodSignature,
    268                              "instantiatedMethodType", instantiatedMethodType,
    269                              "numCaptured", capturedArgs.length);
    270     }
    271 }