Java tutorial
/* * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang.instrument; import java.security.ProtectionDomain; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarFile; /* * Copyright 2003 Wily Technology, Inc. */ /** * This class provides services needed to instrument Java * programming language code. * Instrumentation is the addition of byte-codes to methods for the * purpose of gathering data to be utilized by tools. * Since the changes are purely additive, these tools do not modify * application state or behavior. * Examples of such benign tools include monitoring agents, profilers, * coverage analyzers, and event loggers. * * <P> * There are two ways to obtain an instance of the * <code>Instrumentation</code> interface: * * <ol> * <li><p> When a JVM is launched in a way that indicates an agent * class. In that case an <code>Instrumentation</code> instance * is passed to the <code>premain</code> method of the agent class. * </p></li> * <li><p> When a JVM provides a mechanism to start agents sometime * after the JVM is launched. In that case an <code>Instrumentation</code> * instance is passed to the <code>agentmain</code> method of the * agent code. </p> </li> * </ol> * <p> * These mechanisms are described in the * {@linkplain java.lang.instrument package specification}. * <p> * Once an agent acquires an <code>Instrumentation</code> instance, * the agent may call methods on the instance at any time. * * @apiNote This interface is not intended to be implemented outside of * the java.instrument module. * * @since 1.5 */ public interface Instrumentation { /** * Registers the supplied transformer. All future class definitions * will be seen by the transformer, except definitions of classes upon which any * registered transformer is dependent. * The transformer is called when classes are loaded, when they are * {@linkplain #redefineClasses redefined}. and if <code>canRetransform</code> is true, * when they are {@linkplain #retransformClasses retransformed}. * {@link ClassFileTransformer} defines the order of transform calls. * * If a transformer throws * an exception during execution, the JVM will still call the other registered * transformers in order. The same transformer may be added more than once, * but it is strongly discouraged -- avoid this by creating a new instance of * transformer class. * <P> * This method is intended for use in instrumentation, as described in the * {@linkplain Instrumentation class specification}. * * @param transformer the transformer to register * @param canRetransform can this transformer's transformations be retransformed * @throws java.lang.NullPointerException if passed a <code>null</code> transformer * @throws java.lang.UnsupportedOperationException if <code>canRetransform</code> * is true and the current configuration of the JVM does not allow * retransformation ({@link #isRetransformClassesSupported} is false) * @since 1.6 */ void addTransformer(ClassFileTransformer transformer, boolean canRetransform); /** * Registers the supplied transformer. * <P> * Same as <code>addTransformer(transformer, false)</code>. * * @param transformer the transformer to register * @throws java.lang.NullPointerException if passed a <code>null</code> transformer * @see #addTransformer(ClassFileTransformer,boolean) */ void addTransformer(ClassFileTransformer transformer); /** * Unregisters the supplied transformer. Future class definitions will * not be shown to the transformer. Removes the most-recently-added matching * instance of the transformer. Due to the multi-threaded nature of * class loading, it is possible for a transformer to receive calls * after it has been removed. Transformers should be written defensively * to expect this situation. * * @param transformer the transformer to unregister * @return true if the transformer was found and removed, false if the * transformer was not found * @throws java.lang.NullPointerException if passed a <code>null</code> transformer */ boolean removeTransformer(ClassFileTransformer transformer); /** * Returns whether or not the current JVM configuration supports retransformation * of classes. * The ability to retransform an already loaded class is an optional capability * of a JVM. * Retransformation will only be supported if the * <code>Can-Retransform-Classes</code> manifest attribute is set to * <code>true</code> in the agent JAR file (as described in the * {@linkplain java.lang.instrument package specification}) and the JVM supports * this capability. * During a single instantiation of a single JVM, multiple calls to this * method will always return the same answer. * @return true if the current JVM configuration supports retransformation of * classes, false if not. * @see #retransformClasses * @since 1.6 */ boolean isRetransformClassesSupported(); /** * Retransform the supplied set of classes. * * <P> * This function facilitates the instrumentation * of already loaded classes. * When classes are initially loaded or when they are * {@linkplain #redefineClasses redefined}, * the initial class file bytes can be transformed with the * {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer}. * This function reruns the transformation process * (whether or not a transformation has previously occurred). * This retransformation follows these steps: * <ul> * <li>starting from the initial class file bytes * </li> * <li>for each transformer that was added with <code>canRetransform</code> * false, the bytes returned by * {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[]) * transform} during the last class load or redefine are * reused as the output of the transformation; note that this is * equivalent to reapplying the previous transformation, unaltered; * except that {@code transform} method is not called. * </li> * <li>for each transformer that was added with <code>canRetransform</code> * true, the * {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[]) * transform} method is called in these transformers * </li> * <li>the transformed class file bytes are installed as the new * definition of the class * </li> * </ul> * <P> * * The order of transformation is described in {@link ClassFileTransformer}. * This same order is used in the automatic reapplication of * retransformation incapable transforms. * <P> * * The initial class file bytes represent the bytes passed to * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} or * {@link #redefineClasses redefineClasses} * (before any transformations * were applied), however they might not exactly match them. * The constant pool might not have the same layout or contents. * The constant pool may have more or fewer entries. * Constant pool entries may be in a different order; however, * constant pool indices in the bytecodes of methods will correspond. * Some attributes may not be present. * Where order is not meaningful, for example the order of methods, * order might not be preserved. * * <P> * This method operates on * a set in order to allow interdependent changes to more than one class at the same time * (a retransformation of class A can require a retransformation of class B). * * <P> * If a retransformed method has active stack frames, those active frames continue to * run the bytecodes of the original method. * The retransformed method will be used on new invokes. * * <P> * This method does not cause any initialization except that which would occur * under the customary JVM semantics. In other words, redefining a class * does not cause its initializers to be run. The values of static variables * will remain as they were prior to the call. * * <P> * Instances of the retransformed class are not affected. * * <P> * The retransformation may change method bodies, the constant pool and * attributes (unless explicitly prohibited). * The retransformation must not add, remove or rename fields or methods, change the * signatures of methods, or change inheritance. * The retransformation must not change the <code>NestHost</code> or * <code>NestMembers</code> attributes. * These restrictions may be lifted in future versions. * The class file bytes are not checked, verified and installed * until after the transformations have been applied, if the resultant bytes are in * error this method will throw an exception. * * <P> * If this method throws an exception, no classes have been retransformed. * <P> * This method is intended for use in instrumentation, as described in the * {@linkplain Instrumentation class specification}. * * @param classes array of classes to retransform; * a zero-length array is allowed, in this case, this method does nothing * @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified * ({@link #isModifiableClass} would return <code>false</code>) * @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow * retransformation ({@link #isRetransformClassesSupported} is false) or the retransformation attempted * to make unsupported changes * @throws java.lang.ClassFormatError if the data did not contain a valid class * @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class * @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported * @throws java.lang.ClassCircularityError if the new classes contain a circularity * @throws java.lang.LinkageError if a linkage error occurs * @throws java.lang.NullPointerException if the supplied classes array or any of its components * is <code>null</code>. * * @see #isRetransformClassesSupported * @see #addTransformer * @see java.lang.instrument.ClassFileTransformer * @since 1.6 */ void retransformClasses(Class<?>... classes) throws UnmodifiableClassException; /** * Returns whether or not the current JVM configuration supports redefinition * of classes. * The ability to redefine an already loaded class is an optional capability * of a JVM. * Redefinition will only be supported if the * <code>Can-Redefine-Classes</code> manifest attribute is set to * <code>true</code> in the agent JAR file (as described in the * {@linkplain java.lang.instrument package specification}) and the JVM supports * this capability. * During a single instantiation of a single JVM, multiple calls to this * method will always return the same answer. * @return true if the current JVM configuration supports redefinition of classes, * false if not. * @see #redefineClasses */ boolean isRedefineClassesSupported(); /** * Redefine the supplied set of classes using the supplied class files. * * <P> * This method is used to replace the definition of a class without reference * to the existing class file bytes, as one might do when recompiling from source * for fix-and-continue debugging. * Where the existing class file bytes are to be transformed (for * example in bytecode instrumentation) * {@link #retransformClasses retransformClasses} * should be used. * * <P> * This method operates on * a set in order to allow interdependent changes to more than one class at the same time * (a redefinition of class A can require a redefinition of class B). * * <P> * If a redefined method has active stack frames, those active frames continue to * run the bytecodes of the original method. * The redefined method will be used on new invokes. * * <P> * This method does not cause any initialization except that which would occur * under the customary JVM semantics. In other words, redefining a class * does not cause its initializers to be run. The values of static variables * will remain as they were prior to the call. * * <P> * Instances of the redefined class are not affected. * * <P> * The redefinition may change method bodies, the constant pool and attributes * (unless explicitly prohibited). * The redefinition must not add, remove or rename fields or methods, change the * signatures of methods, or change inheritance. * The redefinition must not change the <code>NestHost</code> or * <code>NestMembers</code> attributes. * These restrictions may be lifted in future versions. * The class file bytes are not checked, verified and installed * until after the transformations have been applied, if the resultant bytes are in * error this method will throw an exception. * * <P> * If this method throws an exception, no classes have been redefined. * <P> * This method is intended for use in instrumentation, as described in the * {@linkplain Instrumentation class specification}. * * @param definitions array of classes to redefine with corresponding definitions; * a zero-length array is allowed, in this case, this method does nothing * @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified * ({@link #isModifiableClass} would return <code>false</code>) * @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow * redefinition ({@link #isRedefineClassesSupported} is false) or the redefinition attempted * to make unsupported changes * @throws java.lang.ClassFormatError if the data did not contain a valid class * @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class * @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported * @throws java.lang.ClassCircularityError if the new classes contain a circularity * @throws java.lang.LinkageError if a linkage error occurs * @throws java.lang.NullPointerException if the supplied definitions array or any of its components * is <code>null</code> * @throws java.lang.ClassNotFoundException Can never be thrown (present for compatibility reasons only) * * @see #isRedefineClassesSupported * @see #addTransformer * @see java.lang.instrument.ClassFileTransformer */ void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException; /** * Tests whether a class is modifiable by * {@linkplain #retransformClasses retransformation} * or {@linkplain #redefineClasses redefinition}. * If a class is modifiable then this method returns <code>true</code>. * If a class is not modifiable then this method returns <code>false</code>. * <P> * For a class to be retransformed, {@link #isRetransformClassesSupported} must also be true. * But the value of <code>isRetransformClassesSupported()</code> does not influence the value * returned by this function. * For a class to be redefined, {@link #isRedefineClassesSupported} must also be true. * But the value of <code>isRedefineClassesSupported()</code> does not influence the value * returned by this function. * <P> * Primitive classes (for example, <code>java.lang.Integer.TYPE</code>) * and array classes are never modifiable. * * @param theClass the class to check for being modifiable * @return whether or not the argument class is modifiable * @throws java.lang.NullPointerException if the specified class is <code>null</code>. * * @see #retransformClasses * @see #isRetransformClassesSupported * @see #redefineClasses * @see #isRedefineClassesSupported * @since 1.6 */ boolean isModifiableClass(Class<?> theClass); /** * Returns an array of all classes currently loaded by the JVM. * * @return an array containing all the classes loaded by the JVM, zero-length if there are none */ @SuppressWarnings("rawtypes") Class[] getAllLoadedClasses(); /** * Returns an array of all classes for which <code>loader</code> is an initiating loader. * If the supplied loader is <code>null</code>, classes initiated by the bootstrap class * loader are returned. * * @param loader the loader whose initiated class list will be returned * @return an array containing all the classes for which loader is an initiating loader, * zero-length if there are none */ @SuppressWarnings("rawtypes") Class[] getInitiatedClasses(ClassLoader loader); /** * Returns an implementation-specific approximation of the amount of storage consumed by * the specified object. The result may include some or all of the object's overhead, * and thus is useful for comparison within an implementation but not between implementations. * * The estimate may change during a single invocation of the JVM. * * @param objectToSize the object to size * @return an implementation-specific approximation of the amount of storage consumed by the specified object * @throws java.lang.NullPointerException if the supplied Object is <code>null</code>. */ long getObjectSize(Object objectToSize); /** * Specifies a JAR file with instrumentation classes to be defined by the * bootstrap class loader. * * <p> When the virtual machine's built-in class loader, known as the "bootstrap * class loader", unsuccessfully searches for a class, the entries in the {@link * java.util.jar.JarFile JAR file} will be searched as well. * * <p> This method may be used multiple times to add multiple JAR files to be * searched in the order that this method was invoked. * * <p> The agent should take care to ensure that the JAR does not contain any * classes or resources other than those to be defined by the bootstrap * class loader for the purpose of instrumentation. * Failure to observe this warning could result in unexpected * behavior that is difficult to diagnose. For example, suppose there is a * loader L, and L's parent for delegation is the bootstrap class loader. * Furthermore, a method in class C, a class defined by L, makes reference to * a non-public accessor class C$1. If the JAR file contains a class C$1 then * the delegation to the bootstrap class loader will cause C$1 to be defined * by the bootstrap class loader. In this example an <code>IllegalAccessError</code> * will be thrown that may cause the application to fail. One approach to * avoiding these types of issues, is to use a unique package name for the * instrumentation classes. * * <p> * <cite>The Java™ Virtual Machine Specification</cite> * specifies that a subsequent attempt to resolve a symbolic * reference that the Java virtual machine has previously unsuccessfully attempted * to resolve always fails with the same error that was thrown as a result of the * initial resolution attempt. Consequently, if the JAR file contains an entry * that corresponds to a class for which the Java virtual machine has * unsuccessfully attempted to resolve a reference, then subsequent attempts to * resolve that reference will fail with the same error as the initial attempt. * * @param jarfile * The JAR file to be searched when the bootstrap class loader * unsuccessfully searches for a class. * * @throws NullPointerException * If <code>jarfile</code> is <code>null</code>. * * @see #appendToSystemClassLoaderSearch * @see java.lang.ClassLoader * @see java.util.jar.JarFile * * @since 1.6 */ void appendToBootstrapClassLoaderSearch(JarFile jarfile); /** * Specifies a JAR file with instrumentation classes to be defined by the * system class loader. * * When the system class loader for delegation (see * {@link java.lang.ClassLoader#getSystemClassLoader getSystemClassLoader()}) * unsuccessfully searches for a class, the entries in the {@link * java.util.jar.JarFile JarFile} will be searched as well. * * <p> This method may be used multiple times to add multiple JAR files to be * searched in the order that this method was invoked. * * <p> The agent should take care to ensure that the JAR does not contain any * classes or resources other than those to be defined by the system class * loader for the purpose of instrumentation. * Failure to observe this warning could result in unexpected * behavior that is difficult to diagnose (see * {@link #appendToBootstrapClassLoaderSearch * appendToBootstrapClassLoaderSearch}). * * <p> The system class loader supports adding a JAR file to be searched if * it implements a method named <code>appendToClassPathForInstrumentation</code> * which takes a single parameter of type <code>java.lang.String</code>. The * method is not required to have <code>public</code> access. The name of * the JAR file is obtained by invoking the {@link java.util.zip.ZipFile#getName * getName()} method on the <code>jarfile</code> and this is provided as the * parameter to the <code>appendToClassPathForInstrumentation</code> method. * * <p> * <cite>The Java™ Virtual Machine Specification</cite> * specifies that a subsequent attempt to resolve a symbolic * reference that the Java virtual machine has previously unsuccessfully attempted * to resolve always fails with the same error that was thrown as a result of the * initial resolution attempt. Consequently, if the JAR file contains an entry * that corresponds to a class for which the Java virtual machine has * unsuccessfully attempted to resolve a reference, then subsequent attempts to * resolve that reference will fail with the same error as the initial attempt. * * <p> This method does not change the value of <code>java.class.path</code> * {@link java.lang.System#getProperties system property}. * * @param jarfile * The JAR file to be searched when the system class loader * unsuccessfully searches for a class. * * @throws UnsupportedOperationException * If the system class loader does not support appending a * a JAR file to be searched. * * @throws NullPointerException * If <code>jarfile</code> is <code>null</code>. * * @see #appendToBootstrapClassLoaderSearch * @see java.lang.ClassLoader#getSystemClassLoader * @see java.util.jar.JarFile * @since 1.6 */ void appendToSystemClassLoaderSearch(JarFile jarfile); /** * Returns whether the current JVM configuration supports * {@linkplain #setNativeMethodPrefix(ClassFileTransformer,String) * setting a native method prefix}. * The ability to set a native method prefix is an optional * capability of a JVM. * Setting a native method prefix will only be supported if the * <code>Can-Set-Native-Method-Prefix</code> manifest attribute is set to * <code>true</code> in the agent JAR file (as described in the * {@linkplain java.lang.instrument package specification}) and the JVM supports * this capability. * During a single instantiation of a single JVM, multiple * calls to this method will always return the same answer. * @return true if the current JVM configuration supports * setting a native method prefix, false if not. * @see #setNativeMethodPrefix * @since 1.6 */ boolean isNativeMethodPrefixSupported(); /** * This method modifies the failure handling of * native method resolution by allowing retry * with a prefix applied to the name. * When used with the * {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer}, * it enables native methods to be * instrumented. * <p> * Since native methods cannot be directly instrumented * (they have no bytecodes), they must be wrapped with * a non-native method which can be instrumented. * For example, if we had: * <pre> * native boolean foo(int x);</pre> * <p> * We could transform the class file (with the * ClassFileTransformer during the initial definition * of the class) so that this becomes: * <pre> * boolean foo(int x) { * <i>... record entry to foo ...</i> * return wrapped_foo(x); * } * * native boolean wrapped_foo(int x);</pre> * <p> * Where <code>foo</code> becomes a wrapper for the actual native * method with the appended prefix "wrapped_". Note that * "wrapped_" would be a poor choice of prefix since it * might conceivably form the name of an existing method * thus something like "$$$MyAgentWrapped$$$_" would be * better but would make these examples less readable. * <p> * The wrapper will allow data to be collected on the native * method call, but now the problem becomes linking up the * wrapped method with the native implementation. * That is, the method <code>wrapped_foo</code> needs to be * resolved to the native implementation of <code>foo</code>, * which might be: * <pre> * Java_somePackage_someClass_foo(JNIEnv* env, jint x)</pre> * <p> * This function allows the prefix to be specified and the * proper resolution to occur. * Specifically, when the standard resolution fails, the * resolution is retried taking the prefix into consideration. * There are two ways that resolution occurs, explicit * resolution with the JNI function <code>RegisterNatives</code> * and the normal automatic resolution. For * <code>RegisterNatives</code>, the JVM will attempt this * association: * <pre>{@code * method(foo) -> nativeImplementation(foo) * }</pre> * <p> * When this fails, the resolution will be retried with * the specified prefix prepended to the method name, * yielding the correct resolution: * <pre>{@code * method(wrapped_foo) -> nativeImplementation(foo) * }</pre> * <p> * For automatic resolution, the JVM will attempt: * <pre>{@code * method(wrapped_foo) -> nativeImplementation(wrapped_foo) * }</pre> * <p> * When this fails, the resolution will be retried with * the specified prefix deleted from the implementation name, * yielding the correct resolution: * <pre>{@code * method(wrapped_foo) -> nativeImplementation(foo) * }</pre> * <p> * Note that since the prefix is only used when standard * resolution fails, native methods can be wrapped selectively. * <p> * Since each <code>ClassFileTransformer</code> * can do its own transformation of the bytecodes, more * than one layer of wrappers may be applied. Thus each * transformer needs its own prefix. Since transformations * are applied in order, the prefixes, if applied, will * be applied in the same order * (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}). * Thus if three transformers applied * wrappers, <code>foo</code> might become * <code>$trans3_$trans2_$trans1_foo</code>. But if, say, * the second transformer did not apply a wrapper to * <code>foo</code> it would be just * <code>$trans3_$trans1_foo</code>. To be able to * efficiently determine the sequence of prefixes, * an intermediate prefix is only applied if its non-native * wrapper exists. Thus, in the last example, even though * <code>$trans1_foo</code> is not a native method, the * <code>$trans1_</code> prefix is applied since * <code>$trans1_foo</code> exists. * * @param transformer * The ClassFileTransformer which wraps using this prefix. * @param prefix * The prefix to apply to wrapped native methods when * retrying a failed native method resolution. If prefix * is either <code>null</code> or the empty string, then * failed native method resolutions are not retried for * this transformer. * @throws java.lang.NullPointerException if passed a <code>null</code> transformer. * @throws java.lang.UnsupportedOperationException if the current configuration of * the JVM does not allow setting a native method prefix * ({@link #isNativeMethodPrefixSupported} is false). * @throws java.lang.IllegalArgumentException if the transformer is not registered * (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}). * * @since 1.6 */ void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix); /** * Redefine a module to expand the set of modules that it reads, the set of * packages that it exports or opens, or the services that it uses or * provides. This method facilitates the instrumentation of code in named * modules where that instrumentation requires changes to the set of modules * that are read, the packages that are exported or open, or the services * that are used or provided. * * <p> This method cannot reduce the set of modules that a module reads, nor * reduce the set of packages that it exports or opens, nor reduce the set * of services that it uses or provides. This method is a no-op when invoked * to redefine an unnamed module. </p> * * <p> When expanding the services that a module uses or provides then the * onus is on the agent to ensure that the service type will be accessible at * each instrumentation site where the service type is used. This method * does not check if the service type is a member of the module or in a * package exported to the module by another module that it reads. </p> * * <p> The {@code extraExports} parameter is the map of additional packages * to export. The {@code extraOpens} parameter is the map of additional * packages to open. In both cases, the map key is the fully-qualified name * of the package as defined in section 6.5.3 of * <cite>The Java™ Language Specification </cite>, for example, {@code * "java.lang"}. The map value is the non-empty set of modules that the * package should be exported or opened to. </p> * * <p> The {@code extraProvides} parameter is the additional service providers * for the module to provide. The map key is the service type. The map value * is the non-empty list of implementation types, each of which is a member * of the module and an implementation of the service. </p> * * <p> This method is safe for concurrent use and so allows multiple agents * to instrument and update the same module at around the same time. </p> * * @param module the module to redefine * @param extraReads the possibly-empty set of additional modules to read * @param extraExports the possibly-empty map of additional packages to export * @param extraOpens the possibly-empty map of additional packages to open * @param extraUses the possibly-empty set of additional services to use * @param extraProvides the possibly-empty map of additional services to provide * * @throws IllegalArgumentException * If {@code extraExports} or {@code extraOpens} contains a key * that is not a package in the module; if {@code extraExports} or * {@code extraOpens} maps a key to an empty set; if a value in the * {@code extraProvides} map contains a service provider type that * is not a member of the module or an implementation of the service; * or {@code extraProvides} maps a key to an empty list * @throws UnmodifiableModuleException if the module cannot be modified * @throws NullPointerException if any of the arguments are {@code null} or * any of the Sets or Maps contains a {@code null} key or value * * @see #isModifiableModule(Module) * @since 9 * @spec JPMS */ void redefineModule(Module module, Set<Module> extraReads, Map<String, Set<Module>> extraExports, Map<String, Set<Module>> extraOpens, Set<Class<?>> extraUses, Map<Class<?>, List<Class<?>>> extraProvides); /** * Tests whether a module can be modified with {@link #redefineModule * redefineModule}. If a module is modifiable then this method returns * {@code true}. If a module is not modifiable then this method returns * {@code false}. This method always returns {@code true} when the module * is an unnamed module (as redefining an unnamed module is a no-op). * * @param module the module to test if it can be modified * @return {@code true} if the module is modifiable, otherwise {@code false} * @throws NullPointerException if the module is {@code null} * * @since 9 * @spec JPMS */ boolean isModifiableModule(Module module); }