1 /*
   2  * Copyright (c) 2018, 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.constant;
  26 
  27 import java.lang.invoke.MethodType;
  28 import java.lang.invoke.TypeDescriptor;
  29 import java.util.List;
  30 import java.util.stream.Collectors;
  31 import java.util.stream.Stream;
  32 
  33 /**
  34  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
  35  * {@linkplain MethodType} constant.
  36  *
  37  * <p>Two {@linkplain MethodTypeDesc} objects are considered {@link Object#equals(Object)}
  38  * if they have the same arity, their return types are equal, and each pair of corresponding
  39  * parameter types are equal.
  40  *
  41  * @apiNote In the future, if the Java language permits, {@linkplain MethodTypeDesc}
  42  * may become a {@code sealed} interface, which would prohibit subclassing except
  43  * by explicitly permitted types.  Non-platform classes should not implement
  44  * {@linkplain MethodTypeDesc} directly.
  45  *
  46  * @since 12
  47  */
  48 public interface MethodTypeDesc
  49         extends ConstantDesc,
  50                 TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc> {
  51     /**
  52      * Create a {@linkplain MethodTypeDesc} given a method descriptor string
  53      *
  54      * @param descriptor a method descriptor string
  55      * @return a {@linkplain MethodTypeDesc} describing the desired method type
  56      * @throws NullPointerException if any argument is {@code null}
  57      * @throws IllegalArgumentException if the descriptor string is not a valid
  58      * method descriptor
  59      * @jvms 4.3.3 Method Descriptors
  60      */
  61     static MethodTypeDesc ofDescriptor(String descriptor) {
  62         return MethodTypeDescImpl.ofDescriptor(descriptor);
  63     }
  64 
  65     /**
  66      * Returns a {@linkplain MethodTypeDesc} given the return type and parameter
  67      * types.
  68      *
  69      * @param returnDesc a {@linkplain ClassDesc} describing the return type
  70      * @param paramDescs {@linkplain ClassDesc}s describing the argument types
  71      * @return a {@linkplain MethodTypeDesc} describing the desired method type
  72      * @throws NullPointerException if any argument is {@code null}
  73      */
  74     static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
  75         return new MethodTypeDescImpl(returnDesc, paramDescs);
  76     }
  77 
  78     /**
  79      * Get the return type of the method type described by this {@linkplain MethodTypeDesc}
  80      *
  81      * @return a {@link ClassDesc} describing the return type of the method type
  82      */
  83     ClassDesc returnType();
  84 
  85     /**
  86      * Get the number of parameters of the method type described by
  87      * this {@linkplain MethodTypeDesc}
  88      * @return the number of parameters
  89      */
  90     int parameterCount();
  91 
  92     /**
  93      * Get the parameter type of the {@code index}'th parameter of the method type
  94      * described by this {@linkplain MethodTypeDesc}
  95      *
  96      * @param index the index of the parameter to retrieve
  97      * @return a {@link ClassDesc} describing the desired parameter type
  98      * @throws IndexOutOfBoundsException if the index is outside the half-open
  99      * range {[0, parameterCount())}
 100      */
 101     ClassDesc parameterType(int index);
 102 
 103     /**
 104      * Get the parameter types as an immutable {@link List}.
 105      *
 106      * @return a {@link List} of {@link ClassDesc} describing the parameter types
 107      */
 108     List<ClassDesc> parameterList();
 109 
 110     /**
 111      * Get the parameter types as an array.
 112      *
 113      * @return an array of {@link ClassDesc} describing the parameter types
 114      */
 115     ClassDesc[] parameterArray();
 116 
 117     /**
 118      * Return a {@linkplain MethodTypeDesc} that is identical to
 119      * this one, except with the specified return type.
 120      *
 121      * @param returnType a {@link ClassDesc} describing the new return type
 122      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 123      * @throws NullPointerException if any argument is {@code null}
 124      */
 125     MethodTypeDesc changeReturnType(ClassDesc returnType);
 126 
 127     /**
 128      * Return a {@linkplain MethodTypeDesc} that is identical to this one,
 129      * except that a single parameter type has been changed to the specified type.
 130      *
 131      * @param index the index of the parameter to change
 132      * @param paramType a {@link ClassDesc} describing the new parameter type
 133      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 134      * @throws NullPointerException if any argument is {@code null}
 135      * @throws IndexOutOfBoundsException if the index is outside the half-open
 136      * range {[0, parameterCount)}
 137      */
 138     MethodTypeDesc changeParameterType(int index, ClassDesc paramType);
 139 
 140     /**
 141      * Return a {@linkplain MethodTypeDesc} that is identical to this one,
 142      * except that a range of parameter types have been removed.
 143      *
 144      * @param start the index of the first parameter to remove
 145      * @param end the index after the last parameter to remove
 146      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 147      * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
 148      * range {[0, parameterCount)}, or {@code end} is outside the closed range
 149      * {@code [0, parameterCount]}
 150      */
 151     MethodTypeDesc dropParameterTypes(int start, int end);
 152 
 153     /**
 154      * Return a {@linkplain MethodTypeDesc} that is identical to this one,
 155      * except that a range of additional parameter types have been inserted.
 156      *
 157      * @param pos the index at which to insert the first inserted parameter
 158      * @param paramTypes {@link ClassDesc}s describing the new parameter types
 159      *                   to insert
 160      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 161      * @throws NullPointerException if any argument is {@code null}
 162      * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
 163      * range {[0, parameterCount]}
 164      */
 165     MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
 166 
 167     /**
 168      * Return the method type descriptor string
 169      *
 170      * @return the method type descriptor string
 171      * @jvms 4.3.3 Method Descriptors
 172      */
 173     default String descriptorString() {
 174         return String.format("(%s)%s",
 175                              Stream.of(parameterArray())
 176                                    .map(ClassDesc::descriptorString)
 177                                    .collect(Collectors.joining()),
 178                              returnType().descriptorString());
 179     }
 180 
 181     /**
 182      * Return a human-readable descriptor for this method type, using the
 183      * canonical names for parameter and return types
 184      *
 185      * @return the human-readable descriptor for this method type
 186      */
 187     default String displayDescriptor() {
 188         return String.format("(%s)%s",
 189                              Stream.of(parameterArray())
 190                                    .map(ClassDesc::displayName)
 191                                    .collect(Collectors.joining(",")),
 192                              returnType().displayName());
 193     }
 194 }