Spectral Powered Mixin contains a Mixin style injector framework in order to modify bytecode in a scalable way. Mixin also provides a simple injector setup solution via a gradle plugin handling the build-time injection and configurations.
Introduction • Installation • Usage • Documentation • Issue?
This mixin framework library provides> simple APIs/functions/methods to handle a mixin based approach to bytecode modifications.
- Annotation based raw injections
- Runtime / Compile Time injectors
- Simple gradle plugin configuration
- Easy Api injection
- Smart multi Mixin class merging
Add to settings.gradle
pluginManagement {
repositories {
gradlePluginPortal()
maven(url = "https://maven.spectralpowered.org/")
}
}
Add to build.gradle
plugins {
id("org.spectralpowered.mixin.plugin") version "0.1.0"
}
repositories {
mavenCentral()
maven(url = "https://maven.spectralpowered.org/")
}
To setup the mixin injector configurations.
dependencies {
// The project / dependency containing your mixins
mixin(project(":my-mixin-module"))
// The project / dependency containing your minxin api
mixinApi(project(":my-api"))
// The project / dependency you want to inject into
inject(project(":my-injection-target"))
}
Mixin dependencies:
dependencies {
// Includes Everything Normally Needed
implementation("org.spectralpowered:mixin:0.1.0")
// Explicit Mixin modules
implementation("org.spectralpowered:mixin-injector:0.1.0")
implementation("org.spectralpowered:mixin-annotations:0.1.0")
implementation("org.spectralpowered:mixin-asm:0.1.0")
}
Mixin Class example:
@Mixin(Test.class)
public abstract class TestMixin implements TestApi {
@Shadow
private abstract void shadow$testMethod();
private void myCustomLogic() {
System.out.println("Hello from TestMixin!");
}
@Overwrite
@Override
public void testMethod() {
this.myCustomLogic();
this.shadow$testMethod();
}
}
Target Class Example:
public class Test {
public void testMethod() {
System.out.println("Hello from original Test class.");
}
}
Api Class Example:
interface TestApi {
void testMethod();
}
When you build or run the module/project with the mixin gradle plugin applied. There will be an embedded jar file put in the resources of your sourceSet at compileTime containing the injected target jar.
my-app/
├─ org.myapp.app/
│ ├─ App.class
│ ├─ Other.class
├─ target.injected.jar
This injected jar target.injected.jar
can simply be loaded into a classloader. See example below.
object App {
@JvmStatic
fun main(args: Array<String>) {
println("Starting app.")
val classLoader = URLClassLoader(arrayOf(App::class.java.getResource("/target.injected.jar")!!.toURI().toURL()))
val testKlass = classLoader.loadClass("myapp.TestClass") as Class<TestApi>
val testInstance = testKlass.getDeclaredConstructor().newInstance()
testInstance.testMethod()
}
}
The following main function will print the following to console:
Starting app.
Hello from TestMixin!
Hello from original Test class.