1 /* 2 * Copyright (c) 2018, 2019, 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.MethodHandle; 28 import java.lang.invoke.MethodHandles; 29 import java.lang.invoke.MethodType; 30 31 import static java.lang.constant.ConstantDescs.CD_void; 32 import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR; 33 34 /** 35 * A <a href="package-summary.html#nominal">nominal descriptor</a> for a 36 * {@link MethodHandle} constant. 37 * 38 * @since 12 39 */ 40 public sealed interface MethodHandleDesc 41 extends ConstantDesc 42 permits AsTypeMethodHandleDesc, 43 DirectMethodHandleDesc { 44 45 /** 46 * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a 47 * declared method, invocation of a constructor, or access to a field. 48 * 49 * <p>The lookup descriptor string has the same format as for the various 50 * variants of {@code CONSTANT_MethodHandle_info} and for the lookup 51 * methods on {@link MethodHandles.Lookup}. For a method or constructor 52 * invocation, it is interpreted as a method type descriptor; for field 53 * access, it is interpreted as a field descriptor. If {@code kind} is 54 * {@code CONSTRUCTOR}, the {@code name} parameter is ignored and the return 55 * type of the lookup descriptor must be {@code void}. If {@code kind} 56 * corresponds to a virtual method invocation, the lookup type includes the 57 * method parameters but not the receiver type. 58 * 59 * @param kind The kind of method handle to be described 60 * @param owner a {@link ClassDesc} describing the class containing the 61 * method, constructor, or field 62 * @param name the unqualified name of the method or field (ignored if 63 * {@code kind} is {@code CONSTRUCTOR}) 64 * @param lookupDescriptor a method descriptor string the lookup type, 65 * if the request is for a method invocation, or 66 * describing the invocation type, if the request is 67 * for a field or constructor 68 * @return the {@linkplain MethodHandleDesc} 69 * @throws NullPointerException if any of the non-ignored arguments are null 70 * @throws IllegalArgumentException if the descriptor string is not a valid 71 * method or field descriptor 72 * @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure 73 * @jvms 4.2.2 Unqualified Names 74 * @jvms 4.3.2 Field Descriptors 75 * @jvms 4.3.3 Method Descriptors 76 */ of(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String name, String lookupDescriptor)77 static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind, 78 ClassDesc owner, 79 String name, 80 String lookupDescriptor) { 81 switch (kind) { 82 case GETTER: 83 case SETTER: 84 case STATIC_GETTER: 85 case STATIC_SETTER: 86 return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor)); 87 default: 88 return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor)); 89 } 90 } 91 92 /** 93 * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a 94 * declared method or constructor. 95 * 96 * <p>The lookup descriptor string has the same format as for the lookup 97 * methods on {@link MethodHandles.Lookup}. If {@code kind} is 98 * {@code CONSTRUCTOR}, the name is ignored and the return type of the lookup 99 * type must be {@code void}. If {@code kind} corresponds to a virtual method 100 * invocation, the lookup type includes the method parameters but not the 101 * receiver type. 102 * 103 * @param kind The kind of method handle to be described; must be one of 104 * {@code SPECIAL, VIRTUAL, STATIC, INTERFACE_SPECIAL, 105 * INTERFACE_VIRTUAL, INTERFACE_STATIC, CONSTRUCTOR} 106 * @param owner a {@link ClassDesc} describing the class containing the 107 * method or constructor 108 * @param name the unqualified name of the method (ignored if {@code kind} 109 * is {@code CONSTRUCTOR}) 110 * @param lookupMethodType a {@link MethodTypeDesc} describing the lookup type 111 * @return the {@linkplain MethodHandleDesc} 112 * @throws NullPointerException if any non-ignored arguments are null 113 * @throws IllegalArgumentException if the {@code name} has the incorrect 114 * format, or the kind is invalid 115 * @jvms 4.2.2 Unqualified Names 116 */ ofMethod(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String name, MethodTypeDesc lookupMethodType)117 static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind, 118 ClassDesc owner, 119 String name, 120 MethodTypeDesc lookupMethodType) { 121 switch (kind) { 122 case GETTER: 123 case SETTER: 124 case STATIC_GETTER: 125 case STATIC_SETTER: 126 throw new IllegalArgumentException(kind.toString()); 127 case VIRTUAL: 128 case SPECIAL: 129 case INTERFACE_VIRTUAL: 130 case INTERFACE_SPECIAL: 131 case INTERFACE_STATIC: 132 case STATIC: 133 case CONSTRUCTOR: 134 return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType); 135 default: 136 throw new IllegalArgumentException(kind.toString()); 137 } 138 } 139 140 /** 141 * Creates a {@linkplain MethodHandleDesc} corresponding to a method handle 142 * that accesses a field. 143 * 144 * @param kind the kind of the method handle to be described; must be one of {@code GETTER}, 145 * {@code SETTER}, {@code STATIC_GETTER}, or {@code STATIC_SETTER} 146 * @param owner a {@link ClassDesc} describing the class containing the field 147 * @param fieldName the unqualified name of the field 148 * @param fieldType a {@link ClassDesc} describing the type of the field 149 * @return the {@linkplain MethodHandleDesc} 150 * @throws NullPointerException if any of the arguments are null 151 * @throws IllegalArgumentException if the {@code kind} is not one of the 152 * valid values or if the field name is not valid 153 * @jvms 4.2.2 Unqualified Names 154 */ ofField(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String fieldName, ClassDesc fieldType)155 static DirectMethodHandleDesc ofField(DirectMethodHandleDesc.Kind kind, 156 ClassDesc owner, 157 String fieldName, 158 ClassDesc fieldType) { 159 MethodTypeDesc mtr = switch (kind) { 160 case GETTER -> MethodTypeDesc.of(fieldType, owner); 161 case SETTER -> MethodTypeDesc.of(CD_void, owner, fieldType); 162 case STATIC_GETTER -> MethodTypeDesc.of(fieldType); 163 case STATIC_SETTER -> MethodTypeDesc.of(CD_void, fieldType); 164 default -> throw new IllegalArgumentException(kind.toString()); 165 }; 166 return new DirectMethodHandleDescImpl(kind, owner, fieldName, mtr); 167 } 168 169 /** 170 * Returns a {@linkplain MethodHandleDesc} corresponding to invocation of a constructor 171 * 172 * @param owner a {@link ClassDesc} describing the class containing the 173 * constructor 174 * @param paramTypes {@link ClassDesc}s describing the parameter types of 175 * the constructor 176 * @return the {@linkplain MethodHandleDesc} 177 * @throws NullPointerException if any argument or its contents is {@code null} 178 */ ofConstructor(ClassDesc owner, ClassDesc... paramTypes)179 static DirectMethodHandleDesc ofConstructor(ClassDesc owner, 180 ClassDesc... paramTypes) { 181 return MethodHandleDesc.ofMethod(CONSTRUCTOR, owner, ConstantDescs.DEFAULT_NAME, 182 MethodTypeDesc.of(CD_void, paramTypes)); 183 } 184 185 /** 186 * Returns a {@linkplain MethodHandleDesc} that describes this method handle 187 * adapted to a different type, as if by {@link MethodHandle#asType(MethodType)}. 188 * 189 * @param type a {@link MethodHandleDesc} describing the new method type 190 * @return a {@linkplain MethodHandleDesc} for the adapted method handle 191 * @throws NullPointerException if the argument is {@code null} 192 */ asType(MethodTypeDesc type)193 default MethodHandleDesc asType(MethodTypeDesc type) { 194 return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type); 195 } 196 197 /** 198 * Returns a {@link MethodTypeDesc} describing the invocation type of the 199 * method handle described by this nominal descriptor. The invocation type 200 * describes the full set of stack values that are consumed by the invocation 201 * (including the receiver, if any). 202 * 203 * @return a {@linkplain MethodHandleDesc} describing the method handle type 204 */ invocationType()205 MethodTypeDesc invocationType(); 206 207 /** 208 * Compares the specified object with this descriptor for equality. Returns 209 * {@code true} if and only if the specified object is also a 210 * {@linkplain MethodHandleDesc}, and both encode the same nominal description 211 * of a method handle. 212 * 213 * @param o the other object 214 * @return whether this descriptor is equal to the other object 215 */ equals(Object o)216 boolean equals(Object o); 217 } 218