1 /*
   2  * Copyright (c) 2012, 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.lang.reflect.Method;
  29 import java.security.AccessController;
  30 import java.security.PrivilegedActionException;
  31 import java.security.PrivilegedExceptionAction;
  32 import java.util.Objects;
  33 
  34 /**
  35  * Serialized form of a lambda expression.  The properties of this class represent the information that is present
  36  * at the lambda factory site, including the identity of the primary functional interface method, the identity of the
  37  * implementation method, and any variables captured from the local environment at the time of lambda capture.
  38  *
  39  * @see LambdaMetafactory
  40  */
  41 public final class SerializedLambda implements Serializable {
  42     private static final long serialVersionUID = 8025925345765570181L;
  43     private final Class<?> capturingClass;
  44     private final String functionalInterfaceClass;
  45     private final String functionalInterfaceMethodName;
  46     private final String functionalInterfaceMethodSignature;
  47     private final int functionalInterfaceMethodKind;
  48     private final String implClass;
  49     private final String implMethodName;
  50     private final String implMethodSignature;
  51     private final int implMethodKind;
  52     private final String instantiatedMethodType;
  53     private final Object[] capturedArgs;
  54 
  55     /**
  56      * Create a {@code SerializedLambda} from the low-level information present at the lambda factory site.
  57      *
  58      * @param capturingClass The class in which the lambda expression appears
  59      * @param functionalInterfaceMethodKind Method handle kind (see {@link MethodHandleInfo}) for the
  60      *                                      functional interface method handle present at the lambda factory site
  61      * @param functionalInterfaceClass Name, in slash-delimited form, for the functional interface class present at the
  62      *                                 lambda factory site
  63      * @param functionalInterfaceMethodName Name of the primary method for the functional interface present at the
  64      *                                      lambda factory site
  65      * @param functionalInterfaceMethodSignature Signature of the primary method for the functional interface present
  66      *                                           at the lambda factory site
  67      * @param implMethodKind Method handle kind for the implementation method
  68      * @param implClass Name, in slash-delimited form, for the class holding the implementation method
  69      * @param implMethodName Name of the implementation method
  70      * @param implMethodSignature Signature of the implementation method
  71      * @param instantiatedMethodType The signature of the primary functional interface method after type variables
  72      *                               are substituted with their instantiation from the capture site
  73      * @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by
  74      *                     the lambda
  75      */
  76     public SerializedLambda(Class<?> capturingClass,
  77                             int functionalInterfaceMethodKind,
  78                             String functionalInterfaceClass,
  79                             String functionalInterfaceMethodName,
  80                             String functionalInterfaceMethodSignature,
  81                             int implMethodKind,
  82                             String implClass,
  83                             String implMethodName,
  84                             String implMethodSignature,
  85                             String instantiatedMethodType,
  86                             Object[] capturedArgs) {
  87         this.capturingClass = capturingClass;
  88         this.functionalInterfaceMethodKind = functionalInterfaceMethodKind;
  89         this.functionalInterfaceClass = functionalInterfaceClass;
  90         this.functionalInterfaceMethodName = functionalInterfaceMethodName;
  91         this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
  92         this.implMethodKind = implMethodKind;
  93         this.implClass = implClass;
  94         this.implMethodName = implMethodName;
  95         this.implMethodSignature = implMethodSignature;
  96         this.instantiatedMethodType = instantiatedMethodType;
  97         this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
  98     }
  99 
 100     /** Get the name of the class that captured this lambda */
 101     public String getCapturingClass() {
 102         return capturingClass.getName().replace('.', '/');
 103     }
 104 
 105     /** Get the name of the functional interface class to which this lambda has been converted */
 106     public String getFunctionalInterfaceClass() {
 107         return functionalInterfaceClass;
 108     }
 109 
 110     /** Get the name of the primary method for the functional interface to which this lambda has been converted */
 111     public String getFunctionalInterfaceMethodName() {
 112         return functionalInterfaceMethodName;
 113     }
 114 
 115     /** Get the signature of the primary method for the functional interface to which this lambda has been converted */
 116     public String getFunctionalInterfaceMethodSignature() {
 117         return functionalInterfaceMethodSignature;
 118     }
 119 
 120     /** Get the method handle kind (see {@link MethodHandleInfo}) of the primary method for the functional interface
 121      * to which this lambda has been converted */
 122     public int getFunctionalInterfaceMethodKind() {
 123         return functionalInterfaceMethodKind;
 124     }
 125 
 126     /** Get the name of the class containing the implementation method */
 127     public String getImplClass() {
 128         return implClass;
 129     }
 130 
 131     /** Get the name of the implementation method */
 132     public String getImplMethodName() {
 133         return implMethodName;
 134     }
 135 
 136     /** Get the signature of the implementation method */
 137     public String getImplMethodSignature() {
 138         return implMethodSignature;
 139     }
 140 
 141     /** Get the method handle kind (see {@link MethodHandleInfo}) of the implementation method */
 142     public int getImplMethodKind() {
 143         return implMethodKind;
 144     }
 145 
 146     /**
 147      * Get the signature of the primary functional interface method after type variables are substituted with
 148      * their instantiation from the capture site
 149      */
 150     public final String getInstantiatedMethodType() {
 151         return instantiatedMethodType;
 152     }
 153 
 154     /** Get the count of dynamic arguments to the lambda capture site */
 155     public int getCapturedArgCount() {
 156         return capturedArgs.length;
 157     }
 158 
 159     /** Get a dynamic argument to the lambda capture site */
 160     public Object getCapturedArg(int i) {
 161         return capturedArgs[i];
 162     }
 163 
 164     private Object readResolve() throws ReflectiveOperationException {
 165         try {
 166             Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
 167                 @Override
 168                 public Method run() throws Exception {
 169                     Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
 170                     m.setAccessible(true);
 171                     return m;
 172                 }
 173             });
 174 
 175             return deserialize.invoke(null, this);
 176         }
 177         catch (PrivilegedActionException e) {
 178             Exception cause = e.getException();
 179             if (cause instanceof ReflectiveOperationException)
 180                 throw (ReflectiveOperationException) cause;
 181             else if (cause instanceof RuntimeException)
 182                 throw (RuntimeException) cause;
 183             else
 184                 throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
 185         }
 186     }
 187 
 188     @Override
 189     public String toString() {
 190         return String.format("SerializedLambda[capturingClass=%s, functionalInterfaceMethod=%s %s.%s:%s, " +
 191                              "implementation=%s %s.%s:%s, instantiatedMethodType=%s, numCaptured=%d]",
 192                              capturingClass, MethodHandleInfo.getReferenceKindString(functionalInterfaceMethodKind),
 193                              functionalInterfaceClass, functionalInterfaceMethodName, functionalInterfaceMethodSignature,
 194                              MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName,
 195                              implMethodSignature, instantiatedMethodType, capturedArgs.length);
 196     }
 197 }