82 * The query methods {@code parameterArray} and {@code parameterList}
83 * also provide a choice between arrays and lists.
84 * <p>
85 * {@code MethodType} objects are sometimes derived from bytecode instructions
86 * such as {@code invokedynamic}, specifically from the type descriptor strings associated
87 * with the instructions in a class file's constant pool.
88 * <p>
89 * Like classes and strings, method types can also be represented directly
90 * in a class file's constant pool as constants.
91 * A method type may be loaded by an {@code ldc} instruction which refers
92 * to a suitable {@code CONSTANT_MethodType} constant pool entry.
93 * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
94 * (For full details on method type constants, see sections {@jvms
95 * 4.4.8} and {@jvms 5.4.3.5} of the Java Virtual Machine
96 * Specification.)
97 * <p>
98 * When the JVM materializes a {@code MethodType} from a descriptor string,
99 * all classes named in the descriptor must be accessible, and will be loaded.
100 * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
101 * This loading may occur at any time before the {@code MethodType} object is first derived.
102 * @author John Rose, JSR 292 EG
103 * @since 1.7
104 */
105 public final
106 class MethodType
107 implements Constable,
108 TypeDescriptor.OfMethod<Class<?>, MethodType>,
109 java.io.Serializable {
110 @java.io.Serial
111 private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
112
113 // The rtype and ptypes fields define the structural identity of the method type:
114 private final @Stable Class<?> rtype;
115 private final @Stable Class<?>[] ptypes;
116
117 // The remaining fields are caches of various sorts:
118 private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
119 private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
120 private @Stable Invokers invokers; // cache of handy higher-order adapters
121 private @Stable String methodDescriptor; // cache for toMethodDescriptorString
1122 * IMPORTANT: This method is preferable for JDK internal use as it more
1123 * correctly interprets {@code null} ClassLoader than
1124 * {@link #fromMethodDescriptorString(String, ClassLoader)}.
1125 * Use of this method also avoids early initialization issues when system
1126 * ClassLoader is not initialized yet.
1127 */
1128 static MethodType fromDescriptor(String descriptor, ClassLoader loader)
1129 throws IllegalArgumentException, TypeNotPresentException
1130 {
1131 if (!descriptor.startsWith("(") || // also generates NPE if needed
1132 descriptor.indexOf(')') < 0 ||
1133 descriptor.indexOf('.') >= 0)
1134 throw newIllegalArgumentException("not a method descriptor: "+descriptor);
1135 List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
1136 Class<?> rtype = types.remove(types.size() - 1);
1137 Class<?>[] ptypes = listToArray(types);
1138 return makeImpl(rtype, ptypes, true);
1139 }
1140
1141 /**
1142 * Produces a bytecode descriptor representation of the method type.
1143 * <p>
1144 * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
1145 * Two distinct classes which share a common name but have different class loaders
1146 * will appear identical when viewed within descriptor strings.
1147 * <p>
1148 * This method is included for the benefit of applications that must
1149 * generate bytecodes that process method handles and {@code invokedynamic}.
1150 * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
1151 * because the latter requires a suitable class loader argument.
1152 * @return the bytecode type descriptor representation
1153 */
1154 public String toMethodDescriptorString() {
1155 String desc = methodDescriptor;
1156 if (desc == null) {
1157 desc = BytecodeDescriptor.unparseMethod(this.rtype, this.ptypes);
1158 methodDescriptor = desc;
1159 }
1160 return desc;
1161 }
1162
1163 /**
1164 * Return a field type descriptor string for this type
1165 *
1166 * @return the descriptor string
1167 * @jvms 4.3.2 Field Descriptors
1168 * @since 12
1169 */
1170 @Override
1171 public String descriptorString() {
1172 return toMethodDescriptorString();
1173 }
1174
1175 /*non-public*/
1176 static String toFieldDescriptorString(Class<?> cls) {
1177 return BytecodeDescriptor.unparse(cls);
1178 }
1179
1180 /**
1181 * Return a nominal descriptor for this instance, if one can be
1182 * constructed, or an empty {@link Optional} if one cannot be.
1183 *
1184 * @return An {@link Optional} containing the resulting nominal descriptor,
1185 * or an empty {@link Optional} if one cannot be constructed.
1186 * @since 12
1187 */
1188 @Override
1189 public Optional<MethodTypeDesc> describeConstable() {
1190 try {
1191 return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
1192 Stream.of(parameterArray())
1193 .map(p -> p.describeConstable().orElseThrow())
1194 .toArray(ClassDesc[]::new)));
1195 }
1196 catch (NoSuchElementException e) {
1197 return Optional.empty();
1198 }
1199 }
1200
1201 /// Serialization.
1202
1203 /**
|
82 * The query methods {@code parameterArray} and {@code parameterList}
83 * also provide a choice between arrays and lists.
84 * <p>
85 * {@code MethodType} objects are sometimes derived from bytecode instructions
86 * such as {@code invokedynamic}, specifically from the type descriptor strings associated
87 * with the instructions in a class file's constant pool.
88 * <p>
89 * Like classes and strings, method types can also be represented directly
90 * in a class file's constant pool as constants.
91 * A method type may be loaded by an {@code ldc} instruction which refers
92 * to a suitable {@code CONSTANT_MethodType} constant pool entry.
93 * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
94 * (For full details on method type constants, see sections {@jvms
95 * 4.4.8} and {@jvms 5.4.3.5} of the Java Virtual Machine
96 * Specification.)
97 * <p>
98 * When the JVM materializes a {@code MethodType} from a descriptor string,
99 * all classes named in the descriptor must be accessible, and will be loaded.
100 * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
101 * This loading may occur at any time before the {@code MethodType} object is first derived.
102 *
103 * @author John Rose, JSR 292 EG
104 * @since 1.7
105 */
106 public final
107 class MethodType
108 implements Constable,
109 TypeDescriptor.OfMethod<Class<?>, MethodType>,
110 java.io.Serializable {
111 @java.io.Serial
112 private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
113
114 // The rtype and ptypes fields define the structural identity of the method type:
115 private final @Stable Class<?> rtype;
116 private final @Stable Class<?>[] ptypes;
117
118 // The remaining fields are caches of various sorts:
119 private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
120 private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
121 private @Stable Invokers invokers; // cache of handy higher-order adapters
122 private @Stable String methodDescriptor; // cache for toMethodDescriptorString
1123 * IMPORTANT: This method is preferable for JDK internal use as it more
1124 * correctly interprets {@code null} ClassLoader than
1125 * {@link #fromMethodDescriptorString(String, ClassLoader)}.
1126 * Use of this method also avoids early initialization issues when system
1127 * ClassLoader is not initialized yet.
1128 */
1129 static MethodType fromDescriptor(String descriptor, ClassLoader loader)
1130 throws IllegalArgumentException, TypeNotPresentException
1131 {
1132 if (!descriptor.startsWith("(") || // also generates NPE if needed
1133 descriptor.indexOf(')') < 0 ||
1134 descriptor.indexOf('.') >= 0)
1135 throw newIllegalArgumentException("not a method descriptor: "+descriptor);
1136 List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
1137 Class<?> rtype = types.remove(types.size() - 1);
1138 Class<?>[] ptypes = listToArray(types);
1139 return makeImpl(rtype, ptypes, true);
1140 }
1141
1142 /**
1143 * Returns a descriptor string for the method type. This method
1144 * is equivalent to calling {@link #descriptorString() MethodType::descriptorString}.
1145 *
1146 * <p>
1147 * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
1148 * Two distinct classes which share a common name but have different class loaders
1149 * will appear identical when viewed within descriptor strings.
1150 * <p>
1151 * This method is included for the benefit of applications that must
1152 * generate bytecodes that process method handles and {@code invokedynamic}.
1153 * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
1154 * because the latter requires a suitable class loader argument.
1155 * @return the descriptor string for this method type
1156 * @jvms 4.3.3 Method Descriptors
1157 */
1158 public String toMethodDescriptorString() {
1159 String desc = methodDescriptor;
1160 if (desc == null) {
1161 desc = BytecodeDescriptor.unparseMethod(this.rtype, this.ptypes);
1162 methodDescriptor = desc;
1163 }
1164 return desc;
1165 }
1166
1167 /**
1168 * Returns a descriptor string for this method type.
1169 *
1170 * <p> If none of the parameter types and return type is a {@linkplain Class#isHidden()
1171 * hidden} class or interface, then the result is a method type descriptor string
1172 * (JVMS {@jvms 4.3.3}). {@link MethodTypeDesc MethodTypeDesc} can be created from
1173 * the result method type descriptor via
1174 * {@link MethodTypeDesc#ofDescriptor(String) MethodTypeDesc::ofDescriptor}.
1175 *
1176 * <p> If any of the parameter types and return type is a {@linkplain Class#isHidden()
1177 * hidden} class or interface, then the result is a string of the form:
1178 * {@code "(<parameter-descriptors>)<return-descriptor>"}
1179 * where {@code <parameter-descriptors>} is the concatenation of the
1180 * {@linkplain Class#descriptorString() descriptor string} of all parameter types
1181 * and the {@linkplain Class#descriptorString() descriptor string} of the return type.
1182 * This method type cannot be described nominally and no
1183 * {@link java.lang.constant.MethodTypeDesc MethodTypeDesc} can be produced from
1184 * the result string.
1185 *
1186 * @return the descriptor string for this method type
1187 * @since 12
1188 * @jvms 4.3.3 Method Descriptors
1189 */
1190 @Override
1191 public String descriptorString() {
1192 return toMethodDescriptorString();
1193 }
1194
1195 /*non-public*/
1196 static String toFieldDescriptorString(Class<?> cls) {
1197 return BytecodeDescriptor.unparse(cls);
1198 }
1199
1200 /**
1201 * Returns a nominal descriptor for this instance, if one can be
1202 * constructed, or an empty {@link Optional} if one cannot be.
1203 *
1204 * <p> If any of the parameter types and return type is {@linkplain Class#isHidden()
1205 * hidden}, then this method returns an empty {@link Optional} because
1206 * this method type cannot be described in nominal form.
1207 *
1208 * @return An {@link Optional} containing the resulting nominal descriptor,
1209 * or an empty {@link Optional} if one cannot be constructed.
1210 * @since 12
1211 */
1212 @Override
1213 public Optional<MethodTypeDesc> describeConstable() {
1214 try {
1215 return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
1216 Stream.of(parameterArray())
1217 .map(p -> p.describeConstable().orElseThrow())
1218 .toArray(ClassDesc[]::new)));
1219 }
1220 catch (NoSuchElementException e) {
1221 return Optional.empty();
1222 }
1223 }
1224
1225 /// Serialization.
1226
1227 /**
|