1/* 2 * Copyright (c) 2012, 2013, 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 */ 25package java.lang.invoke; 26 27import java.io.Serializable; 28import java.lang.reflect.Method; 29import java.security.AccessController; 30import java.security.PrivilegedActionException; 31import java.security.PrivilegedExceptionAction; 32import java.util.Objects; 33 34/** 35 * Serialized form of a lambda expression. The properties of this class 36 * represent the information that is present at the lambda factory site, including 37 * static metafactory arguments such as the identity of the primary functional 38 * interface method and the identity of the implementation method, as well as 39 * dynamic metafactory arguments such as values captured from the lexical scope 40 * at the time of lambda capture. 41 * 42 * <p>Implementors of serializable lambdas, such as compilers or language 43 * runtime libraries, are expected to ensure that instances deserialize properly. 44 * One means to do so is to ensure that the {@code writeReplace} method returns 45 * an instance of {@code SerializedLambda}, rather than allowing default 46 * serialization to proceed. 47 * 48 * <p>{@code SerializedLambda} has a {@code readResolve} method that looks for 49 * a (possibly private) static method called 50 * {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes 51 * that with itself as the first argument, and returns the result. Lambda classes 52 * implementing {@code $deserializeLambda$} are responsible for validating 53 * that the properties of the {@code SerializedLambda} are consistent with a 54 * lambda actually captured by that class. 55 * 56 * @see LambdaMetafactory 57 * @since 1.8 58 */ 59public final class SerializedLambda implements Serializable { 60 private static final long serialVersionUID = 8025925345765570181L; 61 private final Class<?> capturingClass; 62 private final String functionalInterfaceClass; 63 private final String functionalInterfaceMethodName; 64 private final String functionalInterfaceMethodSignature; 65 private final String implClass; 66 private final String implMethodName; 67 private final String implMethodSignature; 68 private final int implMethodKind; 69 private final String instantiatedMethodType; 70 private final Object[] capturedArgs; 71 72 /** 73 * Create a {@code SerializedLambda} from the low-level information present 74 * at the lambda factory site. 75 * 76 * @param capturingClass The class in which the lambda expression appears 77 * @param functionalInterfaceClass Name, in slash-delimited form, of static 78 * type of the returned lambda object 79 * @param functionalInterfaceMethodName Name of the functional interface 80 * method for the present at the 81 * lambda factory site 82 * @param functionalInterfaceMethodSignature Signature of the functional 83 * interface method present at 84 * the lambda factory site 85 * @param implMethodKind Method handle kind for the implementation method 86 * @param implClass Name, in slash-delimited form, for the class holding 87 * the implementation method 88 * @param implMethodName Name of the implementation method 89 * @param implMethodSignature Signature of the implementation method 90 * @param instantiatedMethodType The signature of the primary functional 91 * interface method after type variables 92 * are substituted with their instantiation 93 * from the capture site 94 * @param capturedArgs The dynamic arguments to the lambda factory site, 95 * which represent variables captured by 96 * the lambda 97 */ 98 public SerializedLambda(Class<?> capturingClass, 99 String functionalInterfaceClass, 100 String functionalInterfaceMethodName, 101 String functionalInterfaceMethodSignature, 102 int implMethodKind, 103 String implClass, 104 String implMethodName, 105 String implMethodSignature, 106 String instantiatedMethodType, 107 Object[] capturedArgs) { 108 this.capturingClass = capturingClass; 109 this.functionalInterfaceClass = functionalInterfaceClass; 110 this.functionalInterfaceMethodName = functionalInterfaceMethodName; 111 this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; 112 this.implMethodKind = implMethodKind; 113 this.implClass = implClass; 114 this.implMethodName = implMethodName; 115 this.implMethodSignature = implMethodSignature; 116 this.instantiatedMethodType = instantiatedMethodType; 117 this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); 118 } 119 120 /** 121 * Get the name of the class that captured this lambda. 122 * @return the name of the class that captured this lambda 123 */ 124 public String getCapturingClass() { 125 return capturingClass.getName().replace('.', '/'); 126 } 127 128 /** 129 * Get the name of the invoked type to which this 130 * lambda has been converted 131 * @return the name of the functional interface class to which 132 * this lambda has been converted 133 */ 134 public String getFunctionalInterfaceClass() { 135 return functionalInterfaceClass; 136 } 137 138 /** 139 * Get the name of the primary method for the functional interface 140 * to which this lambda has been converted. 141 * @return the name of the primary methods of the functional interface 142 */ 143 public String getFunctionalInterfaceMethodName() { 144 return functionalInterfaceMethodName; 145 } 146 147 /** 148 * Get the signature of the primary method for the functional 149 * interface to which this lambda has been converted. 150 * @return the signature of the primary method of the functional 151 * interface 152 */ 153 public String getFunctionalInterfaceMethodSignature() { 154 return functionalInterfaceMethodSignature; 155 } 156 157 /** 158 * Get the name of the class containing the implementation 159 * method. 160 * @return the name of the class containing the implementation 161 * method 162 */ 163 public String getImplClass() { 164 return implClass; 165 } 166 167 /** 168 * Get the name of the implementation method. 169 * @return the name of the implementation method 170 */ 171 public String getImplMethodName() { 172 return implMethodName; 173 } 174 175 /** 176 * Get the signature of the implementation method. 177 * @return the signature of the implementation method 178 */ 179 public String getImplMethodSignature() { 180 return implMethodSignature; 181 } 182 183 /** 184 * Get the method handle kind (see {@link MethodHandleInfo}) of 185 * the implementation method. 186 * @return the method handle kind of the implementation method 187 */ 188 public int getImplMethodKind() { 189 return implMethodKind; 190 } 191 192 /** 193 * Get the signature of the primary functional interface method 194 * after type variables are substituted with their instantiation 195 * from the capture site. 196 * @return the signature of the primary functional interface method 197 * after type variable processing 198 */ 199 public final String getInstantiatedMethodType() { 200 return instantiatedMethodType; 201 } 202 203 /** 204 * Get the count of dynamic arguments to the lambda capture site. 205 * @return the count of dynamic arguments to the lambda capture site 206 */ 207 public int getCapturedArgCount() { 208 return capturedArgs.length; 209 } 210 211 /** 212 * Get a dynamic argument to the lambda capture site. 213 * @param i the argument to capture 214 * @return a dynamic argument to the lambda capture site 215 */ 216 public Object getCapturedArg(int i) { 217 return capturedArgs[i]; 218 } 219 220 private Object readResolve() throws ReflectiveOperationException { 221 try { 222 Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<>() { 223 @Override 224 public Method run() throws Exception { 225 Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); 226 m.setAccessible(true); 227 return m; 228 } 229 }); 230 231 return deserialize.invoke(null, this); 232 } 233 catch (PrivilegedActionException e) { 234 Exception cause = e.getException(); 235 if (cause instanceof ReflectiveOperationException) 236 throw (ReflectiveOperationException) cause; 237 else if (cause instanceof RuntimeException) 238 throw (RuntimeException) cause; 239 else 240 throw new RuntimeException("Exception in SerializedLambda.readResolve", e); 241 } 242 } 243 244 @Override 245 public String toString() { 246 String implKind=MethodHandleInfo.referenceKindToString(implMethodKind); 247 return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + 248 "%s=%s %s.%s:%s, %s=%s, %s=%d]", 249 "capturingClass", capturingClass, 250 "functionalInterfaceMethod", functionalInterfaceClass, 251 functionalInterfaceMethodName, 252 functionalInterfaceMethodSignature, 253 "implementation", 254 implKind, 255 implClass, implMethodName, implMethodSignature, 256 "instantiatedMethodType", instantiatedMethodType, 257 "numCaptured", capturedArgs.length); 258 } 259} 260