rt/emul/compact/src/main/java/java/lang/invoke/SerializedLambda.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 14 Sep 2014 19:27:44 +0200
changeset 1692 2f800fdc371e
permissions -rw-r--r--
Adding necessary fake classes to allow Javac to compile lamda expressions against our emulation library.
jaroslav@1692
     1
/*
jaroslav@1692
     2
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
jaroslav@1692
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1692
     4
 *
jaroslav@1692
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1692
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1692
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1692
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1692
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1692
    10
 *
jaroslav@1692
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1692
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1692
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1692
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1692
    15
 * accompanied this code).
jaroslav@1692
    16
 *
jaroslav@1692
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@1692
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1692
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1692
    20
 *
jaroslav@1692
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1692
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1692
    23
 * questions.
jaroslav@1692
    24
 */
jaroslav@1692
    25
package java.lang.invoke;
jaroslav@1692
    26
jaroslav@1692
    27
import java.io.Serializable;
jaroslav@1692
    28
import java.lang.reflect.Method;
jaroslav@1692
    29
import java.security.AccessController;
jaroslav@1692
    30
import java.security.PrivilegedActionException;
jaroslav@1692
    31
import java.security.PrivilegedExceptionAction;
jaroslav@1692
    32
import java.util.Objects;
jaroslav@1692
    33
jaroslav@1692
    34
/**
jaroslav@1692
    35
 * Serialized form of a lambda expression.  The properties of this class
jaroslav@1692
    36
 * represent the information that is present at the lambda factory site, including
jaroslav@1692
    37
 * static metafactory arguments such as the identity of the primary functional
jaroslav@1692
    38
 * interface method and the identity of the implementation method, as well as
jaroslav@1692
    39
 * dynamic metafactory arguments such as values captured from the lexical scope
jaroslav@1692
    40
 * at the time of lambda capture.
jaroslav@1692
    41
 *
jaroslav@1692
    42
 * <p>Implementors of serializable lambdas, such as compilers or language
jaroslav@1692
    43
 * runtime libraries, are expected to ensure that instances deserialize properly.
jaroslav@1692
    44
 * One means to do so is to ensure that the {@code writeReplace} method returns
jaroslav@1692
    45
 * an instance of {@code SerializedLambda}, rather than allowing default
jaroslav@1692
    46
 * serialization to proceed.
jaroslav@1692
    47
 *
jaroslav@1692
    48
 * <p>{@code SerializedLambda} has a {@code readResolve} method that looks for
jaroslav@1692
    49
 * a (possibly private) static method called
jaroslav@1692
    50
 * {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes
jaroslav@1692
    51
 * that with itself as the first argument, and returns the result.  Lambda classes
jaroslav@1692
    52
 * implementing {@code $deserializeLambda$} are responsible for validating
jaroslav@1692
    53
 * that the properties of the {@code SerializedLambda} are consistent with a
jaroslav@1692
    54
 * lambda actually captured by that class.
jaroslav@1692
    55
 *
jaroslav@1692
    56
 * @see LambdaMetafactory
jaroslav@1692
    57
 */
jaroslav@1692
    58
public final class SerializedLambda implements Serializable {
jaroslav@1692
    59
    private static final long serialVersionUID = 8025925345765570181L;
jaroslav@1692
    60
    private final Class<?> capturingClass;
jaroslav@1692
    61
    private final String functionalInterfaceClass;
jaroslav@1692
    62
    private final String functionalInterfaceMethodName;
jaroslav@1692
    63
    private final String functionalInterfaceMethodSignature;
jaroslav@1692
    64
    private final String implClass;
jaroslav@1692
    65
    private final String implMethodName;
jaroslav@1692
    66
    private final String implMethodSignature;
jaroslav@1692
    67
    private final int implMethodKind;
jaroslav@1692
    68
    private final String instantiatedMethodType;
jaroslav@1692
    69
    private final Object[] capturedArgs;
jaroslav@1692
    70
jaroslav@1692
    71
    /**
jaroslav@1692
    72
     * Create a {@code SerializedLambda} from the low-level information present
jaroslav@1692
    73
     * at the lambda factory site.
jaroslav@1692
    74
     *
jaroslav@1692
    75
     * @param capturingClass The class in which the lambda expression appears
jaroslav@1692
    76
     * @param functionalInterfaceClass Name, in slash-delimited form, of static
jaroslav@1692
    77
     *                                 type of the returned lambda object
jaroslav@1692
    78
     * @param functionalInterfaceMethodName Name of the functional interface
jaroslav@1692
    79
     *                                      method for the present at the
jaroslav@1692
    80
     *                                      lambda factory site
jaroslav@1692
    81
     * @param functionalInterfaceMethodSignature Signature of the functional
jaroslav@1692
    82
     *                                           interface method present at
jaroslav@1692
    83
     *                                           the lambda factory site
jaroslav@1692
    84
     * @param implMethodKind Method handle kind for the implementation method
jaroslav@1692
    85
     * @param implClass Name, in slash-delimited form, for the class holding
jaroslav@1692
    86
     *                  the implementation method
jaroslav@1692
    87
     * @param implMethodName Name of the implementation method
jaroslav@1692
    88
     * @param implMethodSignature Signature of the implementation method
jaroslav@1692
    89
     * @param instantiatedMethodType The signature of the primary functional
jaroslav@1692
    90
     *                               interface method after type variables
jaroslav@1692
    91
     *                               are substituted with their instantiation
jaroslav@1692
    92
     *                               from the capture site
jaroslav@1692
    93
     * @param capturedArgs The dynamic arguments to the lambda factory site,
jaroslav@1692
    94
     *                     which represent variables captured by
jaroslav@1692
    95
     *                     the lambda
jaroslav@1692
    96
     */
jaroslav@1692
    97
    public SerializedLambda(Class<?> capturingClass,
jaroslav@1692
    98
                            String functionalInterfaceClass,
jaroslav@1692
    99
                            String functionalInterfaceMethodName,
jaroslav@1692
   100
                            String functionalInterfaceMethodSignature,
jaroslav@1692
   101
                            int implMethodKind,
jaroslav@1692
   102
                            String implClass,
jaroslav@1692
   103
                            String implMethodName,
jaroslav@1692
   104
                            String implMethodSignature,
jaroslav@1692
   105
                            String instantiatedMethodType,
jaroslav@1692
   106
                            Object[] capturedArgs) {
jaroslav@1692
   107
        this.capturingClass = capturingClass;
jaroslav@1692
   108
        this.functionalInterfaceClass = functionalInterfaceClass;
jaroslav@1692
   109
        this.functionalInterfaceMethodName = functionalInterfaceMethodName;
jaroslav@1692
   110
        this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
jaroslav@1692
   111
        this.implMethodKind = implMethodKind;
jaroslav@1692
   112
        this.implClass = implClass;
jaroslav@1692
   113
        this.implMethodName = implMethodName;
jaroslav@1692
   114
        this.implMethodSignature = implMethodSignature;
jaroslav@1692
   115
        this.instantiatedMethodType = instantiatedMethodType;
jaroslav@1692
   116
        this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
jaroslav@1692
   117
    }
jaroslav@1692
   118
jaroslav@1692
   119
    /**
jaroslav@1692
   120
     * Get the name of the class that captured this lambda.
jaroslav@1692
   121
     * @return the name of the class that captured this lambda
jaroslav@1692
   122
     */
jaroslav@1692
   123
    public String getCapturingClass() {
jaroslav@1692
   124
        return capturingClass.getName().replace('.', '/');
jaroslav@1692
   125
    }
jaroslav@1692
   126
jaroslav@1692
   127
    /**
jaroslav@1692
   128
     * Get the name of the invoked type to which this
jaroslav@1692
   129
     * lambda has been converted
jaroslav@1692
   130
     * @return the name of the functional interface class to which
jaroslav@1692
   131
     * this lambda has been converted
jaroslav@1692
   132
     */
jaroslav@1692
   133
    public String getFunctionalInterfaceClass() {
jaroslav@1692
   134
        return functionalInterfaceClass;
jaroslav@1692
   135
    }
jaroslav@1692
   136
jaroslav@1692
   137
    /**
jaroslav@1692
   138
     * Get the name of the primary method for the functional interface
jaroslav@1692
   139
     * to which this lambda has been converted.
jaroslav@1692
   140
     * @return the name of the primary methods of the functional interface
jaroslav@1692
   141
     */
jaroslav@1692
   142
    public String getFunctionalInterfaceMethodName() {
jaroslav@1692
   143
        return functionalInterfaceMethodName;
jaroslav@1692
   144
    }
jaroslav@1692
   145
jaroslav@1692
   146
    /**
jaroslav@1692
   147
     * Get the signature of the primary method for the functional
jaroslav@1692
   148
     * interface to which this lambda has been converted.
jaroslav@1692
   149
     * @return the signature of the primary method of the functional
jaroslav@1692
   150
     * interface
jaroslav@1692
   151
     */
jaroslav@1692
   152
    public String getFunctionalInterfaceMethodSignature() {
jaroslav@1692
   153
        return functionalInterfaceMethodSignature;
jaroslav@1692
   154
    }
jaroslav@1692
   155
jaroslav@1692
   156
    /**
jaroslav@1692
   157
     * Get the name of the class containing the implementation
jaroslav@1692
   158
     * method.
jaroslav@1692
   159
     * @return the name of the class containing the implementation
jaroslav@1692
   160
     * method
jaroslav@1692
   161
     */
jaroslav@1692
   162
    public String getImplClass() {
jaroslav@1692
   163
        return implClass;
jaroslav@1692
   164
    }
jaroslav@1692
   165
jaroslav@1692
   166
    /**
jaroslav@1692
   167
     * Get the name of the implementation method.
jaroslav@1692
   168
     * @return the name of the implementation method
jaroslav@1692
   169
     */
jaroslav@1692
   170
    public String getImplMethodName() {
jaroslav@1692
   171
        return implMethodName;
jaroslav@1692
   172
    }
jaroslav@1692
   173
jaroslav@1692
   174
    /**
jaroslav@1692
   175
     * Get the signature of the implementation method.
jaroslav@1692
   176
     * @return the signature of the implementation method
jaroslav@1692
   177
     */
jaroslav@1692
   178
    public String getImplMethodSignature() {
jaroslav@1692
   179
        return implMethodSignature;
jaroslav@1692
   180
    }
jaroslav@1692
   181
jaroslav@1692
   182
    /**
jaroslav@1692
   183
     * Get the method handle kind (see {@link MethodHandleInfo}) of
jaroslav@1692
   184
     * the implementation method.
jaroslav@1692
   185
     * @return the method handle kind of the implementation method
jaroslav@1692
   186
     */
jaroslav@1692
   187
    public int getImplMethodKind() {
jaroslav@1692
   188
        return implMethodKind;
jaroslav@1692
   189
    }
jaroslav@1692
   190
jaroslav@1692
   191
    /**
jaroslav@1692
   192
     * Get the signature of the primary functional interface method
jaroslav@1692
   193
     * after type variables are substituted with their instantiation
jaroslav@1692
   194
     * from the capture site.
jaroslav@1692
   195
     * @return the signature of the primary functional interface method
jaroslav@1692
   196
     * after type variable processing
jaroslav@1692
   197
     */
jaroslav@1692
   198
    public final String getInstantiatedMethodType() {
jaroslav@1692
   199
        return instantiatedMethodType;
jaroslav@1692
   200
    }
jaroslav@1692
   201
jaroslav@1692
   202
    /**
jaroslav@1692
   203
     * Get the count of dynamic arguments to the lambda capture site.
jaroslav@1692
   204
     * @return the count of dynamic arguments to the lambda capture site
jaroslav@1692
   205
     */
jaroslav@1692
   206
    public int getCapturedArgCount() {
jaroslav@1692
   207
        return capturedArgs.length;
jaroslav@1692
   208
    }
jaroslav@1692
   209
jaroslav@1692
   210
    /**
jaroslav@1692
   211
     * Get a dynamic argument to the lambda capture site.
jaroslav@1692
   212
     * @param i the argument to capture
jaroslav@1692
   213
     * @return a dynamic argument to the lambda capture site
jaroslav@1692
   214
     */
jaroslav@1692
   215
    public Object getCapturedArg(int i) {
jaroslav@1692
   216
        return capturedArgs[i];
jaroslav@1692
   217
    }
jaroslav@1692
   218
jaroslav@1692
   219
    private Object readResolve() throws ReflectiveOperationException {
jaroslav@1692
   220
        try {
jaroslav@1692
   221
            Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
jaroslav@1692
   222
                @Override
jaroslav@1692
   223
                public Method run() throws Exception {
jaroslav@1692
   224
                    Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
jaroslav@1692
   225
                    m.setAccessible(true);
jaroslav@1692
   226
                    return m;
jaroslav@1692
   227
                }
jaroslav@1692
   228
            });
jaroslav@1692
   229
jaroslav@1692
   230
            return deserialize.invoke(null, this);
jaroslav@1692
   231
        }
jaroslav@1692
   232
        catch (PrivilegedActionException e) {
jaroslav@1692
   233
            Exception cause = e.getException();
jaroslav@1692
   234
            if (cause instanceof ReflectiveOperationException)
jaroslav@1692
   235
                throw (ReflectiveOperationException) cause;
jaroslav@1692
   236
            else if (cause instanceof RuntimeException)
jaroslav@1692
   237
                throw (RuntimeException) cause;
jaroslav@1692
   238
            else
jaroslav@1692
   239
                throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
jaroslav@1692
   240
        }
jaroslav@1692
   241
    }
jaroslav@1692
   242
jaroslav@1692
   243
    @Override
jaroslav@1692
   244
    public String toString() {
jaroslav@1692
   245
        return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
jaroslav@1692
   246
                             "%s=%s %s.%s:%s, %s=%s, %s=%d]",
jaroslav@1692
   247
                             "capturingClass", capturingClass,
jaroslav@1692
   248
                             "functionalInterfaceMethod", functionalInterfaceClass,
jaroslav@1692
   249
                               functionalInterfaceMethodName,
jaroslav@1692
   250
                               functionalInterfaceMethodSignature,
jaroslav@1692
   251
                             "implementation",
jaroslav@1692
   252
                               null,
jaroslav@1692
   253
                               implClass, implMethodName, implMethodSignature,
jaroslav@1692
   254
                             "instantiatedMethodType", instantiatedMethodType,
jaroslav@1692
   255
                             "numCaptured", capturedArgs.length);
jaroslav@1692
   256
    }
jaroslav@1692
   257
}