Package de.geolykt.starloader.transformers

# Interface TransformableClassloader

All Known Implementing Classes:
  `MinestomRootClassLoader`

@AvailableSince("4.0.0-a20231223") public interface TransformableClassloader
Interface that should be applied on implementations of `ClassLoader` to mark that they can be transformed via `ASM Transformers`.

This interface exists for abstraction reasons, as SLL's classloader classes will not exist in the minestom package forever - that is, the package in which they exist will be renamed with SLL 5.

When implementing your own classloader, you are encouraged to implement this interface for compatibility reasons.

Since:
  4.0.0-a20231223

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addASMTransformer(@NotNull ASMTransformer transformer)`
  `@NotNull @Unmodifiable Collection<@NotNull ASMTransformer>`
  `getASMTransformers()`
  `boolean`
  `isThreadLoggingClassloadingFailures()`
  Obtains whether the current thread should be logging classloading-related exceptions for this specific classloader.
  `TransformableClassloader`
  `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)`

- ## Method Details

  - ### addASMTransformer

    @Contract(pure=false, mutates="this") @AvailableSince("4.0.0-a20231223") void addASMTransformer(@NotNull @NotNull ASMTransformer transformer)

  - ### getASMTransformers

    @NotNull @Contract(pure=true, value="-> new") @AvailableSince("4.0.0-a20231223") @NotNull @Unmodifiable Collection<@NotNull ASMTransformer> getASMTransformers()

  - ### isThreadLoggingClassloadingFailures

    @Contract(pure=true) @AvailableSince("4.0.0-a20240730") boolean isThreadLoggingClassloadingFailures()
    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.

    Returns:
      Whether the current thread should log classloading failures explicitly.
    Since:
      4.0.0-a20240730

  - ### setThreadLoggingClassloadingFailures

    @Contract(pure=false, value="_ -> this") @AvailableSince("4.0.0-a20240730") TransformableClassloader setThreadLoggingClassloadingFailures(boolean logFailures)
    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.

    Parameters:
      `logFailures` - Whether the current thread should log classloading failures explicitly.
    Returns:
      The current `TransformableClassloader` instance, for chaining.
    Since:
      4.0.0-a20240730

  - ### transformAndDefineClass

    @NotNull @Contract(pure=false) @CheckReturnValue @AvailableSince("4.0.0-a20231223") @NotNull Class<?> transformAndDefineClass(@NotNull @NotNull String className, @NotNull @NotNull RawClassData data)