< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodType.java

Print this page




  87  * Like classes and strings, method types can also be represented directly
  88  * in a class file's constant pool as constants.
  89  * A method type may be loaded by an {@code ldc} instruction which refers
  90  * to a suitable {@code CONSTANT_MethodType} constant pool entry.
  91  * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
  92  * (For full details on method type constants,
  93  * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
  94  * <p>
  95  * When the JVM materializes a {@code MethodType} from a descriptor string,
  96  * all classes named in the descriptor must be accessible, and will be loaded.
  97  * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
  98  * This loading may occur at any time before the {@code MethodType} object is first derived.
  99  * @author John Rose, JSR 292 EG
 100  * @since 1.7
 101  */
 102 public final
 103 class MethodType
 104         implements Constable,
 105                    TypeDescriptor.OfMethod<Class<?>, MethodType>,
 106                    java.io.Serializable {

 107     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
 108 
 109     // The rtype and ptypes fields define the structural identity of the method type:
 110     private final @Stable Class<?>   rtype;
 111     private final @Stable Class<?>[] ptypes;
 112 
 113     // The remaining fields are caches of various sorts:
 114     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
 115     private @Stable MethodType wrapAlt;  // alternative wrapped/unwrapped version
 116     private @Stable Invokers invokers;   // cache of handy higher-order adapters
 117     private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
 118 
 119     /**
 120      * Constructor that performs no copying or validation.
 121      * Should only be called from the factory method makeImpl
 122      */
 123     private MethodType(Class<?> rtype, Class<?>[] ptypes) {
 124         this.rtype = rtype;
 125         this.ptypes = ptypes;
 126     }


1212      * @since 12
1213      */
1214     @Override
1215     public Optional<MethodTypeDesc> describeConstable() {
1216         try {
1217             return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
1218                                                  Stream.of(parameterArray())
1219                                                       .map(p -> p.describeConstable().orElseThrow())
1220                                                       .toArray(ClassDesc[]::new)));
1221         }
1222         catch (NoSuchElementException e) {
1223             return Optional.empty();
1224         }
1225     }
1226 
1227     /// Serialization.
1228 
1229     /**
1230      * There are no serializable fields for {@code MethodType}.
1231      */

1232     private static final java.io.ObjectStreamField[] serialPersistentFields = { };
1233 
1234     /**
1235      * Save the {@code MethodType} instance to a stream.
1236      *
1237      * @serialData
1238      * For portability, the serialized format does not refer to named fields.
1239      * Instead, the return type and parameter type arrays are written directly
1240      * from the {@code writeObject} method, using two calls to {@code s.writeObject}
1241      * as follows:
1242      * <blockquote><pre>{@code
1243 s.writeObject(this.returnType());
1244 s.writeObject(this.parameterArray());
1245      * }</pre></blockquote>
1246      * <p>
1247      * The deserialized field values are checked as if they were
1248      * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
1249      * For example, null values, or {@code void} parameter types,
1250      * will lead to exceptions during deserialization.
1251      * @param s the stream to write the object to
1252      * @throws java.io.IOException if there is a problem writing the object
1253      */

1254     private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
1255         s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
1256         s.writeObject(returnType());
1257         s.writeObject(parameterArray());
1258     }
1259 
1260     /**
1261      * Reconstitute the {@code MethodType} instance from a stream (that is,
1262      * deserialize it).
1263      * This instance is a scratch object with bogus final fields.
1264      * It provides the parameters to the factory method called by
1265      * {@link #readResolve readResolve}.
1266      * After that call it is discarded.
1267      * @param s the stream to read the object from
1268      * @throws java.io.IOException if there is a problem reading the object
1269      * @throws ClassNotFoundException if one of the component classes cannot be resolved
1270      * @see #readResolve
1271      * @see #writeObject
1272      */

1273     private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
1274         // Assign temporary defaults in case this object escapes
1275         MethodType_init(void.class, NO_PTYPES);
1276 
1277         s.defaultReadObject();  // requires serialPersistentFields to be an empty array
1278 
1279         Class<?>   returnType     = (Class<?>)   s.readObject();
1280         Class<?>[] parameterArray = (Class<?>[]) s.readObject();
1281         parameterArray = parameterArray.clone();  // make sure it is unshared
1282 
1283         // Assign deserialized values
1284         MethodType_init(returnType, parameterArray);
1285     }
1286 
1287     // Initialization of state for deserialization only
1288     private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
1289         // In order to communicate these values to readResolve, we must
1290         // store them into the implementation-specific final fields.
1291         checkRtype(rtype);
1292         checkPtypes(ptypes);
1293         UNSAFE.putReference(this, OffsetHolder.rtypeOffset, rtype);
1294         UNSAFE.putReference(this, OffsetHolder.ptypesOffset, ptypes);
1295     }
1296 
1297     // Support for resetting final fields while deserializing. Implement Holder
1298     // pattern to make the rarely needed offset calculation lazy.
1299     private static class OffsetHolder {
1300         static final long rtypeOffset
1301                 = UNSAFE.objectFieldOffset(MethodType.class, "rtype");
1302 
1303         static final long ptypesOffset
1304                 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1305     }
1306 
1307     /**
1308      * Resolves and initializes a {@code MethodType} object
1309      * after serialization.
1310      * @return the fully initialized {@code MethodType} object
1311      */

1312     private Object readResolve() {
1313         // Do not use a trusted path for deserialization:
1314         //    return makeImpl(rtype, ptypes, true);
1315         // Verify all operands, and make sure ptypes is unshared:
1316         try {
1317             return methodType(rtype, ptypes);
1318         } finally {
1319             // Re-assign defaults in case this object escapes
1320             MethodType_init(void.class, NO_PTYPES);
1321         }
1322     }
1323 
1324     /**
1325      * Simple implementation of weak concurrent intern set.
1326      *
1327      * @param <T> interned type
1328      */
1329     private static class ConcurrentWeakInternSet<T> {
1330 
1331         private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;




  87  * Like classes and strings, method types can also be represented directly
  88  * in a class file's constant pool as constants.
  89  * A method type may be loaded by an {@code ldc} instruction which refers
  90  * to a suitable {@code CONSTANT_MethodType} constant pool entry.
  91  * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
  92  * (For full details on method type constants,
  93  * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
  94  * <p>
  95  * When the JVM materializes a {@code MethodType} from a descriptor string,
  96  * all classes named in the descriptor must be accessible, and will be loaded.
  97  * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
  98  * This loading may occur at any time before the {@code MethodType} object is first derived.
  99  * @author John Rose, JSR 292 EG
 100  * @since 1.7
 101  */
 102 public final
 103 class MethodType
 104         implements Constable,
 105                    TypeDescriptor.OfMethod<Class<?>, MethodType>,
 106                    java.io.Serializable {
 107     @java.io.Serial
 108     private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
 109 
 110     // The rtype and ptypes fields define the structural identity of the method type:
 111     private final @Stable Class<?>   rtype;
 112     private final @Stable Class<?>[] ptypes;
 113 
 114     // The remaining fields are caches of various sorts:
 115     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
 116     private @Stable MethodType wrapAlt;  // alternative wrapped/unwrapped version
 117     private @Stable Invokers invokers;   // cache of handy higher-order adapters
 118     private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
 119 
 120     /**
 121      * Constructor that performs no copying or validation.
 122      * Should only be called from the factory method makeImpl
 123      */
 124     private MethodType(Class<?> rtype, Class<?>[] ptypes) {
 125         this.rtype = rtype;
 126         this.ptypes = ptypes;
 127     }


1213      * @since 12
1214      */
1215     @Override
1216     public Optional<MethodTypeDesc> describeConstable() {
1217         try {
1218             return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
1219                                                  Stream.of(parameterArray())
1220                                                       .map(p -> p.describeConstable().orElseThrow())
1221                                                       .toArray(ClassDesc[]::new)));
1222         }
1223         catch (NoSuchElementException e) {
1224             return Optional.empty();
1225         }
1226     }
1227 
1228     /// Serialization.
1229 
1230     /**
1231      * There are no serializable fields for {@code MethodType}.
1232      */
1233     @java.io.Serial
1234     private static final java.io.ObjectStreamField[] serialPersistentFields = { };
1235 
1236     /**
1237      * Save the {@code MethodType} instance to a stream.
1238      *
1239      * @serialData
1240      * For portability, the serialized format does not refer to named fields.
1241      * Instead, the return type and parameter type arrays are written directly
1242      * from the {@code writeObject} method, using two calls to {@code s.writeObject}
1243      * as follows:
1244      * <blockquote><pre>{@code
1245 s.writeObject(this.returnType());
1246 s.writeObject(this.parameterArray());
1247      * }</pre></blockquote>
1248      * <p>
1249      * The deserialized field values are checked as if they were
1250      * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
1251      * For example, null values, or {@code void} parameter types,
1252      * will lead to exceptions during deserialization.
1253      * @param s the stream to write the object to
1254      * @throws java.io.IOException if there is a problem writing the object
1255      */
1256     @java.io.Serial
1257     private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
1258         s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
1259         s.writeObject(returnType());
1260         s.writeObject(parameterArray());
1261     }
1262 
1263     /**
1264      * Reconstitute the {@code MethodType} instance from a stream (that is,
1265      * deserialize it).
1266      * This instance is a scratch object with bogus final fields.
1267      * It provides the parameters to the factory method called by
1268      * {@link #readResolve readResolve}.
1269      * After that call it is discarded.
1270      * @param s the stream to read the object from
1271      * @throws java.io.IOException if there is a problem reading the object
1272      * @throws ClassNotFoundException if one of the component classes cannot be resolved
1273      * @see #readResolve
1274      * @see #writeObject
1275      */
1276     @java.io.Serial
1277     private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
1278         // Assign temporary defaults in case this object escapes
1279         MethodType_init(void.class, NO_PTYPES);
1280 
1281         s.defaultReadObject();  // requires serialPersistentFields to be an empty array
1282 
1283         Class<?>   returnType     = (Class<?>)   s.readObject();
1284         Class<?>[] parameterArray = (Class<?>[]) s.readObject();
1285         parameterArray = parameterArray.clone();  // make sure it is unshared
1286 
1287         // Assign deserialized values
1288         MethodType_init(returnType, parameterArray);
1289     }
1290 
1291     // Initialization of state for deserialization only
1292     private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
1293         // In order to communicate these values to readResolve, we must
1294         // store them into the implementation-specific final fields.
1295         checkRtype(rtype);
1296         checkPtypes(ptypes);
1297         UNSAFE.putReference(this, OffsetHolder.rtypeOffset, rtype);
1298         UNSAFE.putReference(this, OffsetHolder.ptypesOffset, ptypes);
1299     }
1300 
1301     // Support for resetting final fields while deserializing. Implement Holder
1302     // pattern to make the rarely needed offset calculation lazy.
1303     private static class OffsetHolder {
1304         static final long rtypeOffset
1305                 = UNSAFE.objectFieldOffset(MethodType.class, "rtype");
1306 
1307         static final long ptypesOffset
1308                 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1309     }
1310 
1311     /**
1312      * Resolves and initializes a {@code MethodType} object
1313      * after serialization.
1314      * @return the fully initialized {@code MethodType} object
1315      */
1316     @java.io.Serial
1317     private Object readResolve() {
1318         // Do not use a trusted path for deserialization:
1319         //    return makeImpl(rtype, ptypes, true);
1320         // Verify all operands, and make sure ptypes is unshared:
1321         try {
1322             return methodType(rtype, ptypes);
1323         } finally {
1324             // Re-assign defaults in case this object escapes
1325             MethodType_init(void.class, NO_PTYPES);
1326         }
1327     }
1328 
1329     /**
1330      * Simple implementation of weak concurrent intern set.
1331      *
1332      * @param <T> interned type
1333      */
1334     private static class ConcurrentWeakInternSet<T> {
1335 
1336         private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;


< prev index next >