Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v6
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Build and check with Gradle Wrapper
run: ./gradlew check
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Gradle ASMifier Changelog

## Unreleased

- Adding support for any non-Java sources (tested with Kotlin).

## Version 1.2.0 (2025-03-05)

- Adding support for anonymous classes.
Expand Down
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
What it is
---

Convenience tool that converts `.java` files to [ASM](https://asm.ow2.io/) instructions by wrapping
Convenience tool that converts `.java` source files (and non-Java ones that still compile into JVM bytecode, such as
Kotlin's (`.kt`) ones, for example) to [ASM](https://asm.ow2.io/) instructions by wrapping
the [ASMifier](https://asm.ow2.io/javadoc/org/objectweb/asm/util/ASMifier.html) tool around a Gradle incremental task
that can convert multiple `.java` files at once.
that can convert multiple source files at once.

This tool, as well as [the one it's built upon](https://asm.ow2.io/javadoc/org/objectweb/asm/util/ASMifier.html), is
meant to be used as a development tool for anyone who'd like to check how does Java code translate into bytecode
meant to be used as a development tool for anyone who'd like to check how does source code translate into bytecode
instructions using [ASM](https://asm.ow2.io/).

What it is not
---

This is not a tool to generate production code. Its `.java` target files are in a separate location from the production
source files (similarly to the test sources, which are in a separate dir that isn't packaged into the production app).
This is not a tool to generate production code. Its source target files are in a separate location from the
production source files (similarly to the test sources, which are in a separate dir that isn't packaged into the
production app).

How to use
---
Expand Down Expand Up @@ -47,13 +49,16 @@ dependencies {
}
```

The `asmifier` dependency type is added by this plugin to ensure that its dependencies are separated from those of your
app (similarly to configurations such as `testImplementation` are only used for a specific purpose and not to get
packaged with your production code).
You can find the latest ASMifier version [here](https://central.sonatype.com/artifact/org.ow2.asm/asm-util).

> [!NOTE]
> The `asmifier` dependency type is added by this plugin to ensure that its dependencies are separated from those
> of your app (similarly to configurations such as `testImplementation` are only used for a specific purpose and not
> to get packaged with your production code).

### Add sources to transform

The `.java` sources that will be transformed by this plugin must be placed in a src dir named `asmifier`, as
The sources that will be transformed by this plugin must be placed in a src dir named `asmifier`, as
shown below.

```text
Expand All @@ -63,12 +68,12 @@ app/
│ ├─ main/
│ │ ├─ java/
│ ├─ asmifier/
│ │ ├─ java/ <-- Here is where the asmifier .java target files must be placed
│ │ ├─ java/ <-- Here is where the asmifier .java (or other JVM-supported) target files must be placed
```

### Run the Gradle task

To transform the `.java` target files you must run the gradle task named `asmifier`, like so:
To transform the source files you must run the Gradle task named `asmifier`, like so:

```shell
./gradlew asmifier
Expand Down
14 changes: 6 additions & 8 deletions asmifier-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ dependencies {
testImplementation(libs.assertj)
}

val javaVersion = JavaVersion.VERSION_11
java {
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

gradlePlugin {
Expand All @@ -31,17 +31,15 @@ gradlePlugin {
}
}

tasks.withType(Test::class.java) {
tasks.withType<Test> {
useJUnitPlatform()
systemProperty("asm_version", libs.versions.asm.get())
}
tasks.withType(JavaCompile::class.java) {
tasks.withType<JavaCompile> {
if (name.contains("test", true)) {
options.errorprone.isEnabled.set(false)
val testJavaVersion = JavaVersion.VERSION_15.toString()
sourceCompatibility = testJavaVersion
targetCompatibility = testJavaVersion
} else {
options.release = 11 // Ensuring deliverable jvm compatibility
options.errorprone {
check("NullAway", CheckSeverity.ERROR)
option("NullAway:AnnotatedPackages", "com.likethesalad.asm")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.likethesalad.asm;

import com.likethesalad.asm.tasks.AsmifierTask;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.file.Directory;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.Sync;
import org.gradle.api.tasks.TaskProvider;
import org.jetbrains.annotations.NotNull;

Expand All @@ -25,6 +26,16 @@ public void apply(Project project) {

Configuration asmifierClasspath = getAsmifierClasspath(project, asmifierSourceSet);

TaskProvider<Sync> asmifierTargetCollector =
project.getTasks().register("asmifierCollector", Sync.class);
asmifierTargetCollector.configure(
sync -> {
sync.from(
asmifierSourceSet.getOutput(),
copySpec -> copySpec.setIncludes(List.of("**/*.class")));
sync.into(project.getLayout().getBuildDirectory().dir("intermediates/" + sync.getName()));
});

TaskProvider<AsmifierTask> asmifierTaskTaskProvider =
project.getTasks().register(ASMIFIER_TASK_NAME, AsmifierTask.class);
asmifierTaskTaskProvider.configure(
Expand All @@ -36,9 +47,7 @@ public void apply(Project project) {
.getLayout()
.getBuildDirectory()
.dir("generated/sources/" + ASMIFIER_OUTPUT_DIR_NAME));
asmifierTask
.getTargetClasses()
.from(getTargetClassesCollection(project, asmifierSourceSet));
asmifierTask.getTargetClasses().from(asmifierTargetCollector);
asmifierTask.getClasspath().from(asmifierClasspath);
});

Expand All @@ -49,13 +58,6 @@ public void apply(Project project) {
asmifierTaskTaskProvider.flatMap(AsmifierTask::getOutputDir));
}

private static @NotNull FileCollection getTargetClassesCollection(
Project project, SourceSet asmifierSourceSet) {
return project
.files(asmifierSourceSet.getOutput())
.filter(element -> !element.getName().endsWith(".class"));
}

private static void configureDumpSourceSet(
Project project,
SourceSet asmifierSourceSet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void execute(InputChanges inputChanges) {
private void asmifyToFile(File outputFile, FileCollection classpath, String relativeSourcePath) {
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
asmify(classpath, relativeSourcePath, outputStream);
} catch (IOException e) {
} catch (Exception e) {
throw new RuntimeException(
"Exception during asmifier run where the source is: "
+ relativeSourcePath
Expand Down
Loading