From 55bfa434ec0992bb66f05091b99f5696f8cf53ab Mon Sep 17 00:00:00 2001 From: JFronny Date: Sun, 28 Aug 2022 11:43:46 +0200 Subject: [PATCH] [config-compiler-plugin] Keep original bytes for non-config classes --- build.gradle | 7 +++ libjf-config-compiler-plugin/build.gradle | 1 - .../libjf/config/plugin/StreamAction.java | 35 ++++++------ .../asm/ConfigInjectClassTransformer.java | 54 ++++++++++++------- .../plugin/asm/NotAConfigClassException.java | 7 +++ 5 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/NotAConfigClassException.java diff --git a/build.gradle b/build.gradle index d1ead15..e31c989 100644 --- a/build.gradle +++ b/build.gradle @@ -27,3 +27,10 @@ allprojects { compileOnly("io.gitlab.jfronny:commons-gson:$rootProject.commons_version") } } + +task copyVersionNumber { + doLast { + java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new java.awt.datatransfer.StringSelection("$version"), null) + println("Copied version number: $version") + } +} \ No newline at end of file diff --git a/libjf-config-compiler-plugin/build.gradle b/libjf-config-compiler-plugin/build.gradle index a6cf83c..0f30f3d 100644 --- a/libjf-config-compiler-plugin/build.gradle +++ b/libjf-config-compiler-plugin/build.gradle @@ -20,7 +20,6 @@ dependencies { implementation("io.gitlab.jfronny:commons-gson:$rootProject.commons_version") implementation("org.ow2.asm:asm:9.3") implementation("org.ow2.asm:asm-commons:9.3") - implementation("org.ow2.asm:asm-util:9.3") implementation(project(":libjf-config-core-v1")) { transitive(false) } diff --git a/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/StreamAction.java b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/StreamAction.java index 3ce45bf..12d70d9 100644 --- a/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/StreamAction.java +++ b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/StreamAction.java @@ -3,16 +3,17 @@ package io.gitlab.jfronny.libjf.config.plugin; import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.gson.stream.JsonWriter; import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer; +import io.gitlab.jfronny.libjf.config.plugin.asm.NotAConfigClassException; import io.gitlab.jfronny.libjf.config.plugin.fmj.FabricModJsonTransformer; import io.gitlab.jfronny.libjf.config.plugin.util.*; import org.apache.tools.zip.*; import org.gradle.api.GradleException; import org.gradle.api.file.FileCopyDetails; import org.objectweb.asm.*; -import org.objectweb.asm.util.CheckClassAdapter; import java.io.*; -import java.util.*; +import java.util.GregorianCalendar; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; public class StreamAction { @@ -39,7 +40,7 @@ public class StreamAction { } else { return visitFile(details); } - } catch (Exception e) { + } catch (Throwable e) { throw new GradleException("Could not add " + details + " to ZIP " + zipFile, e); } } @@ -103,7 +104,7 @@ public class StreamAction { copyArchiveEntry(archiveFilePath, archive); } return false; - } catch (IOException e) { + } catch (Throwable e) { throw new GradleException("Could not read archive entry " + archiveFilePath.getPathString(), e); } } @@ -136,25 +137,29 @@ public class StreamAction { private void processClass(RelativeArchivePath file, ZipFile archive) throws IOException { ZipEntry zipEntry = new ZipEntry(file.getPathString()); addParentDirectories(new RelativeArchivePath(zipEntry)); - processClass(archive.getInputStream(file.entry), file.getPathString(), file.entry.getTime()); + processClass(archive.getInputStream(file.entry).readAllBytes(), file.getPathString(), file.entry.getTime()); } private void processClass(FileCopyDetails details) throws IOException { - try (InputStream is = new BufferedInputStream(new FileInputStream(details.getFile()))) { - processClass(is, details.getPath(), details.getLastModified()); + try (InputStream is = new FileInputStream(details.getFile())) { + processClass(is.readAllBytes(), details.getPath(), details.getLastModified()); } } - private void processClass(InputStream classInputStream, String path, long lastModified) throws IOException { - final ClassReader reader = new ClassReader(classInputStream); - final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); - reader.accept(new CheckClassAdapter( - new ConfigInjectClassTransformer(modId, writer, knownConfigClasses) - ), ClassReader.EXPAND_FRAMES); + private void processClass(byte[] klazz, String path, long lastModified) throws IOException { + try { + final ClassReader reader = new ClassReader(klazz); + final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + final ConfigInjectClassTransformer transformer = new ConfigInjectClassTransformer(modId, writer, knownConfigClasses); + reader.accept(transformer, ClassReader.EXPAND_FRAMES); + klazz = writer.toByteArray(); + } catch (NotAConfigClassException notAConfigClass) { + // Use original bytes + } ZipEntry archiveEntry = new ZipEntry(path); archiveEntry.setTime(getArchiveTimeFor(lastModified)); zipOutStr.putNextEntry(archiveEntry); - zipOutStr.write(writer.toByteArray()); + zipOutStr.write(klazz); zipOutStr.closeEntry(); } @@ -165,7 +170,7 @@ public class StreamAction { } private void processFMJ(FileCopyDetails details) throws IOException { - try (InputStream is = new BufferedInputStream(new FileInputStream(details.getFile()))) { + try (InputStream is = new FileInputStream(details.getFile())) { processFMJ(is, details.getPath(), details.getLastModified()); } } diff --git a/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/ConfigInjectClassTransformer.java b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/ConfigInjectClassTransformer.java index 8116ff1..c424683 100644 --- a/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/ConfigInjectClassTransformer.java +++ b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/ConfigInjectClassTransformer.java @@ -35,7 +35,23 @@ public class ConfigInjectClassTransformer extends ClassVisitor { private final List verifiers = new LinkedList<>(); private final List values = new LinkedList<>(); private boolean initFound = false; - private TransformerMode mode = TransformerMode.OTHER; + private TransformerMode mode; + + public boolean isCategory() { + return mode == TransformerMode.CONFIG_CATEGORY || isConfig(); + } + + public void ensureCategory() { + if (!isCategory()) throw new NotAConfigClassException(); + } + + public boolean isConfig() { + return mode == TransformerMode.CONFIG_ROOT; + } + + public boolean isOther() { + return mode == TransformerMode.OTHER; + } public ConfigInjectClassTransformer(String modId, ClassVisitor cw, Set knownConfigClasses) { super(ASM9, cw); @@ -52,29 +68,31 @@ public class ConfigInjectClassTransformer extends ClassVisitor { @Override public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { - if (descriptor.equals(Type.getDescriptor(Category.class)) && mode == TransformerMode.OTHER) { + if (mode == null) throw new IllegalStateException("Attempted to visit annotation before class"); + if (descriptor.equals(Type.getDescriptor(Category.class)) && isOther()) { mode = TransformerMode.CONFIG_CATEGORY; return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs); } - if (descriptor.equals(Type.getDescriptor(JfConfig.class)) && mode == TransformerMode.OTHER) { + else if (descriptor.equals(Type.getDescriptor(JfConfig.class)) && isOther()) { mode = TransformerMode.CONFIG_ROOT; knownConfigClasses.add(current); return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs); + } else { + return super.visitAnnotation(descriptor, visible); } - return super.visitAnnotation(descriptor, visible); } @Override public void visitNestMember(String nestMember) { - if (mode != TransformerMode.OTHER) { - categories.add(nestMember); - } + ensureCategory(); + categories.add(nestMember); super.visitNestMember(nestMember); } @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if (mode == TransformerMode.CONFIG_ROOT) { + ensureCategory(); + if (isConfig()) { if ("".equals(name)) { initFound = true; return new ClInitInjectVisitor( @@ -85,10 +103,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor { ); } } - if (mode != TransformerMode.OTHER) { - if (name.startsWith(PREFIX)) { - throw new GradleException("This class declares methods generated by this plugin manually. Do not transform classes twice!"); - } + if (name.startsWith(PREFIX)) { + throw new GradleException("This class declares methods generated by this plugin manually. Do not transform classes twice!"); } if ((access & ACC_STATIC) == ACC_STATIC) { // Possibly add verifier or preset @@ -101,6 +117,7 @@ public class ConfigInjectClassTransformer extends ClassVisitor { @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { + ensureCategory(); if ((access & ACC_STATIC) == ACC_STATIC) { return new FieldMetaGatheringVisitor(super.visitField(access, name, descriptor, signature, value), name, values, Type.getType(descriptor)); } @@ -109,7 +126,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor { @Override public void visitEnd() { - if (mode == TransformerMode.CONFIG_ROOT) { + ensureCategory(); + if (isConfig()) { if (!initFound) { // Generate if missing GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, CLINIT, "()V", null, null); @@ -150,9 +168,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor { m.endMethod(); } } - if (mode != TransformerMode.OTHER) { - boolean root = mode == TransformerMode.CONFIG_ROOT; - Type builderType = root ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE; + { + Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE; GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, BUILDER_ROOT, getMethodDescriptor(builderType, builderType), null, null); m.loadArg(0); for (String name : referencedConfigs) { @@ -195,10 +212,9 @@ public class ConfigInjectClassTransformer extends ClassVisitor { } public void dslInvoke(GeneratorAdapter m, String name, Type returnType, Type... arguments) { - boolean root = mode == TransformerMode.CONFIG_ROOT; - Type builderType = root ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE; + Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE; m.invokeInterface(builderType, new Method(name, returnType, arguments)); - if (root) m.checkCast(CONFIG_BUILDER_TYPE); + if (isConfig()) m.checkCast(CONFIG_BUILDER_TYPE); } private String camelCase(String s) { diff --git a/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/NotAConfigClassException.java b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/NotAConfigClassException.java new file mode 100644 index 0000000..09f50df --- /dev/null +++ b/libjf-config-compiler-plugin/src/main/java/io/gitlab/jfronny/libjf/config/plugin/asm/NotAConfigClassException.java @@ -0,0 +1,7 @@ +package io.gitlab.jfronny.libjf.config.plugin.asm; + +public class NotAConfigClassException extends RuntimeException { + public NotAConfigClassException() { + super("This class is not a config class and should not be modified"); + } +}