Package net.minestom.server.extras.selfmodification

# Class MinestomRootClassLoader

java.lang.Object
java.lang.ClassLoader
java.security.SecureClassLoader
java.net.URLClassLoader
net.minestom.server.extras.selfmodification.HierarchyClassLoader
net.minestom.server.extras.selfmodification.MinestomRootClassLoader

All Implemented Interfaces:
  `TransformableClassloader`, `Closeable`, `AutoCloseable`

public class MinestomRootClassLoader extends HierarchyClassLoader implements TransformableClassloader
Class Loader that can modify class bytecode when they are loaded.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final boolean`
  `DEBUG`
  `final Set<String>`
  `protectedPackages`

  ### Fields inherited from class net.minestom.server.extras.selfmodification.HierarchyClassLoader

  `children, parents`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addASMTransformer(@NotNull ASMTransformer transformer)`
  `void`
  `addTransformer(ASMTransformer transformer)`
  Deprecated.
  `void`
  `addURL(URL url)`
  `Class<?>`
  `findClass(String name)`
  `@NotNull @Unmodifiable Collection<@NotNull ASMTransformer>`
  `getASMTransformers()`
  `@Nullable URI`
  `getClassCodeSourceURI(@NotNull String internalName)`
  Obtain the code source URI of the class, as per `CodeSource.getLocation()`.
  `static MinestomRootClassLoader`
  `getInstance()`
  `String`
  `getName()`
  `List<ASMTransformer>`
  `getTransformers()`
  Deprecated.
  Use `TransformableClassloader.getASMTransformers()` instead.
  `boolean`
  `isProtected(String name)`
  `boolean`
  `isThreadLoggingClassloadingFailures()`
  Obtains whether the current thread should be logging classloading-related exceptions for this specific classloader.
  `byte[]`
  `loadBytesWithChildren(String name, boolean transform)`
  Deprecated.
  `@NotNull Class<?>`
  `loadClass(@NotNull String name, boolean resolve)`
  `RawClassData`
  `loadClassBytes(String name, boolean transform)`
  Loads and possibly transforms class bytecode corresponding to the given binary name.
  `void`
  `loadModifier(ClassLoader modifierLoader, @NotNull String codeModifierClass)`
  `@NotNull URLClassLoader`
  `newChild(@NotNull URL... urls)`
  `void`
  `readAccessWidener(@NotNull InputStream in)`
  Deprecated.
  `MinestomRootClassLoader`
  `setThreadLoggingClassloadingFailures(boolean logFailures)`
  Sets whether the current thread should be logging classloading-related exceptions for this specific classloader.
  `@NotNull Class<?>`
  `transformAndDefineClass(@NotNull String className, @NotNull RawClassData data)`

  ### Methods inherited from class net.minestom.server.extras.selfmodification.HierarchyClassLoader

  `addChild, findLibrary, getResourceAsStreamWithChildren, getResourceAsURLWithChildren, removeChildInHierarchy`

  ### Methods inherited from class java.net.URLClassLoader

  `close, definePackage, findResource, findResources, getPermissions, getResourceAsStream, getURLs, newInstance, newInstance`

  ### Methods inherited from class java.security.SecureClassLoader

  `defineClass, defineClass`

  ### Methods inherited from class java.lang.ClassLoader

  `clearAssertionStatus, defineClass, defineClass, defineClass, defineClass, definePackage, findClass, findLoadedClass, findResource, findSystemClass, getClassLoadingLock, getDefinedPackage, getDefinedPackages, getPackage, getPackages, getParent, getPlatformClassLoader, getResource, getResources, getSystemClassLoader, getSystemResource, getSystemResourceAsStream, getSystemResources, getUnnamedModule, isRegisteredAsParallelCapable, loadClass, registerAsParallelCapable, resolveClass, resources, setClassAssertionStatus, setDefaultAssertionStatus, setPackageAssertionStatus, setSigners`

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### DEBUG

    @Internal public static final boolean DEBUG

  - ### protectedPackages

    public final Set<String> protectedPackages

- ## Method Details

  - ### getInstance

    public static MinestomRootClassLoader getInstance()

  - ### loadClass

    @NotNull public @NotNull Class<?> loadClass(@NotNull @NotNull String name, boolean resolve) throws ClassNotFoundException
    Overrides:
      `loadClass` in class `ClassLoader`
    Throws:
      `ClassNotFoundException`

  - ### isProtected

    @Contract(pure=true) @AvailableSince("4.0.0-a20241104") public boolean isProtected(String name)

  - ### isThreadLoggingClassloadingFailures

    @Contract(pure=true) @AvailableSince("4.0.0-a20240730") public boolean isThreadLoggingClassloadingFailures()
    Description copied from interface: `TransformableClassloader`
    Obtains whether the current thread should be logging classloading-related exceptions for this specific classloader. This may relate to class transformation issues, I/O issues, illegal bytecode among other potential causes. The reason SLL logs these kinds of issues by default is that at times the exceptions that are thrown by the classloader are completely absorbed by the caller. This very easily results in rather hard to trace issues as people will usually not expect a classloading failure as the cause of a bug. This is especially relevant in asynchronous environments where exception swallowing is already very likely in conjunction with faulty ASM Transformers resulting in either a transformation failure or illegal bytecode to be emitted.

    Regardless of this setting, the classloader will always rethrow the exception (or wrap it appropriately, attaching necessary debug info if applicable). By default this setting is set to `true` and is on a per-thread basis, that is the value is backed by a `ThreadLocal` and will thus have concurrency behaviours that align with those of `ThreadLocal`.

    Reasons why this setting may be disabled is either because failures are expected (as is the case in the micromixin test framework for example) or because the thrown exceptions are already being logged and no duplication should occur. Generally disabling logging of these issues should be temporary in nature only where it acutely applies.

    Specified by:
      `isThreadLoggingClassloadingFailures` in interface `TransformableClassloader`
    Returns:
      Whether the current thread should log classloading failures explicitly.

  - ### loadClassBytes

    public RawClassData loadClassBytes(String name, boolean transform) throws IOException, ClassNotFoundException
    Loads and possibly transforms class bytecode corresponding to the given binary name.
    Parameters:
      `name` -
      `transform` -
    Returns:
      The transformed bytes attached with the URL the bytes were loaded from.
    Throws:
      `IOException`
      `ClassNotFoundException`
    Since:
      3.1.0

  - ### loadBytesWithChildren

    @Deprecated public byte[] loadBytesWithChildren(String name, boolean transform) throws IOException, ClassNotFoundException
    Deprecated.
    Throws:
      `IOException`
      `ClassNotFoundException`

  - ### findClass

    public Class<?> findClass(String name) throws ClassNotFoundException
    Overrides:
      `findClass` in class `URLClassLoader`
    Throws:
      `ClassNotFoundException`

  - ### newChild

    @NotNull @Internal public @NotNull URLClassLoader newChild(@NotNull @NotNull URL... urls)

  - ### loadModifier

    @Internal public void loadModifier(ClassLoader modifierLoader, @NotNull @NotNull String codeModifierClass)

  - ### addTransformer

    @Deprecated @ScheduledForRemoval(inVersion="5.0.0") public void addTransformer(ASMTransformer transformer)
    Deprecated.
    Adds a transformer to the transformer pool.
    Parameters:
      `transformer` - The transformer to add
    Since:
      2.1.0

  - ### addURL

    public void addURL(URL url)
    Overrides:
      `addURL` in class `URLClassLoader`

  - ### getTransformers

    @Deprecated @ScheduledForRemoval(inVersion="5.0.0") public List<ASMTransformer> getTransformers()
    Deprecated.
    Use `TransformableClassloader.getASMTransformers()` instead.
    Obtains a clone of the list of ASM Transformers currently in use.
    Returns:
      The ASM transformers in use.
    Since:
      2.1.0

  - ### readAccessWidener

    @Deprecated @ScheduledForRemoval(inVersion="5.0.0") public void readAccessWidener(@NotNull @NotNull InputStream in) throws IOException
    Deprecated.
    Throws:
      `IOException`

  - ### setThreadLoggingClassloadingFailures

    @Contract(pure=false, value="_ -> this") @AvailableSince("4.0.0-a20240730") public MinestomRootClassLoader setThreadLoggingClassloadingFailures(boolean logFailures)
    Description copied from interface: `TransformableClassloader`
    Sets whether the current thread should be logging classloading-related exceptions for this specific classloader. This may relate to class transformation issues, I/O issues, illegal bytecode among other potential causes. The reason SLL logs these kinds of issues by default is that at times the exceptions that are thrown by the classloader are completely absorbed by the caller. This very easily results in rather hard to trace issues as people will usually not expect a classloading failure as the cause of a bug. This is especially relevant in asynchronous environments where exception swallowing is already very likely in conjunction with faulty ASM Transformers resulting in either a transformation failure or illegal bytecode to be emitted.

    Regardless of this setting, the classloader will always rethrow the exception (or wrap it appropriately, attaching necessary debug info if applicable). By default this setting is set to `true` and is on a per-thread basis, that is the value is backed by a `ThreadLocal` and will thus have concurrency behaviours that align with those of `ThreadLocal`.

    Reasons why this setting may be disabled is either because failures are expected (as is the case in the micromixin test framework for example) or because the thrown exceptions are already being logged and no duplication should occur. Generally disabling logging of these issues should be temporary in nature only where it acutely applies.

    Specified by:
      `setThreadLoggingClassloadingFailures` in interface `TransformableClassloader`
    Parameters:
      `logFailures` - Whether the current thread should log classloading failures explicitly.
    Returns:
      The current `TransformableClassloader` instance, for chaining.

  - ### addASMTransformer

    @Contract(pure=false, mutates="this") @AvailableSince("4.0.0-a20231223") public void addASMTransformer(@NotNull @NotNull ASMTransformer transformer)
    Specified by:
      `addASMTransformer` in interface `TransformableClassloader`

  - ### getASMTransformers

    @NotNull @Contract(pure=true, value="-> new") @AvailableSince("4.0.0-a20231223") public @NotNull @Unmodifiable Collection<@NotNull ASMTransformer> getASMTransformers()
    Specified by:
      `getASMTransformers` in interface `TransformableClassloader`

  - ### getClassCodeSourceURI

    @Nullable @Contract(pure=true) @AvailableSince("4.0.0-a20250819") @Experimental public @Nullable URI getClassCodeSourceURI(@NotNull @NotNull String internalName)
    Obtain the code source URI of the class, as per `CodeSource.getLocation()`. If the location is unknown, or if the class was not defined by this classloader, nor by any of it's children, then the returned value may be `null`.

    This method is mainly intended to be used for debugging purposes, or in more concrete terms, to aid tools used for debugging, such as IDEs or profilers. Perhaps however you will find a different use for this method, who knows?

    This method is experimental. It was added for a rather narrow usecase, which might vanish or prove to be irrelevant in the future. Handle with care, and be more keen on sharing feedback with the SLL developers when using this method.

    If multiple classes declare multiple classes with the same name, then the result is undefined. This may especially impact shaded libraries. If needed, it may be beneficial to instead obtain the source through the `protection domain` of a class via `ProtectionDomain.getCodeSource()` and then `CodeSource.getLocation()`. That approach however would involve reflection and would be slower and may have different usecases compared to this method as it implies that the classloader is already precisely known.

    Parameters:
      `internalName` - The internal name of the class, as per `Type.getInternalName()`.
    Returns:
      The `URI` where the given class is located in, following the paradigms of `CodeSource.getLocation()`. For classes located inside JARs, the URI of the jar will be used. For classes within directories, the URI of the directory is used (i.e. `file://bin/` for `file://bin/com/example/Main.class`). If the location of the class file is unknown or cannot be represented as an `URI`, `null` is used.

  - ### transformAndDefineClass

    @NotNull @Contract(pure=false) @CheckReturnValue @AvailableSince("4.0.0-a20231223") public @NotNull Class<?> transformAndDefineClass(@NotNull @NotNull String className, @NotNull @NotNull RawClassData data)
    Specified by:
      `transformAndDefineClass` in interface `TransformableClassloader`

  - ### getName

    public String getName()
    Overrides:
      `getName` in class `ClassLoader`