Class 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 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.1") 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()
      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