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 }