      1 /*
      2  * Copyright (c) 2012, 2020, 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     /**
     71      * The capturing class.
     72      */
     73     private final Class<?> capturingClass;
     74     /**
     75      * The functional interface class.
     76      */
     77     private final String functionalInterfaceClass;
     78     /**
     79      * The functional interface method name.
     80      */
     81     private final String functionalInterfaceMethodName;
     82     /**
     83      * The functional interface method signature.
     84      */
     85     private final String functionalInterfaceMethodSignature;
     86     /**
     87      * The implementation class.
     88      */
     89     private final String implClass;
     90     /**
     91      * The implementation method name.
     92      */
     93     private final String implMethodName;
     94     /**
     95      * The implementation method signature.
     96      */
     97     private final String implMethodSignature;
     98     /**
     99      * The implementation method kind.
    100      */
    101     private final int implMethodKind;
    102     /**
    103      * The instantiated method type.
    104      */
    105     private final String instantiatedMethodType;
    106     /**
    107      * The captured arguments.
    108      */
    109     @SuppressWarnings("serial") // Not statically typed as Serializable
    110     private final Object[] capturedArgs;
    111
    112     /**
    113      * Create a {@code SerializedLambda} from the low-level information present
    114      * at the lambda factory site.
    115      *
    116      * @param capturingClass The class in which the lambda expression appears
    117      * @param functionalInterfaceClass Name, in slash-delimited form, of static
    118      *                                 type of the returned lambda object
    119      * @param functionalInterfaceMethodName Name of the functional interface
    120      *                                      method for the present at the
    121      *                                      lambda factory site
    122      * @param functionalInterfaceMethodSignature Signature of the functional
    123      *                                           interface method present at
    124      *                                           the lambda factory site
    125      * @param implMethodKind Method handle kind for the implementation method
    126      * @param implClass Name, in slash-delimited form, for the class holding
    127      *                  the implementation method
    128      * @param implMethodName Name of the implementation method
    129      * @param implMethodSignature Signature of the implementation method
    130      * @param instantiatedMethodType The signature of the primary functional
    131      *                               interface method after type variables
    132      *                               are substituted with their instantiation
    133      *                               from the capture site
    134      * @param capturedArgs The dynamic arguments to the lambda factory site,
    135      *                     which represent variables captured by
    136      *                     the lambda
    137      */
    138     public SerializedLambda(Class<?> capturingClass,
    139                             String functionalInterfaceClass,
    140                             String functionalInterfaceMethodName,
    141                             String functionalInterfaceMethodSignature,
    142                             int implMethodKind,
    143                             String implClass,
    144                             String implMethodName,
    145                             String implMethodSignature,
    146                             String instantiatedMethodType,
    147                             Object[] capturedArgs) {
    148         this.capturingClass = capturingClass;
    149         this.functionalInterfaceClass = functionalInterfaceClass;
    150         this.functionalInterfaceMethodName = functionalInterfaceMethodName;
    151         this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
    152         this.implMethodKind = implMethodKind;
    153         this.implClass = implClass;
    154         this.implMethodName = implMethodName;
    155         this.implMethodSignature = implMethodSignature;
    156         this.instantiatedMethodType = instantiatedMethodType;
    157         this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
    158     }
    159
    160     /**
    161      * Get the name of the class that captured this lambda.
    162      * @return the name of the class that captured this lambda
    163      */
    164     public String getCapturingClass() {
    165         return capturingClass.getName().replace('.', '/');
    166     }
    167
    168     /**
    169      * Get the name of the invoked type to which this
    170      * lambda has been converted
    171      * @return the name of the functional interface class to which
    172      * this lambda has been converted
    173      */
    174     public String getFunctionalInterfaceClass() {
    175         return functionalInterfaceClass;
    176     }
    177
    178     /**
    179      * Get the name of the primary method for the functional interface
    180      * to which this lambda has been converted.
    181      * @return the name of the primary methods of the functional interface
    182      */
    183     public String getFunctionalInterfaceMethodName() {
    184         return functionalInterfaceMethodName;
    185     }
    186
    187     /**
    188      * Get the signature of the primary method for the functional
    189      * interface to which this lambda has been converted.
    190      * @return the signature of the primary method of the functional
    191      * interface
    192      */
    193     public String getFunctionalInterfaceMethodSignature() {
    194         return functionalInterfaceMethodSignature;
    195     }
    196
    197     /**
    198      * Get the name of the class containing the implementation
    199      * method.
    200      * @return the name of the class containing the implementation
    201      * method
    202      */
    203     public String getImplClass() {
    204         return implClass;
    205     }
    206
    207     /**
    208      * Get the name of the implementation method.
    209      * @return the name of the implementation method
    210      */
    211     public String getImplMethodName() {
    212         return implMethodName;
    213     }
    214
    215     /**
    216      * Get the signature of the implementation method.
    217      * @return the signature of the implementation method
    218      */
    219     public String getImplMethodSignature() {
    220         return implMethodSignature;
    221     }
    222
    223     /**
    224      * Get the method handle kind (see {@link MethodHandleInfo}) of
    225      * the implementation method.
    226      * @return the method handle kind of the implementation method
    227      */
    228     public int getImplMethodKind() {
    229         return implMethodKind;
    230     }
    231
    232     /**
    233      * Get the signature of the primary functional interface method
    234      * after type variables are substituted with their instantiation
    235      * from the capture site.
    236      * @return the signature of the primary functional interface method
    237      * after type variable processing
    238      */
    239     public final String getInstantiatedMethodType() {
    240         return instantiatedMethodType;
    241     }
    242
    243     /**
    244      * Get the count of dynamic arguments to the lambda capture site.
    245      * @return the count of dynamic arguments to the lambda capture site
    246      */
    247     public int getCapturedArgCount() {
    248         return capturedArgs.length;
    249     }
    250
    251     /**
    252      * Get a dynamic argument to the lambda capture site.
    253      * @param i the argument to capture
    254      * @return a dynamic argument to the lambda capture site
    255      */
    256     public Object getCapturedArg(int i) {
    257         return capturedArgs[i];
    258     }
    259
    260     /**
    261      * Resolve a {@code SerializedLambda} to an object.
    262      * @return a SerializedLambda
    263      * @throws ObjectStreamException if the object is not valid
    264      */
    265     @java.io.Serial
    266     private Object readResolve() throws ObjectStreamException {
    267         try {
    268             Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<>() {
    269                 @Override
    270                 public Method run() throws Exception {
    271                     Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
    272                     m.setAccessible(true);
    273                     return m;
    274                 }
    275             });
    276
    277             return deserialize.invoke(null, this);
    278         } catch (ReflectiveOperationException roe) {
    279             ObjectStreamException ose = new InvalidObjectException("ReflectiveOperationException during deserialization");
    280             ose.initCause(roe);
    281             throw ose;
    282         } catch (PrivilegedActionException e) {
    283             Exception cause = e.getException();
    284             if (cause instanceof RuntimeException)
    285                 throw (RuntimeException) cause;
    286             else
    287                 throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
    288         }
    289     }
    290
    291     @Override
    292     public String toString() {
    293         String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
    294         return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
    295                              "%s=%s %s.%s:%s, %s=%s, %s=%d]",
    296                              "capturingClass", capturingClass,
    297                              "functionalInterfaceMethod", functionalInterfaceClass,
    298                                functionalInterfaceMethodName,
    299                                functionalInterfaceMethodSignature,
    300                              "implementation",
    301                                implKind,
    302                                implClass, implMethodName, implMethodSignature,
    303                              "instantiatedMethodType", instantiatedMethodType,
    304                              "numCaptured", capturedArgs.length);
    305     }
    306 }