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