bytecode-viewer icon indicating copy to clipboard operation
bytecode-viewer copied to clipboard

Add support for Quiltflower

Open nick-botticelli opened this issue 3 years ago • 10 comments

Quiltflower is a fork of Fernflower aiming to be faster, produce more readable Java code, and has additional features and fixes.

There is one significant issue: it is a fork that leaves the original package and class names untouched, and I cannot find a way to relocate the package under Maven—so, either an issue is filed and the maintainers of Quiltflower decide to relocate their packages to prevent conflicts with Fernflower (unlikely), or a fork is created to (potentially automatically) handle upstream changes to Quiltflower and put them in a relocated package that doesn't conflict (more time-consuming).

Here is an example of some ugly code from a personal project decompiled with Fernflower vs. Quiltflower. Some code has more changes than others, as well as a few possible regressions. This was decompiled using a single Java 8 class with the latest of both decompilers.

I currently have a working local build of bytecode-viewer up and running with this decompiler (replacing original Fernflower). Let me know what you think and if you think work on a proper Pull Request should be done.

nick-botticelli avatar May 27 '22 02:05 nick-botticelli

I already knew that his request might come at some point since I have had the same idea for ForgeFlower as well :) Relocating could also be done in BCV's build process, but I would need to try that at some point. In fact, BCV uses the maven-shade-plugin which has such capabilities. Otherwise, a "switch" or something could be implemented which is able to download FernFlower forks to a temporary folder and add them to the current ClassLoader that way. After a restart of BCV, these classes are loaded instead then. This would require removing FernFlower from the shaded BytecodeViewer-XXX.jar and adding the respective downloads in Boot.java.

ThexXTURBOXx avatar May 27 '22 06:05 ThexXTURBOXx

I already knew that his request might come at some point since I have had the same idea for ForgeFlower as well :) Relocating could also be done in BCV's build process, but I would need to try that at some point. In fact, BCV uses the maven-shade-plugin which has such capabilities. Otherwise, a "switch" or something could be implemented which is able to download FernFlower forks to a temporary folder and add them to the current ClassLoader that way. After a restart of BCV, these classes are loaded instead then. This would require removing FernFlower from the shaded BytecodeViewer-XXX.jar and adding the respective downloads in Boot.java.

I am researching maven-shade-plugin functionality right now. What would be a good standard for relocated package names?

nick-botticelli avatar May 27 '22 07:05 nick-botticelli

That's a good question. Maybe something like quiltflower.<originalpackage> and forgeflower.<originalpackage> and so on. However, I cannot guarantee success with that approach since the decompilers might use reflection which will (of course) not get relocated. We would need to test this approach thoroughly :)

ThexXTURBOXx avatar May 27 '22 07:05 ThexXTURBOXx

That's a good question. Maybe something like quiltflower.<originalpackage> and forgeflower.<originalpackage> and so on. However, I cannot guarantee success with that approach since the decompilers might use reflection which will (of course) not get relocated. We would need to test this approach thoroughly :)

I'm about to give up on a solution that doesn't use reflection in FernFlowerDecompiler and (now) QuiltFlowerDecompiler. I can relocate the classes successfully, but I cannot figure out how to get FernFlowerDecompiler and QuiltFlowerDecompiler to use separate packages (or excluding FernFlowerDecompiler from the first execution, which results in it missing in the JAR). Would reflection be acceptable? Here's a draft demonstrating this:

                <executions>
                    <execution>
                        <id>shade-1</id>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <includes>
                                    <include>org.quiltmc:quiltflower</include>
                                </includes>
                            </artifactSet>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                </filter>
                            </filters>
                            <relocations>
                                <relocation>
                                    <pattern>org.jetbrains.java.decompiler</pattern>
                                    <shadedPattern>org.jetbrains.java.decompiler.quilt</shadedPattern>
                                </relocation>
                            </relocations>
                        </configuration>
                    </execution>
                    <execution>
                        <id>shade-2</id>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <excludes>
                                    <exclude>org.quiltmc:quiltflower</exclude>
                                </excludes>
                            </artifactSet>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>**/module-info.class</exclude>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                        <exclude>META-INF/*LICENSE*</exclude>
                                        <exclude>META-INF/*NOTICE*</exclude>
                                        <exclude>META-INF/MANIFEST.MF</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>the.bytecode.club.bytecodeviewer.BytecodeViewer</mainClass>
                                    <manifestEntries>
                                        <Implementation-Version>${project.version}</Implementation-Version>
                                        <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
                                        <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
                                    </manifestEntries>
                                </transformer>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>

nick-botticelli avatar May 27 '22 08:05 nick-botticelli

Haven't tried it myself yet, so there could be unseen or unexpected problems. I will try some stuff on that myself next week maybe. This weekend I am sadly very busy because of my studies and research

ThexXTURBOXx avatar May 27 '22 08:05 ThexXTURBOXx

Ok. For now I will write Fernflower to use reflection and call it a day—I'll try and get my code up on my fork soon.

nick-botticelli avatar May 27 '22 08:05 nick-botticelli

Very nice, thank you very much! I will most likely create a PR on your branch at some point if I find anything useful :)

ThexXTURBOXx avatar May 27 '22 08:05 ThexXTURBOXx

So apparently Quiltflower is actually based on ForgeFlower? Not sure if adding ForgeFlower would qualify as bloat. My changes are pushed to my fork.

nick-botticelli avatar May 27 '22 11:05 nick-botticelli

Any update on this? Quiltflower has quite diverged from Fernflower feature- and quality-wise, so IMO it would be a valid addition

NebelNidas avatar Mar 05 '23 21:03 NebelNidas

A solution would be to use a multi-module maven project. A quiltflower-relocate module could shade and relocate and then the mainmodule can depend on the quiltflower-relocate module and access the relocated classes under their new address.

Janmm14 avatar Mar 06 '23 00:03 Janmm14