package de.geolykt.starloader.transformers; import java.util.Collection; import org.jetbrains.annotations.ApiStatus.AvailableSince; import org.jetbrains.annotations.CheckReturnValue; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Unmodifiable; /** * Interface that should be applied on implementations of {@link ClassLoader} to mark that they can be * transformed via {@link ASMTransformer 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 */ @AvailableSince(value = "4.0.0-a20231223") public interface TransformableClassloader { @Contract(pure = false, mutates = "this") @AvailableSince(value = "4.0.0-a20231223") void addASMTransformer(@NotNull ASMTransformer transformer); @NotNull @Unmodifiable @Contract(pure = true, value = "-> new") @AvailableSince(value = "4.0.0-a20231223") Collection<@NotNull ASMTransformer> getASMTransformers(); /** * 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 {@link ThreadLocal} and will thus have concurrency
* behaviours that align with those of {@link 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. * * @return Whether the current thread should log classloading failures explicitly. * @since 4.0.0-a20240730 */ @Contract(pure = true) @AvailableSince(value = "4.0.0-a20240730") boolean isThreadLoggingClassloadingFailures(); /** * 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 {@link ThreadLocal} and will thus have concurrency
* behaviours that align with those of {@link 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. * * @param logFailures Whether the current thread should log classloading failures explicitly. * @return The current {@link TransformableClassloader} instance, for chaining. * @since 4.0.0-a20240730 */ @Contract(pure = false, value = "_ -> this") @AvailableSince(value = "4.0.0-a20240730") TransformableClassloader setThreadLoggingClassloadingFailures(boolean logFailures); @NotNull @Contract(pure = false) @CheckReturnValue @AvailableSince(value = "4.0.0-a20231223") Class> transformAndDefineClass(@NotNull String className, @NotNull RawClassData data); }