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 */ 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 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 */ 58 public final class SerializedLambda implements Serializable { 59 private static final long serialVersionUID = 8025925345765570181L; 60 private final Class<?> capturingClass; 61 private final String functionalInterfaceClass; 62 private final String functionalInterfaceMethodName; 63 private final String functionalInterfaceMethodSignature; 64 private final String implClass; 65 private final String implMethodName; 66 private final String implMethodSignature; 67 private final int implMethodKind; 68 private final String instantiatedMethodType; 69 private final Object[] capturedArgs; 70 71 /** 72 * Create a {@code SerializedLambda} from the low-level information present 73 * at the lambda factory site. 74 * 75 * @param capturingClass The class in which the lambda expression appears 76 * @param functionalInterfaceClass Name, in slash-delimited form, of static 77 * type of the returned lambda object 78 * @param functionalInterfaceMethodName Name of the functional interface 79 * method for the present at the 80 * lambda factory site 81 * @param functionalInterfaceMethodSignature Signature of the functional 82 * interface method present at 83 * the lambda factory site 84 * @param implMethodKind Method handle kind for the implementation method 85 * @param implClass Name, in slash-delimited form, for the class holding 86 * the implementation method 87 * @param implMethodName Name of the implementation method 88 * @param implMethodSignature Signature of the implementation method 89 * @param instantiatedMethodType The signature of the primary functional 90 * interface method after type variables 91 * are substituted with their instantiation 92 * from the capture site 93 * @param capturedArgs The dynamic arguments to the lambda factory site, 94 * which represent variables captured by 95 * the lambda 96 */ 97 public SerializedLambda(Class<?> capturingClass, 98 String functionalInterfaceClass, 99 String functionalInterfaceMethodName, 100 String functionalInterfaceMethodSignature, 101 int implMethodKind, 102 String implClass, 103 String implMethodName, 104 String implMethodSignature, 105 String instantiatedMethodType, 106 Object[] capturedArgs) { 107 this.capturingClass = capturingClass; 108 this.functionalInterfaceClass = functionalInterfaceClass; 109 this.functionalInterfaceMethodName = functionalInterfaceMethodName; 110 this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; 111 this.implMethodKind = implMethodKind; 112 this.implClass = implClass; 113 this.implMethodName = implMethodName; 114 this.implMethodSignature = implMethodSignature; 115 this.instantiatedMethodType = instantiatedMethodType; 116 this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); 117 } 118 119 /** 120 * Get the name of the class that captured this lambda. 121 * @return the name of the class that captured this lambda 122 */ 123 public String getCapturingClass() { 124 return capturingClass.getName().replace('.', '/'); 125 } 126 127 /** 128 * Get the name of the invoked type to which this 129 * lambda has been converted 130 * @return the name of the functional interface class to which 131 * this lambda has been converted 132 */ 133 public String getFunctionalInterfaceClass() { 134 return functionalInterfaceClass; 135 } 136 137 /** 138 * Get the name of the primary method for the functional interface 139 * to which this lambda has been converted. 140 * @return the name of the primary methods of the functional interface 141 */ 142 public String getFunctionalInterfaceMethodName() { 143 return functionalInterfaceMethodName; 144 } 145 146 /** 147 * Get the signature of the primary method for the functional 148 * interface to which this lambda has been converted. 149 * @return the signature of the primary method of the functional 150 * interface 151 */ 152 public String getFunctionalInterfaceMethodSignature() { 153 return functionalInterfaceMethodSignature; 154 } 155 156 /** 157 * Get the name of the class containing the implementation 158 * method. 159 * @return the name of the class containing the implementation 160 * method 161 */ 162 public String getImplClass() { 163 return implClass; 164 } 165 166 /** 167 * Get the name of the implementation method. 168 * @return the name of the implementation method 169 */ 170 public String getImplMethodName() { 171 return implMethodName; 172 } 173 174 /** 175 * Get the signature of the implementation method. 176 * @return the signature of the implementation method 177 */ 178 public String getImplMethodSignature() { 179 return implMethodSignature; 180 } 181 182 /** 183 * Get the method handle kind (see {@link MethodHandleInfo}) of 184 * the implementation method. 185 * @return the method handle kind of the implementation method 186 */ 187 public int getImplMethodKind() { 188 return implMethodKind; 189 } 190 191 /** 192 * Get the signature of the primary functional interface method 193 * after type variables are substituted with their instantiation 194 * from the capture site. 195 * @return the signature of the primary functional interface method 196 * after type variable processing 197 */ 198 public final String getInstantiatedMethodType() { 199 return instantiatedMethodType; 200 } 201 202 /** 203 * Get the count of dynamic arguments to the lambda capture site. 204 * @return the count of dynamic arguments to the lambda capture site 205 */ 206 public int getCapturedArgCount() { 207 return capturedArgs.length; 208 } 209 210 /** 211 * Get a dynamic argument to the lambda capture site. 212 * @param i the argument to capture 213 * @return a dynamic argument to the lambda capture site 214 */ 215 public Object getCapturedArg(int i) { 216 return capturedArgs[i]; 217 } 218 219 private Object readResolve() throws ReflectiveOperationException { 220 try { 221 Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<>() { 222 @Override 223 public Method run() throws Exception { 224 Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); 225 m.setAccessible(true); 226 return m; 227 } 228 }); 229 230 return deserialize.invoke(null, this); 231 } 232 catch (PrivilegedActionException e) { 233 Exception cause = e.getException(); 234 if (cause instanceof ReflectiveOperationException) 235 throw (ReflectiveOperationException) cause; 236 else if (cause instanceof RuntimeException) 237 throw (RuntimeException) cause; 238 else 239 throw new RuntimeException("Exception in SerializedLambda.readResolve", e); 240 } 241 } 242 243 @Override 244 public String toString() { 245 String implKind=MethodHandleInfo.referenceKindToString(implMethodKind); 246 return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + 247 "%s=%s %s.%s:%s, %s=%s, %s=%d]", 248 "capturingClass", capturingClass, 249 "functionalInterfaceMethod", functionalInterfaceClass, 250 functionalInterfaceMethodName, 251 functionalInterfaceMethodSignature, 252 "implementation", 253 implKind, 254 implClass, implMethodName, implMethodSignature, 255 "instantiatedMethodType", instantiatedMethodType, 256 "numCaptured", capturedArgs.length); 257 } 258 }