From aa66b2f73a0b3a340059eac7916a22ef32a3cdb7 Mon Sep 17 00:00:00 2001
From: RaphiMC <50594595+RaphiMC@users.noreply.github.com>
Date: Mon, 4 Sep 2023 18:53:18 +0200
Subject: [PATCH] Implemented gradle plugin and cleaned up code Release 1.0.0
---
README.md | 41 ++++
build.gradle | 8 +
gradle-plugin/build.gradle | 5 +
gradle-plugin/gradle.properties | 1 +
.../gradle/task/DowngradeJarTask.java | 187 ++++++++++++++++++
.../gradle/task/DowngradeSourceSetTask.java | 141 +++++++++++++
gradle.properties | 2 +-
impl-classtransform/build.gradle | 5 +
impl-classtransform/gradle.properties | 1 +
.../JavaDowngraderTransformer.java | 24 ++-
.../classprovider}/AbstractClassProvider.java | 2 +-
.../ClosingFileSystemClassProvider.java | 2 +-
.../FileSystemClassProvider.java | 2 +-
.../classprovider}/LazyFileClassProvider.java | 10 +-
.../classprovider}/PathClassProvider.java | 10 +-
.../classtransform/util/ClassNameUtil.java | 23 ++-
.../classtransform/util/FileSystemUtil.java | 39 ++++
settings.gradle | 2 +
standalone/build.gradle | 11 +-
.../javadowngrader/standalone/Main.java | 94 ++++-----
.../standalone/util/CloseableSupplier.java | 49 -----
.../standalone/util/GeneralUtil.java | 36 +---
22 files changed, 532 insertions(+), 163 deletions(-)
create mode 100644 gradle-plugin/build.gradle
create mode 100644 gradle-plugin/gradle.properties
create mode 100644 gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeJarTask.java
create mode 100644 gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeSourceSetTask.java
create mode 100644 impl-classtransform/build.gradle
create mode 100644 impl-classtransform/gradle.properties
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform}/JavaDowngraderTransformer.java (70%)
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider}/AbstractClassProvider.java (96%)
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider}/ClosingFileSystemClassProvider.java (94%)
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider}/FileSystemClassProvider.java (94%)
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider}/LazyFileClassProvider.java (87%)
rename {standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider}/PathClassProvider.java (86%)
rename standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/Closeable.java => impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/ClassNameUtil.java (57%)
create mode 100644 impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/FileSystemUtil.java
delete mode 100644 standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/CloseableSupplier.java
diff --git a/README.md b/README.md
index 755aa5a..b3f5a9e 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,47 @@ Here is an example command to convert the jar input.jar to Java 8 and output it
## Usage (As a library)
To transform a ``ClassNode`` you can use the ``JavaDowngrader`` class.
As a low level class modification framework in your application [ClassTransform](https://github.com/Lenni0451/ClassTransform) is recommended.
+JavaDowngrader provides the ``impl-classtransform`` submodule which contains various utility classes for ClassTransform.
+
+## Usage (In Gradle)
+To use JavaDowngrader in gradle (To downgrade a whole jar or one of your source sets) you have to add the following to the top of your build.gradle:
+```groovy
+buildscript {
+ repositories {
+ maven {
+ name = "Lenni0451 Releases"
+ url "https://maven.lenni0451.net/releases"
+ }
+ }
+
+ dependencies {
+ classpath "net.raphimc.javadowngrader:gradle-plugin:1.0.0"
+ }
+}
+```
+
+### Downgrade the main source set
+```groovy
+tasks.register("java8Main", DowngradeSourceSetTask) {
+ sourceSet = sourceSets.main
+}.get().dependsOn("classes")
+classes.finalizedBy("java8Main")
+```
+
+### Downgrade the built jar (If you use Java 8+ libraries)
+```groovy
+tasks.register("java8Jar", DowngradeJarTask) {
+ input = tasks.jar.archiveFile.get().asFile
+ outputSuffix = "+java8"
+ compileClassPath = sourceSets.main.compileClasspath
+}.get().dependsOn("build")
+build.finalizedBy("java8Jar")
+```
+
+Some of the optional properties include:
+- ``targetVersion``: The target classfile version (Default: 8)
+- ``outputSuffix``: The suffix to append to the output jar file (Default: "-downgraded")
+- ``copyRuntimeClasses``: Whether to copy the JavaDowngrader runtime classes to the output jar (Default: true). Should be set to false if your jar already contains JavaDowngrader itself
## Contact
If you encounter any issues, please report them on the
diff --git a/build.gradle b/build.gradle
index e1fc53c..723a160 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,6 +14,14 @@ allprojects {
repositories {
mavenCentral()
+ maven {
+ name = "Lenni0451 Releases"
+ url "https://maven.lenni0451.net/releases"
+ }
+ maven {
+ name = "Lenni0451 Snapshots"
+ url "https://maven.lenni0451.net/snapshots"
+ }
}
java {
diff --git a/gradle-plugin/build.gradle b/gradle-plugin/build.gradle
new file mode 100644
index 0000000..40160c6
--- /dev/null
+++ b/gradle-plugin/build.gradle
@@ -0,0 +1,5 @@
+dependencies {
+ api project(":impl-classtransform")
+
+ implementation gradleApi()
+}
diff --git a/gradle-plugin/gradle.properties b/gradle-plugin/gradle.properties
new file mode 100644
index 0000000..dfa687a
--- /dev/null
+++ b/gradle-plugin/gradle.properties
@@ -0,0 +1 @@
+maven_name=gradle-plugin
diff --git a/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeJarTask.java b/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeJarTask.java
new file mode 100644
index 0000000..82d89e7
--- /dev/null
+++ b/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeJarTask.java
@@ -0,0 +1,187 @@
+/*
+ * This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
+ * Copyright (C) 2023 RK_01/RaphiMC and contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package net.raphimc.javadowngrader.gradle.task;
+
+import net.lenni0451.classtransform.TransformerManager;
+import net.lenni0451.classtransform.utils.tree.BasicClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.JavaDowngraderTransformer;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.LazyFileClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.PathClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.util.ClassNameUtil;
+import net.raphimc.javadowngrader.impl.classtransform.util.FileSystemUtil;
+import net.raphimc.javadowngrader.runtime.RuntimeRoot;
+import net.raphimc.javadowngrader.util.Constants;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.tasks.Internal;
+import org.gradle.api.tasks.TaskAction;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+public class DowngradeJarTask extends DefaultTask {
+
+ @Internal
+ private File input;
+
+ @Internal
+ private String outputSuffix = "-downgraded";
+
+ @Internal
+ private FileCollection compileClassPath;
+
+ @Internal
+ private int targetVersion = Opcodes.V1_8;
+
+ @Internal
+ private boolean copyRuntimeClasses = true;
+
+ @TaskAction
+ public void run() throws IOException, URISyntaxException {
+ Objects.requireNonNull(this.input, "input must be set");
+ Objects.requireNonNull(this.outputSuffix, "outputSuffix must be set");
+ Objects.requireNonNull(this.compileClassPath, "compileClassPath must be set");
+ if (!this.input.exists()) throw new IllegalArgumentException("input does not exist");
+ if (!this.input.isFile() || !this.input.getName().endsWith(".jar")) throw new IllegalArgumentException("input is not a jar file");
+
+ System.out.println("Downgrading jar: " + this.input.getName());
+ try (FileSystem inFs = FileSystems.newFileSystem(this.input.toPath(), null)) {
+ final Path inRoot = inFs.getRootDirectories().iterator().next();
+
+ final TransformerManager transformerManager = new TransformerManager(
+ new PathClassProvider(inRoot, new LazyFileClassProvider(this.compileClassPath.getFiles(), new BasicClassProvider()))
+ );
+ transformerManager.addBytecodeTransformer(new JavaDowngraderTransformer(
+ transformerManager, this.targetVersion, c -> Files.isRegularFile(inRoot.resolve(ClassNameUtil.toClassFilename(c)))
+ ));
+
+ final String outputName = this.input.getName().substring(0, this.input.getName().length() - 4) + this.outputSuffix;
+ final File outputFile = new File(this.input.getParentFile(), outputName + ".jar");
+
+ try (FileSystem outFs = FileSystems.newFileSystem(new URI("jar:" + outputFile.toURI()), Collections.singletonMap("create", "true"))) {
+ final Path outRoot = outFs.getRootDirectories().iterator().next();
+
+ // Downgrade classes
+ try (Stream stream = Files.walk(inRoot)) {
+ stream.forEach(path -> {
+ try {
+ final String relative = ClassNameUtil.slashName(inRoot.relativize(path));
+ final Path dest = outRoot.resolve(relative);
+ if (Files.isDirectory(path)) {
+ Files.createDirectories(dest);
+ return;
+ }
+ final Path parent = dest.getParent();
+ if (parent != null) {
+ Files.createDirectories(parent);
+ }
+ if (!relative.endsWith(".class") || relative.contains("META-INF/versions/")) {
+ Files.copy(path, dest);
+ return;
+ }
+ final String className = ClassNameUtil.toClassName(relative);
+ final byte[] bytecode = Files.readAllBytes(path);
+ final byte[] result;
+ try {
+ result = transformerManager.transform(className, bytecode);
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to transform " + className, e);
+ }
+ Files.write(dest, result != null ? result : bytecode);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+
+ // Copy runtime classes
+ if (this.copyRuntimeClasses) {
+ try (FileSystem runtimeRootFs = FileSystemUtil.getOrCreateFileSystem(RuntimeRoot.class.getResource("").toURI())) {
+ final Path runtimeRoot = runtimeRootFs.getPath(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE);
+ try (Stream stream = Files.walk(runtimeRoot)) {
+ stream.filter(Files::isRegularFile)
+ .filter(p -> !p.getFileName().toString().equals(Constants.JAVADOWNGRADER_RUNTIME_ROOT))
+ .forEach(path -> {
+ final String relative = ClassNameUtil.slashName(runtimeRoot.relativize(path));
+ final Path dest = outRoot.resolve(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE + relative);
+ try {
+ Files.createDirectories(dest.getParent());
+ Files.copy(path, dest);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public File getInput() {
+ return this.input;
+ }
+
+ public String getOutputSuffix() {
+ return this.outputSuffix;
+ }
+
+ public FileCollection getCompileClassPath() {
+ return this.compileClassPath;
+ }
+
+ public int getTargetVersion() {
+ return this.targetVersion;
+ }
+
+ public boolean getCopyRuntimeClasses() {
+ return this.copyRuntimeClasses;
+ }
+
+ public void setInput(final File input) {
+ this.input = input;
+ }
+
+ public void setOutputSuffix(final String outputSuffix) {
+ this.outputSuffix = outputSuffix;
+ }
+
+ public void setCompileClassPath(final FileCollection compileClassPath) {
+ this.compileClassPath = compileClassPath;
+ }
+
+ public void setTargetVersion(final int targetVersion) {
+ this.targetVersion = targetVersion;
+ }
+
+ public void setCopyRuntimeClasses(final boolean copyRuntimeClasses) {
+ this.copyRuntimeClasses = copyRuntimeClasses;
+ }
+
+}
diff --git a/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeSourceSetTask.java b/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeSourceSetTask.java
new file mode 100644
index 0000000..3d04617
--- /dev/null
+++ b/gradle-plugin/src/main/java/net/raphimc/javadowngrader/gradle/task/DowngradeSourceSetTask.java
@@ -0,0 +1,141 @@
+/*
+ * This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
+ * Copyright (C) 2023 RK_01/RaphiMC and contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package net.raphimc.javadowngrader.gradle.task;
+
+import net.lenni0451.classtransform.TransformerManager;
+import net.lenni0451.classtransform.utils.tree.BasicClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.JavaDowngraderTransformer;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.LazyFileClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.PathClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.util.ClassNameUtil;
+import net.raphimc.javadowngrader.impl.classtransform.util.FileSystemUtil;
+import net.raphimc.javadowngrader.runtime.RuntimeRoot;
+import net.raphimc.javadowngrader.util.Constants;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.tasks.Internal;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.TaskAction;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+public class DowngradeSourceSetTask extends DefaultTask {
+
+ @Internal
+ private SourceSet sourceSet;
+
+ @Internal
+ private int targetVersion = Opcodes.V1_8;
+
+ @Internal
+ private boolean copyRuntimeClasses = true;
+
+ @TaskAction
+ public void run() throws IOException, URISyntaxException {
+ Objects.requireNonNull(this.sourceSet, "sourceSet must be set");
+
+ for (File classesDir : this.sourceSet.getOutput().getClassesDirs()) {
+ System.out.println("Downgrading source set: " + this.getProject().getProjectDir().toPath().relativize(classesDir.toPath()));
+
+ final Path inRoot = classesDir.toPath();
+ final TransformerManager transformerManager = new TransformerManager(
+ new PathClassProvider(inRoot, new LazyFileClassProvider(this.sourceSet.getCompileClasspath().getFiles(), new BasicClassProvider()))
+ );
+ transformerManager.addBytecodeTransformer(new JavaDowngraderTransformer(
+ transformerManager, this.targetVersion, c -> Files.isRegularFile(inRoot.resolve(ClassNameUtil.toClassFilename(c)))
+ ));
+
+ // Downgrade classes
+ try (Stream stream = Files.walk(inRoot)) {
+ stream.forEach(path -> {
+ try {
+ final String relative = ClassNameUtil.slashName(inRoot.relativize(path));
+ if (!relative.endsWith(".class")) return;
+ final String className = ClassNameUtil.toClassName(relative);
+ final byte[] bytecode = Files.readAllBytes(path);
+ final byte[] result;
+ try {
+ result = transformerManager.transform(className, bytecode);
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to transform " + className, e);
+ }
+ if (result != null) {
+ Files.write(path, result);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+
+ // Copy runtime classes
+ if (this.copyRuntimeClasses) {
+ try (FileSystem runtimeRootFs = FileSystemUtil.getOrCreateFileSystem(RuntimeRoot.class.getResource("").toURI())) {
+ final Path runtimeRoot = runtimeRootFs.getPath(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE);
+ try (Stream stream = Files.walk(runtimeRoot)) {
+ stream.filter(Files::isRegularFile)
+ .filter(p -> !p.getFileName().toString().equals(Constants.JAVADOWNGRADER_RUNTIME_ROOT))
+ .forEach(path -> {
+ final String relative = ClassNameUtil.slashName(runtimeRoot.relativize(path));
+ final Path dest = inRoot.resolve(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE + relative);
+ try {
+ Files.createDirectories(dest.getParent());
+ Files.copy(path, dest);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ public SourceSet getSourceSet() {
+ return this.sourceSet;
+ }
+
+ public int getTargetVersion() {
+ return this.targetVersion;
+ }
+
+ public boolean getCopyRuntimeClasses() {
+ return this.copyRuntimeClasses;
+ }
+
+ public void setSourceSet(final SourceSet sourceSet) {
+ this.sourceSet = sourceSet;
+ }
+
+ public void setTargetVersion(final int targetVersion) {
+ this.targetVersion = targetVersion;
+ }
+
+ public void setCopyRuntimeClasses(final boolean copyRuntimeClasses) {
+ this.copyRuntimeClasses = copyRuntimeClasses;
+ }
+
+}
diff --git a/gradle.properties b/gradle.properties
index 095a8fe..09b9816 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,4 +4,4 @@ org.gradle.configureondemand=true
maven_group=net.raphimc.javadowngrader
maven_name=core
-maven_version=1.0.0-SNAPSHOT
+maven_version=1.0.0
diff --git a/impl-classtransform/build.gradle b/impl-classtransform/build.gradle
new file mode 100644
index 0000000..a49e525
--- /dev/null
+++ b/impl-classtransform/build.gradle
@@ -0,0 +1,5 @@
+dependencies {
+ api project(":")
+
+ api "net.lenni0451.classtransform:core:1.11.0-SNAPSHOT"
+}
diff --git a/impl-classtransform/gradle.properties b/impl-classtransform/gradle.properties
new file mode 100644
index 0000000..0b620df
--- /dev/null
+++ b/impl-classtransform/gradle.properties
@@ -0,0 +1 @@
+maven_name=impl-classtransform
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/JavaDowngraderTransformer.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/JavaDowngraderTransformer.java
similarity index 70%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/JavaDowngraderTransformer.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/JavaDowngraderTransformer.java
index c403efc..3484a56 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/JavaDowngraderTransformer.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/JavaDowngraderTransformer.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform;
import net.lenni0451.classtransform.TransformerManager;
import net.lenni0451.classtransform.transformer.IBytecodeTransformer;
@@ -28,10 +28,32 @@
public class JavaDowngraderTransformer implements IBytecodeTransformer {
+ public static final int NATIVE_CLASS_VERSION;
+
+ static {
+ final String classVersion = System.getProperty("java.class.version");
+ final String[] versions = classVersion.split("\\.");
+ final int majorVersion = Integer.parseInt(versions[0]);
+ final int minorVersion = Integer.parseInt(versions[1]);
+ NATIVE_CLASS_VERSION = minorVersion << 16 | majorVersion;
+ }
+
private final TransformerManager transformerManager;
private final int targetVersion;
private final Predicate classFilter;
+ public JavaDowngraderTransformer(final TransformerManager transformerManager) {
+ this(transformerManager, NATIVE_CLASS_VERSION);
+ }
+
+ public JavaDowngraderTransformer(final TransformerManager transformerManager, final int targetVersion) {
+ this(transformerManager, targetVersion, s -> true);
+ }
+
+ public JavaDowngraderTransformer(final TransformerManager transformerManager, final Predicate classFilter) {
+ this(transformerManager, NATIVE_CLASS_VERSION, classFilter);
+ }
+
public JavaDowngraderTransformer(final TransformerManager transformerManager, final int targetVersion, final Predicate classFilter) {
this.transformerManager = transformerManager;
this.targetVersion = targetVersion;
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/AbstractClassProvider.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/AbstractClassProvider.java
similarity index 96%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/AbstractClassProvider.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/AbstractClassProvider.java
index 6f13d0f..9b58ad7 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/AbstractClassProvider.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/AbstractClassProvider.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform.classprovider;
import net.lenni0451.classtransform.utils.tree.IClassProvider;
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/ClosingFileSystemClassProvider.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/ClosingFileSystemClassProvider.java
similarity index 94%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/ClosingFileSystemClassProvider.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/ClosingFileSystemClassProvider.java
index f78f813..16480f9 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/ClosingFileSystemClassProvider.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/ClosingFileSystemClassProvider.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform.classprovider;
import net.lenni0451.classtransform.utils.tree.IClassProvider;
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/FileSystemClassProvider.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/FileSystemClassProvider.java
similarity index 94%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/FileSystemClassProvider.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/FileSystemClassProvider.java
index e54f8df..f990c95 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/FileSystemClassProvider.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/FileSystemClassProvider.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform.classprovider;
import net.lenni0451.classtransform.utils.tree.IClassProvider;
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/LazyFileClassProvider.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/LazyFileClassProvider.java
similarity index 87%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/LazyFileClassProvider.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/LazyFileClassProvider.java
index 6436eba..8c4b9db 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/LazyFileClassProvider.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/LazyFileClassProvider.java
@@ -15,19 +15,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform.classprovider;
import net.lenni0451.classtransform.utils.tree.IClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.util.FileSystemUtil;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.nio.file.FileSystemAlreadyExistsException;
-import java.nio.file.FileSystems;
import java.util.Collection;
-import java.util.Collections;
import java.util.NoSuchElementException;
public class LazyFileClassProvider extends AbstractClassProvider implements AutoCloseable {
@@ -68,9 +66,7 @@ private static PathClassProvider open(final File file) {
}
try {
- return new ClosingFileSystemClassProvider(FileSystems.newFileSystem(uri, Collections.emptyMap()), null);
- } catch (FileSystemAlreadyExistsException e) {
- return new FileSystemClassProvider(FileSystems.getFileSystem(uri), null);
+ return new ClosingFileSystemClassProvider(FileSystemUtil.getOrCreateFileSystem(uri), null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/PathClassProvider.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/PathClassProvider.java
similarity index 86%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/PathClassProvider.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/PathClassProvider.java
index 9babce7..3f7d6e4 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/transform/PathClassProvider.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/PathClassProvider.java
@@ -15,10 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.transform;
+package net.raphimc.javadowngrader.impl.classtransform.classprovider;
import net.lenni0451.classtransform.utils.tree.IClassProvider;
-import net.raphimc.javadowngrader.standalone.util.GeneralUtil;
+import net.raphimc.javadowngrader.impl.classtransform.util.ClassNameUtil;
import java.io.IOException;
import java.io.UncheckedIOException;
@@ -41,7 +41,7 @@ public PathClassProvider(final Path root, final IClassProvider parent) {
@Override
public byte[] getClass(String name) {
- final Path path = this.root.resolve(GeneralUtil.toClassFilename(name));
+ final Path path = this.root.resolve(ClassNameUtil.toClassFilename(name));
if (Files.exists(path)) {
try {
return Files.readAllBytes(path);
@@ -62,7 +62,7 @@ public Map> getAllClasses() {
.filter(Files::isRegularFile)
.filter(f -> f.getFileName().endsWith(".class"))
.collect(Collectors.toMap(
- p -> GeneralUtil.toClassName(GeneralUtil.slashName(this.root.relativize(p))),
+ p -> ClassNameUtil.toClassName(ClassNameUtil.slashName(this.root.relativize(p))),
p -> () -> {
try {
return Files.readAllBytes(p);
@@ -78,7 +78,7 @@ public Map> getAllClasses() {
}
@SafeVarargs
- public static Map merge(final Map map, final Map... others) {
+ private static Map merge(final Map map, final Map... others) {
final Map newMap = new HashMap<>(map);
for (Map other : others) newMap.putAll(other);
return newMap;
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/Closeable.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/ClassNameUtil.java
similarity index 57%
rename from standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/Closeable.java
rename to impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/ClassNameUtil.java
index 542780a..437da3d 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/Closeable.java
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/ClassNameUtil.java
@@ -15,17 +15,24 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package net.raphimc.javadowngrader.standalone.util;
+package net.raphimc.javadowngrader.impl.classtransform.util;
-public interface Closeable extends AutoCloseable {
- @Override
- void close() throws E;
+import net.lenni0451.classtransform.utils.ASMUtils;
- static Closeable ofRunnable(Runnable run) {
- return run::run;
+import java.nio.file.Path;
+
+public class ClassNameUtil {
+
+ public static String toClassFilename(final String className) {
+ return ASMUtils.slash(className).concat(".class");
}
- static Closeable none() {
- return () -> {};
+ public static String toClassName(final String classFilename) {
+ return ASMUtils.dot(classFilename.substring(0, classFilename.length() - 6));
}
+
+ public static String slashName(final Path path) {
+ return path.toString().replace(path.getFileSystem().getSeparator(), "/");
+ }
+
}
diff --git a/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/FileSystemUtil.java b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/FileSystemUtil.java
new file mode 100644
index 0000000..f2944cd
--- /dev/null
+++ b/impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/util/FileSystemUtil.java
@@ -0,0 +1,39 @@
+/*
+ * This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
+ * Copyright (C) 2023 RK_01/RaphiMC and contributors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package net.raphimc.javadowngrader.impl.classtransform.util;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.FileSystems;
+import java.util.Collections;
+
+public class FileSystemUtil {
+
+ public static FileSystem getOrCreateFileSystem(final URI uri) throws IOException {
+ FileSystem fileSystem;
+ try {
+ fileSystem = FileSystems.getFileSystem(uri);
+ } catch (FileSystemNotFoundException e) {
+ fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
+ }
+ return fileSystem;
+ }
+
+}
diff --git a/settings.gradle b/settings.gradle
index 3c577fb..f28cc28 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,3 +9,5 @@ rootProject.name = "JavaDowngrader"
include(":standalone")
include(":runtime-dep")
+include(":impl-classtransform")
+include(":gradle-plugin")
diff --git a/standalone/build.gradle b/standalone/build.gradle
index 64db375..22be540 100644
--- a/standalone/build.gradle
+++ b/standalone/build.gradle
@@ -10,17 +10,8 @@ configurations {
api.extendsFrom include
}
-repositories {
- maven {
- name = "Lenni0451 Releases"
- url "https://maven.lenni0451.net/releases"
- }
-}
-
dependencies {
- include project(":")
-
- include "net.lenni0451.classtransform:core:1.10.1"
+ include project(":impl-classtransform")
include "net.sf.jopt-simple:jopt-simple:5.0.4"
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/Main.java b/standalone/src/main/java/net/raphimc/javadowngrader/standalone/Main.java
index 5434396..f66580c 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/Main.java
+++ b/standalone/src/main/java/net/raphimc/javadowngrader/standalone/Main.java
@@ -22,11 +22,13 @@
import me.tongfei.progressbar.ProgressBarStyle;
import net.lenni0451.classtransform.TransformerManager;
import net.lenni0451.classtransform.utils.tree.BasicClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.JavaDowngraderTransformer;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.LazyFileClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.classprovider.PathClassProvider;
+import net.raphimc.javadowngrader.impl.classtransform.util.ClassNameUtil;
+import net.raphimc.javadowngrader.impl.classtransform.util.FileSystemUtil;
+import net.raphimc.javadowngrader.runtime.RuntimeRoot;
import net.raphimc.javadowngrader.standalone.progress.MultiThreadedProgressBar;
-import net.raphimc.javadowngrader.standalone.transform.JavaDowngraderTransformer;
-import net.raphimc.javadowngrader.standalone.transform.LazyFileClassProvider;
-import net.raphimc.javadowngrader.standalone.transform.PathClassProvider;
-import net.raphimc.javadowngrader.standalone.util.CloseableSupplier;
import net.raphimc.javadowngrader.standalone.util.GeneralUtil;
import net.raphimc.javadowngrader.util.Constants;
import org.slf4j.Logger;
@@ -76,9 +78,9 @@ public static void main(String[] args) throws Throwable {
.withRequiredArg()
.withValuesConvertedBy(new PathConverter());
final OptionSpec threadCount = parser.acceptsAll(asList("thread_count", "threads", "t"), "The number of threads to use for the downgrading")
- .withRequiredArg()
- .ofType(Integer.class)
- .defaultsTo(Math.min(Runtime.getRuntime().availableProcessors(), 255));
+ .withRequiredArg()
+ .ofType(Integer.class)
+ .defaultsTo(Math.min(Runtime.getRuntime().availableProcessors(), 255));
final OptionSet options;
try {
@@ -117,10 +119,10 @@ public static void main(String[] args) throws Throwable {
try {
final long start = System.nanoTime();
doConversion(
- inputFile, outputFile,
- options.valueOf(version),
- GeneralUtil.flatten(options.valuesOf(libraryPath)),
- Math.min(options.valueOf(threadCount), 255)
+ inputFile, outputFile,
+ options.valueOf(version),
+ GeneralUtil.flatten(options.valuesOf(libraryPath)),
+ Math.min(options.valueOf(threadCount), 255)
);
final long end = System.nanoTime();
LOGGER.info(
@@ -176,60 +178,41 @@ private static void doConversion(
LOGGER.info("Opening source JAR");
try (FileSystem inFs = FileSystems.newFileSystem(inputFile.toPath(), null)) {
final Path inRoot = inFs.getRootDirectories().iterator().next();
+
final TransformerManager transformerManager = new TransformerManager(
new PathClassProvider(inRoot, new LazyFileClassProvider(libraryPath, new BasicClassProvider()))
);
transformerManager.addBytecodeTransformer(new JavaDowngraderTransformer(
- transformerManager, targetVersion.getVersion(),
- c -> Files.isRegularFile(inRoot.resolve(GeneralUtil.toClassFilename(c)))
+ transformerManager, targetVersion.getVersion(), c -> Files.isRegularFile(inRoot.resolve(ClassNameUtil.toClassFilename(c)))
));
try (FileSystem outFs = FileSystems.newFileSystem(new URI("jar:" + outputFile.toURI()), Collections.singletonMap("create", "true"))) {
final Path outRoot = outFs.getRootDirectories().iterator().next();
- LOGGER.info("Copying runtime classes");
- try (CloseableSupplier supplier = GeneralUtil.getPath(Main.class.getResource(
- '/' + Constants.JAVADOWNGRADER_RUNTIME_PACKAGE + Constants.JAVADOWNGRADER_RUNTIME_ROOT
- ).toURI())) {
- final Path runtimeRoot = supplier.get().getParent();
- try (Stream stream = Files.walk(runtimeRoot)) {
- stream.filter(Files::isRegularFile)
- .filter(p -> !p.getFileName().toString().equals(Constants.JAVADOWNGRADER_RUNTIME_ROOT))
- .forEach(p -> {
- final String relative = GeneralUtil.slashName(runtimeRoot.relativize(p));
- final Path dest = outRoot.resolve(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE + relative);
- try {
- Files.createDirectories(dest.getParent());
- Files.copy(p, dest);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- }
- }
+
LOGGER.info("Downgrading classes with {} thread(s)", threadCount);
final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
final List> tasks;
final MultiThreadedProgressBar[] pb = new MultiThreadedProgressBar[1];
try (Stream stream = Files.walk(inRoot)) {
tasks = stream.map(path -> (Callable) () -> {
- final String relative = GeneralUtil.slashName(inRoot.relativize(path));
+ final String relative = ClassNameUtil.slashName(inRoot.relativize(path));
pb[0].setThreadTask(relative);
- final Path inOther = outRoot.resolve(relative);
+ final Path dest = outRoot.resolve(relative);
if (Files.isDirectory(path)) {
- Files.createDirectories(inOther);
+ Files.createDirectories(dest);
pb[0].step();
return null;
}
- final Path parent = inOther.getParent();
+ final Path parent = dest.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
- if (!relative.endsWith(".class")) {
- Files.copy(path, inOther);
+ if (!relative.endsWith(".class") || relative.contains("META-INF/versions/")) {
+ Files.copy(path, dest);
pb[0].step();
return null;
}
- final String className = GeneralUtil.toClassName(relative);
+ final String className = ClassNameUtil.toClassName(relative);
final byte[] bytecode = Files.readAllBytes(path);
byte[] result = null;
try {
@@ -237,7 +220,7 @@ private static void doConversion(
} catch (Exception e) {
LOGGER.error("Failed to transform {}", className, e);
}
- Files.write(inOther, result != null ? result : bytecode);
+ Files.write(dest, result != null ? result : bytecode);
pb[0].step();
return null;
@@ -245,11 +228,11 @@ private static void doConversion(
}
try {
pb[0] = MultiThreadedProgressBar.create(
- new ProgressBarBuilder()
- .setTaskName("Downgrading")
- .setStyle(ProgressBarStyle.ASCII)
- .setInitialMax(tasks.size())
- .setUpdateIntervalMillis(100)
+ new ProgressBarBuilder()
+ .setTaskName("Downgrading")
+ .setStyle(ProgressBarStyle.ASCII)
+ .setInitialMax(tasks.size())
+ .setUpdateIntervalMillis(100)
);
threadPool.invokeAll(tasks);
} finally {
@@ -261,6 +244,25 @@ private static void doConversion(
if (!threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
throw new IllegalStateException("Thread pool didn't shutdown correctly");
}
+
+ LOGGER.info("Copying runtime classes");
+ try (FileSystem runtimeRootFs = FileSystemUtil.getOrCreateFileSystem(RuntimeRoot.class.getResource("").toURI())) {
+ final Path runtimeRoot = runtimeRootFs.getPath(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE);
+ try (Stream stream = Files.walk(runtimeRoot)) {
+ stream.filter(Files::isRegularFile)
+ .filter(p -> !p.getFileName().toString().equals(Constants.JAVADOWNGRADER_RUNTIME_ROOT))
+ .forEach(path -> {
+ final String relative = ClassNameUtil.slashName(runtimeRoot.relativize(path));
+ final Path dest = outRoot.resolve(Constants.JAVADOWNGRADER_RUNTIME_PACKAGE + relative);
+ try {
+ Files.createDirectories(dest.getParent());
+ Files.copy(path, dest);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+ }
LOGGER.info("Writing final JAR");
}
}
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/CloseableSupplier.java b/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/CloseableSupplier.java
deleted file mode 100644
index 7d74a5d..0000000
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/CloseableSupplier.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
- * Copyright (C) 2023 RK_01/RaphiMC and contributors
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package net.raphimc.javadowngrader.standalone.util;
-
-import java.util.function.Supplier;
-
-public interface CloseableSupplier extends Supplier, Closeable {
-
- static CloseableSupplier of(Supplier supplier, Closeable closeable) {
- return new CloseableSupplier() {
- @Override
- public void close() throws E {
- closeable.close();
- }
-
- @Override
- public T get() {
- return supplier.get();
- }
- };
- }
-
- static CloseableSupplier of(Supplier supplier) {
- return of(supplier, Closeable.none());
- }
-
- static CloseableSupplier ofValue(T value, Closeable closeable) {
- return of(() -> value, closeable);
- }
-
- static CloseableSupplier ofValue(T value) {
- return ofValue(value, Closeable.none());
- }
-}
diff --git a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/GeneralUtil.java b/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/GeneralUtil.java
index cb2029c..00c65a0 100644
--- a/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/GeneralUtil.java
+++ b/standalone/src/main/java/net/raphimc/javadowngrader/standalone/util/GeneralUtil.java
@@ -17,45 +17,15 @@
*/
package net.raphimc.javadowngrader.standalone.util;
-import net.lenni0451.classtransform.utils.ASMUtils;
-
-import java.io.IOException;
-import java.net.URI;
-import java.nio.file.*;
-import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class GeneralUtil {
+
public static List flatten(List> list) {
return list.stream()
- .flatMap(List::stream)
- .collect(Collectors.toList());
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
}
- public static String toClassFilename(String className) {
- return ASMUtils.slash(className).concat(".class");
- }
-
- public static String toClassName(String classFilename) {
- return ASMUtils.dot(classFilename.substring(0, classFilename.length() - 6));
- }
-
- public static String slashName(Path path) {
- final String separator = path.getFileSystem().getSeparator();
- if (separator.equals("/")) {
- return path.toString();
- }
- return path.toString().replace(separator, "/");
- }
-
- @SuppressWarnings("DuplicateExpressions")
- public static CloseableSupplier getPath(URI uri) throws IOException {
- try {
- return CloseableSupplier.ofValue(Paths.get(uri));
- } catch (FileSystemNotFoundException e) {
- final FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
- return CloseableSupplier.ofValue(Paths.get(uri), fs::close);
- }
- }
}