From 96159162a60e18f43e94fe83bf4f26cf21b5b893 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Mon, 8 Jul 2024 10:14:39 -0500 Subject: [PATCH 01/15] ignore warning option --- .../jvmdg/gradle/JVMDowngraderExtension.kt | 32 ++- .../jvmdg/gradle/flags/DowngradeFlags.kt | 76 +++++- .../jvmdg/gradle/task/DowngradeJar.kt | 7 +- .../wagyourtail/jvmdg/gradle/task/ShadeJar.kt | 7 +- .../jvmdg/gradle/task/files/DowngradeFiles.kt | 7 +- .../jvmdg/gradle/task/files/ShadeFiles.kt | 7 +- gradle.properties | 2 +- .../wagyourtail/jvmdg/ClassDowngrader.java | 29 ++- .../java/xyz/wagyourtail/jvmdg/Constants.java | 6 + .../java/xyz/wagyourtail/jvmdg/cli/Flags.java | 222 +++++++++++++++--- .../java/xyz/wagyourtail/jvmdg/cli/Main.java | 24 +- .../xyz/wagyourtail/jvmdg/logging/Logger.java | 19 +- .../wagyourtail/jvmdg/runtime/Bootstrap.java | 13 +- .../jvmdg/runtime/ClassDowngradingAgent.java | 17 +- .../jvmdg/version/VersionProvider.java | 3 +- .../test/{ => integration}/ClassRunner.java | 3 +- .../jvmdg/test/unit/TestFlags.java | 31 +++ 17 files changed, 381 insertions(+), 124 deletions(-) rename src/test/java/xyz/wagyourtail/jvmdg/test/{ => integration}/ClassRunner.java (99%) create mode 100644 src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt index d9ff5d76..ca11003d 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt @@ -57,11 +57,28 @@ abstract class JVMDowngraderExtension @Inject constructor(@get:Internal val proj apiJar }).finalizeValueOnRead() quiet.convention(false).finalizeValueOnRead() + logAnsiColors.convention(true).finalizeValueOnRead() + logLevel.convention("INFO").finalizeValueOnRead() + ignoreWarningsIn.convention(emptySet()).finalizeValueOnRead() debug.convention(false).finalizeValueOnRead() debugSkipStubs.convention(emptySet()).finalizeValueOnRead() + debugDumpClasses.convention(false).finalizeValueOnRead() shadePath.convention { it.substringBefore(".").substringBeforeLast("-").replace(Regex("[.;\\[/]"), "-") + "/" } } + fun convention(flags: ShadeFlags) { + convention(flags as DowngradeFlags) + flags.shadePath.convention(shadePath).finalizeValueOnRead() + } + + fun convention(flags: DowngradeFlags) { + flags.downgradeTo.convention(downgradeTo).finalizeValueOnRead() + flags.apiJar.convention(apiJar).finalizeValueOnRead() + flags.quiet.convention(quiet).finalizeValueOnRead() + flags.debug.convention(debug).finalizeValueOnRead() + flags.debugSkipStubs.convention(debugSkipStubs).finalizeValueOnRead() + } + @get:Internal internal val downgradedApis = defaultedMapOf { version -> val downgradedPath = project.file(".gradle").resolve("jvmdg/java-api-${this.version}-${version}-downgraded.jar") @@ -97,11 +114,7 @@ abstract class JVMDowngraderExtension @Inject constructor(@get:Internal val proj spec.to.attribute(artifactType, "jar").attribute(downgradeAttr, true).attribute(shadeAttr, false) spec.parameters { - it.downgradeTo.set(downgradeTo) - it.apiJar.set(apiJar) - it.quiet.set(quiet) - it.debug.set(debug) - it.debugSkipStubs.set(debugSkipStubs) + this@JVMDowngraderExtension.convention(it) config(it) javaVersion = it.downgradeTo.get() } @@ -121,14 +134,7 @@ abstract class JVMDowngraderExtension @Inject constructor(@get:Internal val proj spec.to.attribute(artifactType, "jar").attribute(shadeAttr, true).attribute(downgradeAttr, true) spec.parameters { - it.downgradeTo.set(downgradeTo) - it.apiJar.set(project.provider { - downgradedApis[it.downgradeTo.get()] - }) - it.quiet.set(quiet) - it.debug.set(debug) - it.debugSkipStubs.set(debugSkipStubs) - it.shadePath.set(shadePath) + this@JVMDowngraderExtension.convention(it) config(it) } } diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index 5eb22f7d..7fb0f09a 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -7,38 +7,102 @@ import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.Optional import xyz.wagyourtail.jvmdg.cli.Flags +import xyz.wagyourtail.jvmdg.logging.Logger import xyz.wagyourtail.jvmdg.util.toOpcode import java.io.File interface DowngradeFlags : TransformParameters { + /** + * sets the target class version to downgrade to, + * default is [JavaVersion.VERSION_1_8] + */ @get:Input @get:Optional val downgradeTo: Property + /** + * sets the api jar to use for downgrading + * default is null + */ @get:Input @get:Optional val apiJar: Property + /** + * sets the log level to [Logger.Level.FATAL] + * @deprecated use [logLevel], if this is true, it will override [logLevel] to [Logger.Level.FATAL] + */ @get:Input @get:Optional + @get:Deprecated(message = "use logLevel", replaceWith = ReplaceWith("logLevel = LogLevel.DEBUG")) val quiet: Property + /** + * sets if the logger should use ansi colors for the console to look pretty + */ @get:Input @get:Optional + val logAnsiColors: Property + + + /** + * sets the log level, default is [Logger.Level.INFO] as a string + */ + @get:Input + @get:Optional + val logLevel: Property + + /** + * sets if any classes should be set to ignore missing class/member warnings + * this will prevent [xyz.wagyourtail.jvmdg.version.VersionProvider.printWarnings] for + * any classes in this set + * + * This set also allows for packages to be ignored, by ending with a `*` or `**` to ignore all sub-packages + * @since 0.9.0 + */ + @get:Input + @get:Optional + val ignoreWarningsIn: SetProperty + + /** + * sets if the logger should print debug messages + * @deprecated use [logLevel], if this is true, it will override [logLevel] to [Logger.Level.DEBUG] + */ + @get:Input + @get:Optional + @get:Deprecated(message = "use logLevel", replaceWith = ReplaceWith("logLevel = LogLevel.DEBUG")) val debug: Property + /** + * this skips applying stubs for the specified input class version, this will still apply the + * [xyz.wagyourtail.jvmdg.version.VersionProvider.otherTransforms] + * such as `INVOKE_INTERFACE` -> `INVOKE_SPECIAL` for private interface methods in java 9 -> 8 + */ @get:Input @get:Optional val debugSkipStubs: SetProperty + + /** + * sets if classes should be dumped to the [xyz.wagyourtail.jvmdg.Constants.DEBUG_DIR] directory + * @since 0.9.0 + */ + @get:Input + @get:Optional + val debugDumpClasses: Property + } fun DowngradeFlags.toFlags(): Flags { val flags = Flags() - flags.api = apiJar.get() - flags.printDebug = debug.get() - flags.quiet = quiet.get() - flags.classVersion = downgradeTo.get().toOpcode() - flags.debugSkipStubs = debugSkipStubs.get().map { it.toOpcode() }.toSet() + flags.api = apiJar.orNull + flags.quiet = quiet.getOrElse(false) + flags.logAnsiColors = logAnsiColors.getOrElse(true) + flags.logLevel = Logger.Level.valueOf(logLevel.getOrElse("INFO").uppercase()) + flags.printDebug = debug.getOrElse(false) + flags.classVersion = downgradeTo.getOrElse(JavaVersion.VERSION_1_8).toOpcode() + flags.debugSkipStubs = debugSkipStubs.getOrElse(emptySet()).map { it.toOpcode() }.toSet() + ignoreWarningsIn.getOrElse(emptySet()).forEach { flags.addIgnore(it) } + flags.debugDumpClasses = debugDumpClasses.getOrElse(false) return flags -} \ No newline at end of file +} diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/DowngradeJar.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/DowngradeJar.kt index d2affdb7..c80f7d3e 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/DowngradeJar.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/DowngradeJar.kt @@ -34,12 +34,7 @@ abstract class DowngradeJar : Jar(), DowngradeFlags { group = "JVMDowngrader" description = "Downgrades the jar to the specified version" - downgradeTo.convention(jvmdg.downgradeTo).finalizeValueOnRead() - apiJar.convention(jvmdg.apiJar).finalizeValueOnRead() - quiet.convention(jvmdg.quiet).finalizeValueOnRead() - debug.convention(jvmdg.debug).finalizeValueOnRead() - debugSkipStubs.convention(jvmdg.debugSkipStubs).finalizeValueOnRead() - + jvmdg.convention(this) } @TaskAction diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/ShadeJar.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/ShadeJar.kt index 3d075fd8..cc2d18d0 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/ShadeJar.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/ShadeJar.kt @@ -31,12 +31,7 @@ abstract class ShadeJar : Jar(), ShadeFlags { group = "JVMDowngrader" description = "Downgrades the jar to the specified version" - downgradeTo.convention(jvmdg.downgradeTo).finalizeValueOnRead() - apiJar.convention(jvmdg.apiJar).finalizeValueOnRead() - quiet.convention(jvmdg.quiet).finalizeValueOnRead() - debug.convention(jvmdg.debug).finalizeValueOnRead() - debugSkipStubs.convention(jvmdg.debugSkipStubs).finalizeValueOnRead() - shadePath.convention(jvmdg.shadePath).finalizeValueOnRead() + jvmdg.convention(this) } @TaskAction diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt index 1abdae93..852546ac 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt @@ -3,7 +3,6 @@ package xyz.wagyourtail.jvmdg.gradle.task.files import org.gradle.api.file.FileCollection import org.gradle.api.internal.ConventionTask import org.gradle.api.tasks.* -import org.jetbrains.annotations.ApiStatus import xyz.wagyourtail.jvmdg.ClassDowngrader import xyz.wagyourtail.jvmdg.compile.PathDowngrader import xyz.wagyourtail.jvmdg.gradle.flags.DowngradeFlags @@ -50,11 +49,7 @@ abstract class DowngradeFiles : ConventionTask(), DowngradeFlags { } init { - downgradeTo.convention(jvmdg.downgradeTo).finalizeValueOnRead() - apiJar.convention(jvmdg.apiJar).finalizeValueOnRead() - quiet.convention(jvmdg.quiet).finalizeValueOnRead() - debug.convention(jvmdg.debug).finalizeValueOnRead() - debugSkipStubs.convention(jvmdg.debugSkipStubs).finalizeValueOnRead() + jvmdg.convention(this) } @TaskAction diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/ShadeFiles.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/ShadeFiles.kt index f800643c..59bc78de 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/ShadeFiles.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/ShadeFiles.kt @@ -43,12 +43,7 @@ abstract class ShadeFiles : ConventionTask(), ShadeFlags { } init { - downgradeTo.convention(jvmdg.downgradeTo).finalizeValueOnRead() - apiJar.convention(jvmdg.apiJar).finalizeValueOnRead() - quiet.convention(jvmdg.quiet).finalizeValueOnRead() - debug.convention(jvmdg.debug).finalizeValueOnRead() - debugSkipStubs.convention(jvmdg.debugSkipStubs).finalizeValueOnRead() - shadePath.convention(jvmdg.shadePath).finalizeValueOnRead() + jvmdg.convention(this) } // fun setShadePath(path: String) { diff --git a/gradle.properties b/gradle.properties index a74b5300..68f03598 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ kotlin.code.style=official org.gradle.jvmargs=-Xmx4G org.gradle.parallel=true -version=0.8.2 +version=0.9.0 asm_version=9.7 diff --git a/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java b/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java index e0622f4a..f0986aae 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java @@ -49,7 +49,7 @@ public class ClassDowngrader implements Closeable { protected ClassDowngrader(@NotNull Flags flags) { this.flags = flags; this.target = flags.classVersion; - logger = new Logger(ClassDowngrader.class, flags.printDebug ? Logger.Level.DEBUG : flags.quiet ? Logger.Level.FATAL : Logger.Level.INFO, System.out); + logger = new Logger(ClassDowngrader.class, flags.getLogLevel(), flags.logAnsiColors, System.out); try { classLoader = new DowngradingClassLoader(this, ClassDowngrader.class.getClassLoader()); } catch (IOException e) { @@ -286,7 +286,7 @@ public Map downgrade(/* in out */ AtomicReference name, } Map outputs = new HashMap<>(); try { - if (flags.printDebug) System.out.println("Transforming " + name.get()); + logger.trace("Transforming " + name.get()); Set extra = downgrade(node, enableRuntime, new Function() { @Override @@ -303,28 +303,31 @@ public ClassNode apply(String s) { } }); for (ClassNode c : extra) { - if (flags.printDebug) { - File f = new File(Constants.DEBUG_DIR, c.name + ".javasm"); - f.getParentFile().mkdirs(); - try (FileOutputStream fos = new FileOutputStream(f)) { - TraceClassVisitor tcv = new TraceClassVisitor(null, new Textifier(), new PrintWriter(fos)); - c.accept(tcv); - } catch (IOException ignored) { - } - } + // TODO: uncomment with asm 9.8 +// if (flags.debugDumpClasses) { +// File f = new File(Constants.DEBUG_DIR, c.name + ".javasm"); +// f.getParentFile().mkdirs(); +// try (FileOutputStream fos = new FileOutputStream(f)) { +// TraceClassVisitor tcv = new TraceClassVisitor(null, new Textifier(), new PrintWriter(fos)); +// c.accept(tcv); +// } catch (IOException ignored) { +// } +// } outputs.put(c.name, classNodeToBytes(c)); } } catch (Exception e) { throw new RuntimeException("Failed to downgrade " + name.get(), e); } - if (logger.is(Logger.Level.DEBUG)) { + if (logger.is(Logger.Level.DEBUG) || flags.debugDumpClasses) { for (Map.Entry entry : outputs.entrySet()) { if (!entry.getKey().equals(name.get())) { logger.debug("Downgraded " + entry.getKey() + " from unknown to " + target); } else { logger.debug("Downgraded " + entry.getKey() + " from " + version + " to " + target); } - writeBytesToDebug(entry.getKey(), entry.getValue()); + if (flags.debugDumpClasses) { + writeBytesToDebug(entry.getKey(), entry.getValue()); + } } } return outputs; diff --git a/src/main/java/xyz/wagyourtail/jvmdg/Constants.java b/src/main/java/xyz/wagyourtail/jvmdg/Constants.java index 8ce802e7..1e1d1518 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/Constants.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/Constants.java @@ -4,12 +4,18 @@ public class Constants { + @Deprecated public static final String QUIET = "jvmdg.quiet"; + public static final String LOG_ANSI_COLORS = "jvmdg.logAnsiColors"; + public static final String LOG_LEVEL = "jvmdg.logLevel"; public static final String JAVA_API = "jvmdg.java-api"; public static final String ALLOW_MAVEN_LOOKUP = "jvmdg.maven"; + public static final String IGNORE_WARNINGS = "jvmdg.ignoreWarnings"; + public static final String DEBUG = "jvmdg.debug"; public static final String DEBUG_SKIP_STUBS = "jvmdg.debug.skipStubs"; + public static final String DEBUG_DUMP_CLASSES = "jvmdg.debug.dumpClasses"; public static final File DIR = new File(".jvmdg"); diff --git a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java index e8292087..6df7431a 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java @@ -1,8 +1,11 @@ package xyz.wagyourtail.jvmdg.cli; +import org.jetbrains.annotations.ApiStatus; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; import xyz.wagyourtail.jvmdg.ClassDowngrader; import xyz.wagyourtail.jvmdg.Constants; +import xyz.wagyourtail.jvmdg.logging.Logger; import xyz.wagyourtail.jvmdg.util.Consumer; import xyz.wagyourtail.jvmdg.util.Function; @@ -18,27 +21,91 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.TreeMap; public class Flags { public static final String jvmdgVersion = Flags.class.getPackage().getImplementationVersion(); + /** + * sets the target class version, default is {@link Opcodes#V1_8} + */ public int classVersion = Opcodes.V1_8; + + /** + * sets the api jar to use, if null will attempt to automatically find it + */ public File api = null; + + /** + * sets the log level to {@link Logger.Level#FATAL} + * @deprecated use logLevel, if this is true, it will override {@link #logLevel} to {@link Logger.Level#FATAL} + */ + @Deprecated public boolean quiet = Boolean.getBoolean(Constants.QUIET); + + /** + * sets if the logger should use ansi colors for the console to look pretty + */ + public boolean logAnsiColors = Boolean.getBoolean(System.getProperty(Constants.LOG_ANSI_COLORS, "true")); + /** + * sets the log level + * @see Logger.Level + * @since 0.9.0 + */ + public Logger.Level logLevel = Logger.Level.valueOf(System.getProperty(Constants.LOG_LEVEL, "INFO").toUpperCase()); + + /** + * sets if any classes should be set to ignore missing class/member warnings + * this will prevent {@link xyz.wagyourtail.jvmdg.version.VersionProvider#printWarnings(Set, String)} for + * any classes in this set + *

+ * This set also allows for packages to be ignored, by ending with a {@code *} or {@code **} to ignore all sub-packages + * @since 0.9.0 + */ + public TreeMap ignoreWarningsIn = new TreeMap<>(); + + /** + * sets if maven lookup is allowed for auto resolving {@link #api} + */ public boolean allowMaven = Boolean.getBoolean(Constants.ALLOW_MAVEN_LOOKUP); // debug + /** + * sets the log level to {@link Logger.Level#DEBUG} + * @deprecated use logLevel, if this is true, it will override {@link #logLevel} to {@link Logger.Level#DEBUG} + */ + @Deprecated public boolean printDebug = Boolean.getBoolean(Constants.DEBUG); + + /** + * this skips applying stubs for the specified input class version, this will still apply the + * {@link xyz.wagyourtail.jvmdg.version.VersionProvider#otherTransforms(ClassNode, Set, Function, Set)} + * such as {@code INVOKE_INTERFACE} -> {@code INVOKE_SPECIAL} for private interface methods in java 9 -> 8 + */ public Set debugSkipStubs = new HashSet<>(getDebugSkip()); + /** + * sets if classes should be dumped to the {@link Constants#DEBUG_DIR} directory + * @since 0.9.0 + */ + public boolean debugDumpClasses = Boolean.getBoolean(Constants.DEBUG_DUMP_CLASSES); + + public Flags() { + getIgnoreWarnings(); + } + public Flags copy() { Flags flags = new Flags(); flags.classVersion = classVersion; flags.api = api; flags.quiet = quiet; + flags.logAnsiColors = logAnsiColors; + flags.logLevel = logLevel; flags.allowMaven = allowMaven; + flags.ignoreWarningsIn = new TreeMap<>(ignoreWarningsIn); flags.printDebug = printDebug; flags.debugSkipStubs = new HashSet<>(debugSkipStubs); + flags.debugDumpClasses = debugDumpClasses; return flags; } @@ -51,15 +118,112 @@ public Flags copy(Consumer modifier) { @Override public String toString() { return "Flags{" + - "classVersion=" + classVersion + - ", api=" + api + - ", quiet=" + quiet + - ", allowMaven=" + allowMaven + - ", printDebug=" + printDebug + - ", debugSkipStubs=" + debugSkipStubs + - '}'; + "classVersion=" + classVersion + + ", api=" + api + + ", quiet=" + quiet + + ", logAnsiColors=" + logAnsiColors + + ", logLevel=" + logLevel + + ", allowMaven=" + allowMaven + + ", printDebug=" + printDebug + + ", debugSkipStubs=" + debugSkipStubs + + ", ignoreWarningsIn=" + ignoreWarningsIn + + '}'; + } + + public void addIgnore(String s) { + if (s.endsWith("**")) { + ignoreWarningsIn.put(s.substring(0, s.length() - 2), WildcardType.DOUBLE); + } else if (s.endsWith("*")) { + ignoreWarningsIn.put(s.substring(0, s.length() - 1), WildcardType.SINGLE); + } else { + ignoreWarningsIn.put(s, WildcardType.NONE); + } + } + + /* getters */ + + /** + * internal method for retrieving the actual log level + */ + @ApiStatus.Internal + public Logger.Level getLogLevel() { + if (quiet) { + return Logger.Level.FATAL; + } + if (printDebug) { + return Logger.Level.DEBUG; + } + return logLevel; + } + + /** + * internal method to resolve the java api jar + */ + @ApiStatus.Internal + public File findJavaApi() { + try { + if (api != null) { + return api; + } + Constants.DIR.mkdirs(); + Path tmp = Constants.DIR.toPath().resolve("jvmdg-api.jar"); + File prop = getJavaApiFromSystemProperty(); + if (prop != null) { + return prop; + } + URL url = getJavaApiFromShade(); + if (url == null && allowMaven) { + url = getJavaApiFromMaven(); + } + if (url != null) { + try (InputStream in = url.openStream()) { + Files.copy(in, tmp, StandardCopyOption.REPLACE_EXISTING); + } + return tmp.toFile(); + } else { + // failed to find java api + if (!quiet) { + System.err.println("[JvmDowngrader] Failed to find java api jar!"); + } + return null; + } + } catch (IOException e) { + throw new RuntimeException("Failed to find java api", e); + } } + public boolean checkInIgnoreWarnings(String className) { + Map.Entry entry = ignoreWarningsIn.floorEntry(className); + if (entry != null && className.startsWith(entry.getKey())) { + switch (entry.getValue()) { + case NONE: + if (className.equals(entry.getKey())) { + return true; + } + return true; + case SINGLE: + int lastSlash = className.lastIndexOf('/'); + if (lastSlash == -1) { + return true; + } + String parent = className.substring(0, lastSlash + 1); + String value = entry.getKey(); + if (!value.endsWith("/")) { + value = value.substring(0, value.lastIndexOf('/') + 1); + } + if (parent.equals(value)) { + return true; + } + break; + case DOUBLE: + return true; + } + } + return false; + } + + /* initialization methods */ + private Set getDebugSkip() { Set skip = new HashSet<>(); String skipStubs = System.getProperty(Constants.DEBUG_SKIP_STUBS); @@ -70,6 +234,16 @@ private Set getDebugSkip() { return skip; } + private TreeMap getIgnoreWarnings() { + String ignoreWarnings = System.getProperty(Constants.IGNORE_WARNINGS); + if (ignoreWarnings == null) return new TreeMap<>(); + TreeMap map = new TreeMap<>(); + for (String s : ignoreWarnings.split(",")) { + addIgnore(s); + } + return map; + } + private URL getJavaApiFromShade() throws IOException { return ClassDowngrader.class.getResource("/META-INF/lib/java-api.jar"); } @@ -113,35 +287,9 @@ private URL getJavaApiFromMaven() throws IOException { } } - public File findJavaApi() { - try { - if (api != null) { - return api; - } - Constants.DIR.mkdirs(); - Path tmp = Constants.DIR.toPath().resolve("jvmdg-api.jar"); - File prop = getJavaApiFromSystemProperty(); - if (prop != null) { - return prop; - } - URL url = getJavaApiFromShade(); - if (url == null && allowMaven) { - url = getJavaApiFromMaven(); - } - if (url != null) { - try (InputStream in = url.openStream()) { - Files.copy(in, tmp, StandardCopyOption.REPLACE_EXISTING); - } - return tmp.toFile(); - } else { - // failed to find java api - if (!quiet) { - System.err.println("[JvmDowngrader] Failed to find java api jar!"); - } - return null; - } - } catch (IOException e) { - throw new RuntimeException("Failed to find java api", e); - } + public enum WildcardType { + NONE, + SINGLE, + DOUBLE } } diff --git a/src/main/java/xyz/wagyourtail/jvmdg/cli/Main.java b/src/main/java/xyz/wagyourtail/jvmdg/cli/Main.java index 71dd367c..17bd3634 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/cli/Main.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/cli/Main.java @@ -4,6 +4,7 @@ import xyz.wagyourtail.jvmdg.compile.ApiShader; import xyz.wagyourtail.jvmdg.compile.PathDowngrader; import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.logging.Logger; import xyz.wagyourtail.jvmdg.util.Utils; import java.io.File; @@ -25,12 +26,15 @@ public static void main(String[] args) throws IOException, ClassNotFoundExceptio parser.addChildren( new Arguments("--help", "Prints this help", new String[]{"-h"}, null), new Arguments("--version", "Prints the version", new String[]{"-v"}, null), - new Arguments("--quiet", "Suppress all warnings", new String[]{"-q"}, null), + new Arguments("--logLevel", "Set the log level", new String[]{"-l"}, new String[]{"level"}), + new Arguments("--quiet", "[Deprecated] Suppress all warnings", new String[]{"-q"}, null), + new Arguments("--ignoreWarningsIn", "Ignore warnings of missing class/member stubs in package/class matching", new String[]{"-i"}, new String[]{"package or class identifier"}), new Arguments("--api", "Provide a java-api jar", new String[]{"-a"}, new String[]{"jar"}), new Arguments("--classVersion", "Target class version (ex. \"52\" for java 8)", new String[]{"-c"}, new String[]{"version"}), new Arguments("debug", "Set debug flags/call debug actions", null, null).addChildren( - new Arguments("--print", "Enable printing debug info", new String[]{"-p"}, null), + new Arguments("--print", "[Deprecated] Enable printing debug info", new String[]{"-p"}, null), new Arguments("--skipStubs", "Skip method/class stubs for these class versions", new String[]{"-s"}, new String[]{"versions"}), + new Arguments("--dumpClasses", "Dump classes to the debug folder", new String[]{"-d"}, null), new Arguments("downgradeApi", "Retrieves and downgrades the java api jar", null, new String[]{"outputPath"}) ), new Arguments("downgrade", "Downgrades a jar or folder", null, null).addChildren( @@ -73,12 +77,25 @@ public static void main(String[] args) throws IOException, ClassNotFoundExceptio case "--quiet": flags.quiet = true; break; + case "--logLevel": + if (entry.getValue().size() > 1) { + throw new IllegalArgumentException("Multiple log levels specified"); + } + flags.logLevel = Logger.Level.valueOf(entry.getValue().get(0)[0].toUpperCase()); + break; case "--classVersion": if (entry.getValue().size() > 1) { throw new IllegalArgumentException("Multiple class versions specified"); } flags.classVersion = Integer.parseInt(entry.getValue().get(0)[0]); break; + case "--ignoreWarningsIn": + for (String[] s : entry.getValue()) { + for (String string : s) { + flags.addIgnore(string); + } + } + break; case "--api": if (entry.getValue().size() > 1) { throw new IllegalArgumentException("Multiple api paths specified"); @@ -123,6 +140,9 @@ public static void debug(Map> args) throws IOException { case "--print": flags.printDebug = true; break; + case "--dumpClasses": + flags.debugDumpClasses = true; + break; case "--skipStubs": for (String[] s : entry.getValue()) { for (String string : s) { diff --git a/src/main/java/xyz/wagyourtail/jvmdg/logging/Logger.java b/src/main/java/xyz/wagyourtail/jvmdg/logging/Logger.java index 4528ec75..6868aa96 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/logging/Logger.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/logging/Logger.java @@ -11,16 +11,18 @@ public class Logger { private final String prefix; private final Level level; + private final boolean useAnsiColors; private final PrintStream out; - public Logger(String prefix, Level level, PrintStream out) { + public Logger(String prefix, Level level, boolean useAnsiColors, PrintStream out) { this.prefix = prefix; this.level = level; this.out = out; + this.useAnsiColors = useAnsiColors; } - public Logger(Class clazz, Level level, PrintStream out) { - this(clazz.getSimpleName(), level, out); + public Logger(Class clazz, Level level, boolean useAnsiColors, PrintStream out) { + this(clazz.getSimpleName(), level, useAnsiColors, out); } public boolean is(Level level) { @@ -29,7 +31,12 @@ public boolean is(Level level) { public void log(Level level, String message) { if (is(level)) { - out.println(level.wrap("[" + prefix + "] " + level + ": " + message)); + String messageContent = "[" + prefix + "] " + level + ": " + message; + if (useAnsiColors) { + out.println(level.ansiColor(messageContent)); + } else { + out.println(messageContent); + } } } @@ -88,7 +95,7 @@ public void accept(PrintStream printStream) { } public Logger subLogger(String prefix) { - return new Logger(this.prefix + "/" + prefix, level, out); + return new Logger(this.prefix + "/" + prefix, level, useAnsiColors, out); } public Logger subLogger(Class clazz) { @@ -129,7 +136,7 @@ public AnsiColor getAnsiColor() { return ansiColor; } - public String wrap(String message) { + public String ansiColor(String message) { return ansiColor.wrap(message); } } diff --git a/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java b/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java index 3907fcac..58ad4d4c 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java @@ -4,6 +4,7 @@ import xyz.wagyourtail.jvmdg.Constants; import xyz.wagyourtail.jvmdg.cli.Flags; import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.logging.Logger; import xyz.wagyourtail.jvmdg.util.Utils; import java.io.File; @@ -19,17 +20,11 @@ import java.security.MessageDigest; import java.util.HashSet; import java.util.jar.JarFile; -import java.util.logging.Level; -import java.util.logging.Logger; public class Bootstrap { static final Flags flags = new Flags(); static final ClassDowngrader currentVersionDowngrader = ClassDowngrader.getCurrentVersionDowngrader(flags); - private static final Logger LOGGER = Logger.getLogger("JVMDowngrader"); - - static { - LOGGER.setLevel(flags.printDebug ? Level.ALL : Level.WARNING); - } + static final Logger LOGGER = new Logger("JVMDowngrader", flags.getLogLevel(), flags.logAnsiColors, System.out); public static void main(String[] args) { LOGGER.info("Starting JVMDowngrader Bootstrap in standalone mode."); @@ -76,7 +71,7 @@ public static void premain(String args, Instrumentation instrumentation) throws Path tmp = Constants.DIR.toPath().resolve("java-api-downgraded-" + currentVersionDowngrader.target + "-" + zipSha.substring(0, 8) + ".jar"); boolean downgrade = false; if (!Files.exists(tmp)) { - LOGGER.warning("Downgrading java-api.jar as its hash changed or this is first launch, this may take a minute..."); + LOGGER.warn("Downgrading java-api.jar as its hash changed or this is first launch, this may take a minute..."); downgrade = true; } if (downgrade) { @@ -94,7 +89,7 @@ public static void premain(String args, Instrumentation instrumentation) throws instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(self.toURI().getPath())); instrumentation.addTransformer(new ClassDowngradingAgent(), instrumentation.isRetransformClassesSupported()); if (!instrumentation.isModifiableClass(CodeSource.class) || !instrumentation.isRetransformClassesSupported()) { - LOGGER.severe("CodeSource is not modifiable, this will prevent loading signed classes properly!!!"); + LOGGER.fatal("CodeSource is not modifiable, this will prevent loading signed classes properly!!!"); } else { LOGGER.info("CodeSource is modifiable, attempting to retransform it to fix code signing."); instrumentation.retransformClasses(CodeSource.class); diff --git a/src/main/java/xyz/wagyourtail/jvmdg/runtime/ClassDowngradingAgent.java b/src/main/java/xyz/wagyourtail/jvmdg/runtime/ClassDowngradingAgent.java index 0d55ed86..308010af 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/runtime/ClassDowngradingAgent.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/runtime/ClassDowngradingAgent.java @@ -1,6 +1,7 @@ package xyz.wagyourtail.jvmdg.runtime; import org.objectweb.asm.*; +import xyz.wagyourtail.jvmdg.logging.Logger; import xyz.wagyourtail.jvmdg.util.Function; import xyz.wagyourtail.jvmdg.util.Utils; @@ -13,19 +14,13 @@ import java.security.ProtectionDomain; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; public class ClassDowngradingAgent implements ClassFileTransformer { public static final MethodHandle defineClass; public static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("jvmdg.dump", "false")); - private static final Logger LOGGER = Logger.getLogger("JVMDowngrader/Agent"); + private static final Logger LOGGER = Bootstrap.LOGGER.subLogger("Agent"); private static final int currentVersion; - static { - LOGGER.setLevel(Bootstrap.flags.printDebug ? Level.ALL : Level.OFF); - } - static { Method md; try { @@ -89,10 +84,10 @@ public byte[] transform(final ClassLoader loader, String className, Class cla int version = ((bytes[6] & 0xFF) << 8) | (bytes[7] & 0xFF); if (version <= currentVersion) { // already at or below the target version - LOGGER.finer("Ignoring " + className + " as it is already at or below the target version"); + LOGGER.trace("Ignoring " + className + " as it is already at or below the target version"); return null; } - LOGGER.fine("Transforming " + className + " from " + version + " to " + currentVersion); + LOGGER.trace("Transforming " + className + " from " + version + " to " + currentVersion); // if (loader instanceof DowngradingClassLoader) return bytes; // already handled Map outputs = Bootstrap.currentVersionDowngrader.downgrade(new AtomicReference<>(className), bytes, true, new Function() { @Override @@ -106,11 +101,11 @@ public byte[] apply(String s) { } } }); - LOGGER.fine("transform size: " + (outputs == null ? null : outputs.size())); + LOGGER.trace("transform size: " + (outputs == null ? null : outputs.size())); if (outputs == null) return bytes; bytes = null; for (Map.Entry entry : outputs.entrySet()) { - LOGGER.fine("Loading " + entry.getKey() + " into " + loader); + LOGGER.trace("Loading " + entry.getKey() + " into " + loader); if (DUMP_CLASSES) { Bootstrap.currentVersionDowngrader.writeBytesToDebug(entry.getKey(), entry.getValue()); } diff --git a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java index 5c2e41d5..0084355f 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java @@ -840,8 +840,9 @@ public ClassNode apply(ClassNode classNode) throws IOException { return clazz; } - private void printWarnings(Set warnings, String className) { + public void printWarnings(Set warnings, String className) { if (!warnings.isEmpty() && logger.is(Logger.Level.WARN)) { + if (downgrader.flags.checkInIgnoreWarnings(className)) return; StringBuilder sb = new StringBuilder(); for (String warning : warnings) { sb.append(" ").append(warning).append("\n"); diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/ClassRunner.java b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java similarity index 99% rename from src/test/java/xyz/wagyourtail/jvmdg/test/ClassRunner.java rename to src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java index 8af8ee98..eeb7066c 100644 --- a/src/test/java/xyz/wagyourtail/jvmdg/test/ClassRunner.java +++ b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java @@ -1,4 +1,4 @@ -package xyz.wagyourtail.jvmdg.test; +package xyz.wagyourtail.jvmdg.test.integration; import org.apache.commons.io.function.IOStream; import org.junit.jupiter.api.BeforeAll; @@ -14,6 +14,7 @@ import xyz.wagyourtail.jvmdg.cli.Flags; import xyz.wagyourtail.jvmdg.compile.ApiShader; import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.test.JavaRunner; import xyz.wagyourtail.jvmdg.util.Utils; import java.io.File; diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java b/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java new file mode 100644 index 00000000..42e2d0b9 --- /dev/null +++ b/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java @@ -0,0 +1,31 @@ +package xyz.wagyourtail.jvmdg.test.unit; + +import org.junit.jupiter.api.Test; +import xyz.wagyourtail.jvmdg.cli.Flags; + +import static org.junit.jupiter.api.Assertions.*; + +public class TestFlags { + + + @Test + public void testClassIn() { + Flags f = new Flags(); + f.addIgnore("aaa/bbb/*"); + f.addIgnore("aaa/bbb/ccc/*"); + f.addIgnore("bbb/**"); + f.addIgnore("ccc/aa/dd*"); + + assertTrue(f.checkInIgnoreWarnings("aaa/bbb/ccc/ddd")); + assertTrue(f.checkInIgnoreWarnings("aaa/bbb/ccc")); + assertFalse(f.checkInIgnoreWarnings("aaa/bbb/ddd/ccc")); + assertTrue(f.checkInIgnoreWarnings("bbb/aaa/ccc")); + assertTrue(f.checkInIgnoreWarnings("bbb/ccc")); + assertTrue(f.checkInIgnoreWarnings("bbb/ccc/ddd")); + assertTrue(f.checkInIgnoreWarnings("ccc/aa/ddd")); + assertTrue(f.checkInIgnoreWarnings("ccc/aa/dddc")); + assertFalse(f.checkInIgnoreWarnings("ccc/aa/dd/ee")); + assertFalse(f.checkInIgnoreWarnings("ccc/aa/de")); + } + +} From 16bfc467ba027ed67ca02065fb4a217fb7d20dae Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Mon, 8 Jul 2024 10:24:08 -0500 Subject: [PATCH 02/15] add member and change to list --- .../wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt | 7 ++++--- .../wagyourtail/jvmdg/version/VersionProvider.java | 11 +++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index 7fb0f09a..a97017e2 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -2,6 +2,7 @@ package xyz.wagyourtail.jvmdg.gradle.flags import org.gradle.api.JavaVersion import org.gradle.api.artifacts.transform.TransformParameters +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input @@ -63,7 +64,7 @@ interface DowngradeFlags : TransformParameters { */ @get:Input @get:Optional - val ignoreWarningsIn: SetProperty + val ignoreWarningsIn: ListProperty /** * sets if the logger should print debug messages @@ -101,8 +102,8 @@ fun DowngradeFlags.toFlags(): Flags { flags.logLevel = Logger.Level.valueOf(logLevel.getOrElse("INFO").uppercase()) flags.printDebug = debug.getOrElse(false) flags.classVersion = downgradeTo.getOrElse(JavaVersion.VERSION_1_8).toOpcode() - flags.debugSkipStubs = debugSkipStubs.getOrElse(emptySet()).map { it.toOpcode() }.toSet() - ignoreWarningsIn.getOrElse(emptySet()).forEach { flags.addIgnore(it) } + flags.debugSkipStubs = debugSkipStubs.getOrElse(emptyList()).map { it.toOpcode() }.toSet() + ignoreWarningsIn.getOrElse(emptyList()).forEach { flags.addIgnore(it) } flags.debugDumpClasses = debugDumpClasses.getOrElse(false) return flags } diff --git a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java index 0084355f..fc428325 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java @@ -331,6 +331,7 @@ public void stub(Class clazz) { logger.warn("failed to create stub(s) for " + clazz.getName(), e); } if (!warnings.isEmpty() && logger.is(Logger.Level.WARN)) { + if (downgrader.flags.checkInIgnoreWarnings(clazz.getName())) return; StringBuilder sb = new StringBuilder(); for (String warning : warnings) { sb.append(" ").append(warning).append("\n"); @@ -420,11 +421,13 @@ public ClassNode stubMethods(ClassNode owner, Set extra, boolean enab owner.methods.set(owner.methods.indexOf(method), newMethod); } if (!warnings.isEmpty() && logger.is(Logger.Level.WARN)) { - StringBuilder sb = new StringBuilder(); - for (String warning : warnings) { - sb.append(" ").append(warning).append("\n"); + if (!downgrader.flags.checkInIgnoreWarnings(owner.name + "." + method.name)) { + StringBuilder sb = new StringBuilder(); + for (String warning : warnings) { + sb.append(" ").append(warning).append("\n"); + } + logger.warn("Warnings for " + owner.name + "." + method.name + method.desc + " (" + warnings.size() + ") : \n" + sb); } - logger.warn("Warnings for " + owner.name + "." + method.name + method.desc + " (" + warnings.size() + ") : \n" + sb); } } return owner; From 163559547ca475b04678593840233ab4429ff3a7 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Mon, 8 Jul 2024 10:40:26 -0500 Subject: [PATCH 03/15] add explanation --- src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java index 6df7431a..8997bb6c 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java @@ -193,6 +193,9 @@ public File findJavaApi() { } public boolean checkInIgnoreWarnings(String className) { + // find the entry that is <= the className, because a treeSet is sorted, this is either className, + // a prefix of classname, a random other string that is less than className, ie. "aaa" < "bbb", or null if there + // is no entries that are <= className in the map Map.Entry entry = ignoreWarningsIn.floorEntry(className); if (entry != null && className.startsWith(entry.getKey())) { switch (entry.getValue()) { From 0eb787ed089ac95f1bd0e27360f69d7e6b3b94e1 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Mon, 8 Jul 2024 10:54:37 -0500 Subject: [PATCH 04/15] fix --- .../kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index a97017e2..71023667 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -102,7 +102,7 @@ fun DowngradeFlags.toFlags(): Flags { flags.logLevel = Logger.Level.valueOf(logLevel.getOrElse("INFO").uppercase()) flags.printDebug = debug.getOrElse(false) flags.classVersion = downgradeTo.getOrElse(JavaVersion.VERSION_1_8).toOpcode() - flags.debugSkipStubs = debugSkipStubs.getOrElse(emptyList()).map { it.toOpcode() }.toSet() + flags.debugSkipStubs = debugSkipStubs.getOrElse(emptySet()).map { it.toOpcode() }.toSet() ignoreWarningsIn.getOrElse(emptyList()).forEach { flags.addIgnore(it) } flags.debugDumpClasses = debugDumpClasses.getOrElse(false) return flags From f356c8679e1f30edc11b77aa86e5433385d394d5 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Wed, 10 Jul 2024 18:07:18 -0500 Subject: [PATCH 05/15] finalize input/output immediately on donwgradeFiles --- .../jvmdg/gradle/task/files/DowngradeFiles.kt | 19 +++++++++++++------ .../wagyourtail/jvmdg/util/AsyncUtils.java | 8 -------- .../wagyourtail/jvmdg/test/JavaRunner.java | 3 ++- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt index 852546ac..fd5304cc 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/task/files/DowngradeFiles.kt @@ -22,8 +22,20 @@ abstract class DowngradeFiles : ConventionTask(), DowngradeFlags { project.extensions.getByType(JVMDowngraderExtension::class.java) } + private var _inputCollection: FileCollection by FinalizeOnRead(MustSet()) + @get:InputFiles - var inputCollection: FileCollection by FinalizeOnRead(MustSet()) + var inputCollection: FileCollection + get() = _inputCollection + set(value) { + _inputCollection = value + + // use _inputCollection to finalize it immediately + val fd = _inputCollection.map { it to temporaryDir.resolve(it.name) } + outputs.dirs(*fd.filter { it.first.isDirectory }.map { it.second }.toTypedArray()) + outputs.files(*fd.filter { it.first.isFile }.map { it.second }.toTypedArray()) + + } @get:InputFiles var classpath: FileCollection by FinalizeOnRead(LazyMutable { @@ -40,11 +52,6 @@ abstract class DowngradeFiles : ConventionTask(), DowngradeFlags { */ @get:Internal val outputCollection: FileCollection by lazy { - val fd = inputCollection.map { it to temporaryDir.resolve(it.name) } - - outputs.dirs(*fd.filter { it.first.isDirectory }.map { it.second }.toTypedArray()) - outputs.files(*fd.filter { it.first.isFile }.map { it.second }.toTypedArray()) - outputs.files } diff --git a/src/shared/java/xyz/wagyourtail/jvmdg/util/AsyncUtils.java b/src/shared/java/xyz/wagyourtail/jvmdg/util/AsyncUtils.java index 017773ad..68df1295 100644 --- a/src/shared/java/xyz/wagyourtail/jvmdg/util/AsyncUtils.java +++ b/src/shared/java/xyz/wagyourtail/jvmdg/util/AsyncUtils.java @@ -133,14 +133,6 @@ public void run() { return FileVisitResult.CONTINUE; } }); -// while (!futures.isEmpty()) { -// try { -// futures.poll().get(); -// } catch (InterruptedException | ExecutionException e) { -// throw new RuntimeException(e); -// } -// } -// return null; return (Future) waitForFutures(futures); } diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java b/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java index d8421231..8c704f8b 100644 --- a/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java +++ b/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java @@ -234,7 +234,8 @@ public enum JavaVersion { V19, V20, V21, - V22; + V22, + V23; public static JavaVersion fromClassVers(int vers) { return JavaVersion.values()[vers - 45]; From 57842e49514c53fb7e325ed96c58b6706da080ff Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Wed, 10 Jul 2024 18:52:20 -0500 Subject: [PATCH 06/15] fix tests --- .../xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java index eeb7066c..7f480b87 100644 --- a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java +++ b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java @@ -219,7 +219,7 @@ public static void clearPrevious() throws IOException { } @ParameterizedTest - @MethodSource({"xyz.wagyourtail.jvmdg.test.ClassRunner#arguments"}) + @MethodSource({"xyz.wagyourtail.jvmdg.test.integration.ClassRunner#arguments"}) @Execution(ExecutionMode.CONCURRENT) public void testDowngrade(String mainClass, FlagsAndRunner javaVersion) throws IOException, InterruptedException { System.out.println("TEST_DOWNGRADE: Running " + mainClass + " on " + javaVersion.readableSlug()); From 6e4b8fdac0975b9ef04bb73bb64495eae312af06 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 15:54:09 -0500 Subject: [PATCH 07/15] allow multiple api jars fix --- .../jvmdg/classloader/DowngradingClassLoader.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/xyz/wagyourtail/jvmdg/classloader/DowngradingClassLoader.java b/src/main/java/xyz/wagyourtail/jvmdg/classloader/DowngradingClassLoader.java index ec4ada64..a982809e 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/classloader/DowngradingClassLoader.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/classloader/DowngradingClassLoader.java @@ -25,9 +25,11 @@ public class DowngradingClassLoader extends ClassLoader implements Closeable { public DowngradingClassLoader(ClassDowngrader downgrader) throws IOException { super(); - File apiJar = downgrader.flags.findJavaApi(); + Set apiJar = downgrader.flags.findJavaApi(); if (apiJar != null) { - delegates.add(new JarFileResourceProvider(new JarFile(apiJar))); + for (File file : apiJar) { + delegates.add(new JarFileResourceProvider(new JarFile(file))); + } } this.holder = downgrader; if (downgrader.target != Utils.getCurrentClassVersion()) { @@ -40,9 +42,11 @@ public DowngradingClassLoader(ClassDowngrader downgrader) throws IOException { public DowngradingClassLoader(ClassDowngrader downgrader, ClassLoader parent) throws IOException { super(parent); - File apiJar = downgrader.flags.findJavaApi(); + Set apiJar = downgrader.flags.findJavaApi(); if (apiJar != null) { - delegates.add(new JarFileResourceProvider(new JarFile(apiJar))); + for (File file : apiJar) { + delegates.add(new JarFileResourceProvider(new JarFile(file))); + } } this.holder = downgrader; if (downgrader.target != Utils.getCurrentClassVersion()) { From a5e0c00131290b0b62a0f7822ca405174516d6f7 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 16:17:28 -0500 Subject: [PATCH 08/15] fix bootstrap --- .../wagyourtail/jvmdg/runtime/Bootstrap.java | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java b/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java index 58ad4d4c..3cfc2809 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/runtime/Bootstrap.java @@ -19,6 +19,7 @@ import java.security.CodeSource; import java.security.MessageDigest; import java.util.HashSet; +import java.util.Set; import java.util.jar.JarFile; public class Bootstrap { @@ -66,24 +67,32 @@ public static String sha1(Path p) { public static void premain(String args, Instrumentation instrumentation) throws IOException, URISyntaxException, UnmodifiableClassException { LOGGER.info("Starting JVMDowngrader Bootstrap in agent mode."); // downgrade api - Path zip = flags.findJavaApi().toPath(); - String zipSha = sha1(zip); - Path tmp = Constants.DIR.toPath().resolve("java-api-downgraded-" + currentVersionDowngrader.target + "-" + zipSha.substring(0, 8) + ".jar"); - boolean downgrade = false; - if (!Files.exists(tmp)) { - LOGGER.warn("Downgrading java-api.jar as its hash changed or this is first launch, this may take a minute..."); - downgrade = true; - } - if (downgrade) { - Files.createDirectories(tmp.getParent()); - for (File file : tmp.getParent().toFile().listFiles()) { - if (file.isDirectory()) continue; - file.delete(); + for (File zip : flags.findJavaApi()) { + String zipSha = sha1(zip.toPath()); + String name = zip.getName(); + int idx = name.lastIndexOf('.'); + if (idx != -1) { + name = name.substring(0, idx); + } + Path tmp = Constants.DIR.toPath().resolve(name + "-downgraded-" + currentVersionDowngrader.target + "-" + zipSha.substring(0, 8) + ".jar"); + boolean downgrade = false; + if (!Files.exists(tmp)) { + LOGGER.warn("Downgrading " + zip.getName() + " as its hash changed or this is first launch, this may take a minute..."); + downgrade = true; + } + if (downgrade) { + Files.createDirectories(tmp.getParent()); + for (File file : tmp.getParent().toFile().listFiles()) { + if (file.isDirectory()) continue; + if (file.getName().startsWith(name + "-downgraded-" + currentVersionDowngrader.target) && file.getName().endsWith(".jar")) { + file.delete(); + } + } + Files.createDirectories(tmp.getParent()); + ZipDowngrader.downgradeZip(currentVersionDowngrader, zip.toPath(), new HashSet(), tmp); } - Files.createDirectories(tmp.getParent()); - ZipDowngrader.downgradeZip(currentVersionDowngrader, zip, new HashSet(), tmp); + instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(tmp.toFile())); } - instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(tmp.toFile())); // add self URL self = ClassDowngrader.class.getProtectionDomain().getCodeSource().getLocation(); instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(self.toURI().getPath())); From ea642d9b2dc02faaf848e83fd7f55f9d8699bfde Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 16:20:24 -0500 Subject: [PATCH 09/15] fix tests --- .../xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt | 1 + .../wagyourtail/jvmdg/test/integration/ClassRunner.java | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt index c8d687c0..5e01241a 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/JVMDowngraderExtension.kt @@ -45,6 +45,7 @@ abstract class JVMDowngraderExtension @Inject constructor(@get:Internal val proj /** * the main api jar to use for downgrading */ + @get:Internal var apiJarDefault by LazyMutable { val apiJar = project.file(".gradle").resolve("jvmdg/java-api-${version}.jar") if (!apiJar.exists() || project.gradle.startParameter.isRefreshDependencies) { diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java index fefee7bf..2477b43f 100644 --- a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java +++ b/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java @@ -69,7 +69,7 @@ private static Stream> zip(Stream a, Stream b) { private static Stream flags() { Flags flags = ClassRunner.flags.copy(); flags.quiet = true; - flags.api = javaApi.toFile(); + flags.api = Set.of(javaApi.toFile()); return Stream.of( new FlagsAndRunner(flags.copy(e -> e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode()), JavaRunner.JavaVersion.V1_8) @@ -176,7 +176,7 @@ private static synchronized Path getShadedJar(FlagsAndRunner flags) { "downgradetest", getDowngradedJar(flags).toFile(), target.toFile(), - getApiJar(flags).toFile() + Set.of(getApiJar(flags).toFile()) ); return target; } catch (IOException ex) { @@ -198,7 +198,7 @@ private static synchronized Path getApiJar(FlagsAndRunner flags) { Path target = getApiPath(flags); ZipDowngrader.downgradeZip( ClassDowngrader.downgradeTo(flags.flags), - flags.flags.api.toPath(), + javaApi, Set.of(), target ); @@ -390,6 +390,7 @@ public void testRuntime(String mainClass, FlagsAndRunner javaVersion) throws IOE } public static void compareResults(String mainClass, FlagsAndRunner javaVersion, Map.Entry originalResult, Map.Entry downgradedResult) { + assertEquals(0, originalResult.getKey()); assertEquals(originalResult.getValue(), downgradedResult.getValue(), "Output mismatch for " + mainClass + " on " + javaVersion.readableSlug()); assertEquals(originalResult.getKey(), downgradedResult.getKey(), "Exit code mismatch for " + mainClass + " on " + javaVersion.readableSlug()); } From 97daa46f79b8334ea654995b0a21d217ea070288 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 16:24:27 -0500 Subject: [PATCH 10/15] pt 2 --- src/main/java/xyz/wagyourtail/jvmdg/compile/ApiShader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/xyz/wagyourtail/jvmdg/compile/ApiShader.java b/src/main/java/xyz/wagyourtail/jvmdg/compile/ApiShader.java index 29071227..ccc3985b 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/compile/ApiShader.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/compile/ApiShader.java @@ -162,7 +162,7 @@ public static void shadeApis(final String prefix, final Path inputRoot, final Pa if (!prefix.endsWith("/")) throw new IllegalArgumentException("prefix must end with /"); try { // step 3: traverse the input classes for references to the api - final ReferenceGraph inputRefs = new ReferenceGraph(false); + final ReferenceGraph inputRefs = new ReferenceGraph(true); inputRefs.scan(inputRoot, new ReferenceGraph.Filter() { @Override public boolean shouldInclude(FullyQualifiedMemberNameAndDesc member) { From 9393ae8ffdd4c859aa400701447f5ad3669cb05f Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 16:41:52 -0500 Subject: [PATCH 11/15] fix gradle --- .../kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index e68cc842..a4444070 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -30,7 +30,7 @@ interface DowngradeFlags : TransformParameters { */ @get:InputFiles @get:Optional - var apiJar: ListProperty + val apiJar: ListProperty /** * sets the log level to [Logger.Level.FATAL] From 2e8769c2b21e34b63fb6189eb187bfd675ca96e1 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 16:45:03 -0500 Subject: [PATCH 12/15] add path sensitivity --- .../xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt | 5 ++--- gradle-plugin/test-downgrade/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index a4444070..01686818 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -6,9 +6,7 @@ import org.gradle.api.file.FileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.* import xyz.wagyourtail.jvmdg.cli.Flags import xyz.wagyourtail.jvmdg.logging.Logger import xyz.wagyourtail.jvmdg.util.toOpcode @@ -29,6 +27,7 @@ interface DowngradeFlags : TransformParameters { * default is null */ @get:InputFiles + @get:PathSensitive(PathSensitivity.ABSOLUTE) @get:Optional val apiJar: ListProperty diff --git a/gradle-plugin/test-downgrade/build.gradle.kts b/gradle-plugin/test-downgrade/build.gradle.kts index 12856ed8..6ec8b11c 100644 --- a/gradle-plugin/test-downgrade/build.gradle.kts +++ b/gradle-plugin/test-downgrade/build.gradle.kts @@ -89,7 +89,7 @@ sourceSets { val jvmdg = extensions.getByType(JVMDowngraderExtension::class.java) if (project.hasProperty("runningTest")) { - jvmdg.apiJar = project.file("../../java-api/build/libs/jvmdowngrader-java-api-${props.getProperty("version")}.jar") + jvmdg.apiJar = listOf(project.file("../../java-api/build/libs/jvmdowngrader-java-api-${props.getProperty("version")}.jar")) } val downgrade by configurations.creating From 0cf5c4698cd9ff8bc394971be7d1f618e912be72 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 17:02:37 -0500 Subject: [PATCH 13/15] fix checks not using outputVersion --- .../wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt | 2 +- .../java/xyz/wagyourtail/jvmdg/ClassDowngrader.java | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt index 01686818..a51cf0ee 100644 --- a/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt +++ b/gradle-plugin/src/main/kotlin/xyz/wagyourtail/jvmdg/gradle/flags/DowngradeFlags.kt @@ -27,7 +27,7 @@ interface DowngradeFlags : TransformParameters { * default is null */ @get:InputFiles - @get:PathSensitive(PathSensitivity.ABSOLUTE) + @get:PathSensitive(PathSensitivity.NONE) @get:Optional val apiJar: ListProperty diff --git a/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java b/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java index f0986aae..324ec56a 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java @@ -113,11 +113,12 @@ public synchronized Map collectProviders() { } public Set getMembers(int version, Type type, Set warnings) throws IOException { - for (int vers = version; vers > target; vers--) { + for (int vers = version; vers > target; ) { VersionProvider downgrader = downgraders.get(vers); if (downgrader == null) { throw new RuntimeException("Unsupported class version: " + vers + " supported: " + downgraders.keySet()); } + vers = downgrader.outputVersion; downgrader.ensureInit(this); Type stubbed = downgrader.stubClass(type, warnings); if (!stubbed.equals(type)) { @@ -158,11 +159,12 @@ public Set getMembers(int version, Type type, Set war } public List> getSupertypes(int version, Type type, Set warnings) throws IOException { - for (int vers = version; vers > target; vers--) { + for (int vers = version; vers > target;) { VersionProvider downgrader = downgraders.get(vers); if (downgrader == null) { throw new RuntimeException("Unsupported class version: " + vers + " supported: " + downgraders.keySet()); } + vers = downgrader.outputVersion; downgrader.ensureInit(this); Type stubbed = downgrader.stubClass(type, warnings); if (!stubbed.equals(type)) { @@ -191,11 +193,12 @@ public List> getSupertypes(int version, Type type, Set warnings) throws IOException { - for (int vers = version; vers > target; vers--) { + for (int vers = version; vers > target; ) { VersionProvider downgrader = downgraders.get(vers); if (downgrader == null) { throw new RuntimeException("Unsupported class version: " + vers + " supported: " + downgraders.keySet()); } + vers = downgrader.outputVersion; downgrader.ensureInit(this); Type stubbed = downgrader.stubClass(type, warnings); if (!stubbed.equals(type)) { @@ -214,11 +217,12 @@ public Boolean isInterface(int version, Type type, Set warnings) throws } public Type stubClass(int version, Type type, Set warnings) { - for (int vers = version; vers > target; vers--) { + for (int vers = version; vers > target;) { VersionProvider downgrader = downgraders.get(vers); if (downgrader == null) { throw new RuntimeException("Unsupported class version: " + vers + " supported: " + downgraders.keySet()); } + vers = downgrader.outputVersion; downgrader.ensureInit(this); Type stubbed = downgrader.stubClass(type, warnings); if (!stubbed.equals(type)) { From 1fc60a968dc6e0c87191447d82f1046454ec9c45 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 17:13:28 -0500 Subject: [PATCH 14/15] set to output version directly --- .../java/xyz/wagyourtail/jvmdg/version/VersionProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java index fc428325..c5ba1044 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java @@ -839,7 +839,7 @@ public ClassNode apply(ClassNode classNode) throws IOException { return null; } printWarnings(warnings, className); - clazz.version = inputVersion - 1; + clazz.version = outputVersion; return clazz; } From 6189d124bcdbd284896c4e971b87c774f0504ff9 Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Sat, 20 Jul 2024 18:00:26 -0500 Subject: [PATCH 15/15] add excludeChild option to stub --- .../jvmdg/j15/stub/java_base/J_L_CharSequence.java | 2 +- .../wagyourtail/jvmdg/version/map/ClassMapping.java | 12 ++++++++++++ .../java/xyz/wagyourtail/jvmdg/version/Stub.java | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/java-api/src/java15/java/xyz/wagyourtail/jvmdg/j15/stub/java_base/J_L_CharSequence.java b/java-api/src/java15/java/xyz/wagyourtail/jvmdg/j15/stub/java_base/J_L_CharSequence.java index bd6eb877..ab3d9707 100644 --- a/java-api/src/java15/java/xyz/wagyourtail/jvmdg/j15/stub/java_base/J_L_CharSequence.java +++ b/java-api/src/java15/java/xyz/wagyourtail/jvmdg/j15/stub/java_base/J_L_CharSequence.java @@ -4,7 +4,7 @@ public class J_L_CharSequence { - @Stub + @Stub(excludeChild = "java/lang/String") public static boolean isEmpty(CharSequence cs) { return cs.length() == 0; } diff --git a/src/main/java/xyz/wagyourtail/jvmdg/version/map/ClassMapping.java b/src/main/java/xyz/wagyourtail/jvmdg/version/map/ClassMapping.java index b14ce474..ede995e9 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/version/map/ClassMapping.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/version/map/ClassMapping.java @@ -187,6 +187,18 @@ public Pair getParentStubFor(MemberNameAndDesc member, boolean run for (ClassMapping parent : parents.get()) { Pair node = parent.getStubFor(member, false, runtimeAvailable, special, warnings); if (node != null) { + + // check if explicitly excluded from stubbing + // ie. method exists on the subtype in question + for (String child : node.getSecond().excludeChild()) { + if (child.startsWith("L") && child.endsWith(";")) { + child = child.substring(1, child.length() - 1); + } + if (child.equals(current.getInternalName())) { + return null; + } + } + return node; } } diff --git a/src/shared/java/xyz/wagyourtail/jvmdg/version/Stub.java b/src/shared/java/xyz/wagyourtail/jvmdg/version/Stub.java index 9f775952..4b959a72 100644 --- a/src/shared/java/xyz/wagyourtail/jvmdg/version/Stub.java +++ b/src/shared/java/xyz/wagyourtail/jvmdg/version/Stub.java @@ -32,4 +32,6 @@ boolean noSpecial() default false; + String[] excludeChild() default {}; + } \ No newline at end of file