### Use Vineflower decompiler API in Java Source: https://vineflower.org/usage-code Demonstrates the core API usage for Vineflower decompiler. Shows how to configure inputs, outputs, options, and execute decompilation. ```Java Decompiler decompiler = new Decompiler.Builder() .inputs(inputFile) // also accepts IContextSource .output(new SingleFileSaver(outputJar)) // also accepts DirectoryResultSaver, or a custom IResultSaver implementation .option(IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, true) // optional, change options for the decompiler .logger(new IFernflowerLogger() { ... }) // optional, provide a logger impl for the decompiler to use .libraries(libraryFile) // optional, include libraries to enhance the decompiler's analysis but not decompile .build(); decompiler.decompile(); // Done! ``` -------------------------------- ### Double Brace Initializers in Enums (Java) Source: https://vineflower.org/output-comparison Illustrates the decompilation of enums using double brace initializers, a feature that can be challenging for decompilers. Compares how different tools handle the syntax and modifiers. ```Java public enum TestEnum { A {{ System.out.println("A"); }}, B {{ System.out.println("B"); }} } ``` ```Java public static enum TestEnum { A { { System.out.println("A"); } }, B { { System.out.println("B"); } }; } ``` ```Java public static enum TestEnum { A { private { System.out.println("A"); } }, B { private { System.out.println("B"); } }; } ``` ```Java public static enum TestEnum { A{ { System.out.println("A"); } } , B{ { System.out.println("B"); } }; } ``` ```Java public enum TestEnum permits TestEnum$1, TestEnum$2 { A { { System.out.println("A"); } }, B { { System.out.println("B"); } }; } ``` -------------------------------- ### Java: Try-with-resources with finally block (Java 16) Source: https://vineflower.org/output-comparison Illustrates the decompilation of a try-with-resources statement combined with a finally block, using bytecode generated from Java 16. Vineflower, CFR, and Procyon decompile this construct correctly, whereas Fernflower and JD-GUI do not recognize the pattern and produce more verbose or incorrect code. ```java public void test(File file) throws FileNotFoundException { try (Scanner scanner = new Scanner(file)) { scanner.next(); } finally { System.out.println("Hello"); } } ``` ```java public void test(File file) throws FileNotFoundException { try { Scanner scanner = new Scanner(file); try { scanner.next(); } catch (Throwable var10) { try { scanner.close(); } catch (Throwable var9) { var10.addSuppressed(var9); } throw var10; } scanner.close(); } finally { System.out.println("Hello"); } } ``` ```java public void test(File file) throws FileNotFoundException { try (Scanner scanner = new Scanner(file);){ scanner.next(); } finally { System.out.println("Hello"); } } ``` ```java public void test(final File file) throws FileNotFoundException { try (final Scanner scanner = new Scanner(file)) { scanner.next(); } finally { System.out.println("Hello"); } } ``` ```java public void test(File file) throws FileNotFoundException { try { Scanner scanner = new Scanner(file); try { scanner.next(); scanner.close(); } catch (Throwable throwable) { try { scanner.close(); } catch (Throwable throwable1) { throwable.addSuppressed(throwable1); } throw throwable; } } finally { System.out.println("Hello"); } } ``` -------------------------------- ### Vineflower decompiled definite assignment test Source: https://vineflower.org/output-comparison Vineflower's reconstruction of the definite assignment test method. Demonstrates how Vineflower simplifies complex conditionals and handles variable assignments in control flow structures. Shows differences in block organization compared to original source. ```java void testAssignments(int n, boolean bool) { if (bool) { int a = n; if (n > 0 || (a = -n) > 100) { System.out.println(a); } } int b; if (!bool && (b = n * n) <= 0) { System.out.println(b); } else { System.out.println("b"); } double cFake = 0.01; System.out.println(cFake); if (n < 1.0 - n && (cFake = n + 5) > cFake * cFake - cFake / 2.0 ? !(n > cFake) : !(n < 5.0 - (cFake = n))) { cFake += 5.0; } else { System.out.println(cFake); cFake += 2.0; } System.out.println(cFake); double d; if ((d = n) > 0.0) { System.out.println(d); } } ``` -------------------------------- ### Decompile While Loop with Break Source: https://vineflower.org/output-comparison Illustrates how different decompilers handle `while` loops with `break` statements. The test cases explore varying loop structures and exit conditions, examining the decompilers' ability to reconstruct the original logic. ```Java public void test(int i) { while (i > 10) { i++; if (i == 15) { break; } System.out.println(0); } } ``` ```Java public void test(int i) { while (i > 10) { if (++i != 15) { System.out.println(0); continue; } break; } } ``` ```Java public void test(int i) { while(true) { if (i > 10) { ++i; if (i != 15) { System.out.println((int)0); continue; } } return; } } ``` ```Java public void test(int i) { while (i > 10 && ++i != 15) { System.out.println(0); } } ``` ```Java public void test(int i) { while (i > 10 && ++i != 15) { System.out.println(0); } } ``` ```Java public void test(int i) { i++; while (i > 10 && i != 15) System.out.println(0); } ``` -------------------------------- ### Configure Sonatype snapshots repository in Gradle (Kotlin) Source: https://vineflower.org/usage-code Configures Gradle (Kotlin DSL) to use Sonatype OSS snapshots repository for accessing Vineflower development builds. ```Kotlin repositories { maven(url = "https://central.sonatype.com/repository/maven-snapshots/") { name = "sonatype-central-snapshots" } } ``` -------------------------------- ### Configure Sonatype snapshots repository in Maven Source: https://vineflower.org/usage-code Configures Maven to use Sonatype OSS snapshots repository for accessing Vineflower development builds. ```XML sonatype-central-snapshots https://central.sonatype.com/repository/maven-snapshots/ ``` -------------------------------- ### Decompile Java method with pattern matching in argument Source: https://vineflower.org/output-comparison Demonstrates decompilation of a method that uses pattern matching (instanceof with variable) to compute a boolean argument for another method call. The source uses a concise expression; decompilers vary between preserving the pattern match and introducing temporary variables or labels. ```Java (Vineflower) public void test(Object o) { this.accept(o, o instanceof String s && s.length() > 5); } ``` ```Java (Fernflower) public void test(Object o) { boolean var10002; label12: { if (o instanceof String s) { if (s.length() > 5) { var10002 = true; break label12; } } var10002 = false; } this.accept(o, var10002); } ``` ```Java (CFR) public void test(Object o) { String s; Object object = o; this.accept(o, object instanceof String && (s = (String)object).length() > 5); } ``` ```Java (Procyon) public void test(final Object o) { boolean b = false; Label_0029: { if (o instanceof final String s) { if (s.length() > 5) { b = true; break Label_0029; } } b = false; } this.accept(o, b); } ``` -------------------------------- ### Configure Sonatype snapshots repository in Gradle (Groovy) Source: https://vineflower.org/usage-code Configures Gradle (Groovy DSL) to use Sonatype OSS snapshots repository for accessing Vineflower development builds. ```Groovy repositories { maven { name = "sonatype-central-snapshots" url = "https://central.sonatype.com/repository/maven-snapshots/" } } ``` -------------------------------- ### Switch Pattern Matching (Java 21) Source: https://vineflower.org/output-comparison Shows the decompilation of Java 21's switch pattern matching feature. Evaluates which decompilers can correctly reconstruct switch expressions and handle the underlying invokedynamic calls. ```Java public String test2(Object o) { return switch (o) { case Integer i -> Integer.toString(i); case String s -> s; default -> "null"; }; } ``` ```Java public String test2(Object o) { return switch (o) { case Integer i -> Integer.toString(i); case String s -> s; default -> "null"; }; } ``` ```Java public String test2(Object o) { String var10000; switch (o) { case Integer i -> var10000 = Integer.toString(i); case String s -> var10000 = s; default -> var10000 = "null"; } return var10000; } ``` ```Java public String test2(Object o) { Object object = o; Objects.requireNonNull(object); Object object2 = object; int n = 0; return switch (SwitchBootstraps.typeSwitch("typeSwitch", new Object[]{Integer.class, String.class}, (Object)object2, n)) { case 0 -> { Integer i = (Integer)object2; yield Integer.toString(i); } case 1 -> { String s; yield s = (String)object2; } default -> "null"; }; } ``` ```Java public String test2(final Object o) { Objects.requireNonNull(o); String string = null; switch (/* invokedynamic(!) */ProcyonInvokeDynamicHelper_2.invoke(o, false)) { case 0: { final Integer i = (Integer)o; string = Integer.toString(i); break; } case 1: { final String s = string = (String)o; break; } default: { string = "null"; break; } } return string; } ``` -------------------------------- ### Boxing and Unboxing in Conditional Statements (Java) Source: https://vineflower.org/output-comparison Demonstrates how different Java decompilers handle boxing and unboxing operations within conditional statements. Some decompilers may incorrectly unbox constants, leading to syntax errors. ```Java public void test(int x) { if ((x ^ 126) == 7) { Integer.valueOf(0xFFFF); } else { Boolean.valueOf(false); } Float.valueOf(0.9f); } ``` ```Java public void test(int x) { if ((x ^ 126) == 7) { Integer.valueOf(65535); } else { Boolean.valueOf(false); } Float.valueOf(0.9F); } ``` ```Java public void test(int x) { if ((x ^ 126) == 7) { 65535; } else { false; } 0.9F; } ``` ```Java public void test(int x) { if ((x ^ 0x7E) == 7) { Integer.valueOf(65535); } else { Boolean.valueOf(false); } Float.valueOf(0.9f); } ``` ```Java public void test(final int x) { if ((x ^ 0x7E) == 0x7) { 65535; } else { false; } 0.9f; } ``` ```Java public void test(int x) { if ((x ^ 0x7E) == 7) { Integer.valueOf(65535); } else { Boolean.valueOf(false); } Float.valueOf(0.9F); } ``` -------------------------------- ### Decompile Java switch expression method Source: https://vineflower.org/output-comparison Shows how various decompilers translate a Java 14 switch expression that returns a string based on an integer input. No external dependencies are required. The method returns a string for cases 1 and 2, otherwise "Unknown". Some decompilers generate auxiliary variables or malformed code. ```Java (Vineflower) public String test(int i) { return switch (i) { case 1 -> "1"; case 2 -> "2"; default -> "Unknown"; }; } ``` ```Java (CFR) public String test(int i) { return switch (i) { case 1 -> "1"; case 2 -> "2"; default -> "Unknown"; }; } ``` ```Java (Procyon) public void test(final int i) { return switch (i) { case 1 -> "1"; case 2 -> "2"; default -> "Unknown"; }; } ``` ```Java (Fernflower) public String test(int i) { String var10000; switch (i) { case 1 -> var10000 = "1"; case 2 -> var10000 = "2"; default -> var10000 = "Unknown"; } return var10000; } ``` ```Java (JD-GUI) public String test(int i) { switch (i) { case 1: case 2: } return "Unknown"; } ``` -------------------------------- ### Procyon decompiled definite assignment test Source: https://vineflower.org/output-comparison Procyon's reconstruction of the definite assignment test method. Uses labeled break constructs and final variable modifiers. Shows different approaches to handling conditional expressions compared to other decompilers. ```java void testAssignments(final int n, final boolean bool) { if (bool) { int a = n; if (n > 0 || (a = -n) > 100) { System.out.println(a); } } Label_0062: { if (!bool) { int b = n; if ((b *= n) <= 0) { System.out.println(b); break Label_0062; } } System.out.println("b"); } final double cFake = 0.01; System.out.println(cFake); double c = 0.0; Label_0161: { Label_0153: { if (n >= 1.0 - n || (c = n + 5) <= c * c - c / 2.0) { if (n >= 5.0 - (c = n)) { break Label_0153; } } else if (n <= c) { break Label_0153; } System.out.println(c); c += 2.0; break Label_0161; } c += 5.0; } System.out.println(c); final double d; final boolean x; if (x = ((d = n) > 0.0)) { System.out.println(d); } } ``` -------------------------------- ### Original Source: Nameless Local Class Test - Java Source: https://vineflower.org/output-comparison This source code demonstrates a nameless local class assigned to a var variable, defining a println method that prints to System.out. The method calls println with a string argument. Purpose: Tests decompiler support for Java 10+ var and anonymous classes. Limitations: Requires Java 10+ for var keyword. ```java public void testNamelessTypeVirtual() { var printer = new Object() { void println(String s) { System.out.println(s); } }; printer.println("goodbye, world!"); } ``` -------------------------------- ### Decompiling Java 21 Record Patterns Source: https://vineflower.org/output-comparison Record patterns enable destructuring in pattern matching, introduced in Java 21, allowing concise instanceof checks with variable binding. This snippet displays the source method using record patterns and decompiled versions, where Vineflower approximates it with synthetic variables but others use verbose try-catch for shared exception handling. Depends on record definition; inputs are bytecode, outputs vary in readability and correctness, with limitations in preserving pattern syntax and control flow. ```Java public void test1(R r) { if (r instanceof R(int x, Object o)) { System.out.println(x); System.out.println(o); } } // Not shown in decompiled output for space record R(int i, Object o) {} ``` ```Java public void test1(R r) { if (r instanceof R(int var5, Object var8)) { System.out.println(var5); System.out.println(var8); } } ``` ```Java public void test1(R r) { if (r instanceof R) { R var10000 = r; try { var9 = var10000.i(); } catch (Throwable var7) { throw new MatchException(var7.toString(), var7); } int o = var9; int x = o; var10000 = r; try { var11 = var10000.o(); } catch (Throwable var6) { throw new MatchException(var6.toString(), var6); } Object o = var11; System.out.println(x); System.out.println(o); } } ``` ```Java public void test1(R r) { if (r instanceof R) { Object object; int x; R r2 = r; try { int n; x = n = r2.i(); } catch (Throwable throwable) { throw new MatchException(throwable.toString(), throwable); } Object o = object = r2.o(); System.out.println(x); System.out.println(o); } } ``` ```Java public void test1(final R r) { while (true) { if (r instanceof R) { try { final int x = r.i(); final Object o = r.o(); System.out.println(x); System.out.println(o); } catch (final Throwable cause) { throw new MatchException(cause.toString(), cause); } return; } continue; } } ``` ```Java public void test1(R r) { if (r instanceof R) { R r1 = r; try { int i = r1.i(), x = i; Object object1 = r1.o(), o = object1; System.out.println(x); System.out.println(o); } catch (Throwable throwable) { throw new MatchException(throwable.toString(), throwable); } } } ``` -------------------------------- ### Decompile Java method using null in generic context Source: https://vineflower.org/output-comparison Illustrates decompilation of a method that retrieves an Optional from a map and returns its value or null. The code works with standard Java collections and Optional. Some decompilers add unnecessary casts, while JD-GUI inserts extra type casts for the map key. ```Java (Vineflower) public Object doThing(Map> map) { return map.get(0).orElse(null); } ``` ```Java (CFR) public Object doThing(Map> map) { return map.get(0).orElse(null); } ``` ```Java (Fernflower) public Object doThing(Map> map) { return (map.get(0)).orElse((Object)null); } ``` ```Java (Procyon) public Object doThing(final Map> map) { return map.get(0).orElse((Object)null); } ``` ```Java (JD-GUI) public Object doThing(Map> map) { return ((Optional)map.get(Integer.valueOf(0))).orElse(null); } ``` -------------------------------- ### JD-GUI Decompilation: Nameless Local Class - Java Source: https://vineflower.org/output-comparison JD-GUI incorrectly decompiles by creating a named Object without the inner class definition, passing 'this' to the constructor and calling println directly on it. No var usage. Limitations: Completely misses the anonymous class structure, resulting in non-compilable or incorrect code. ```java public void testNamelessTypeVirtual() { Object object = new Object(this); object.println("goodbye, world!"); } ``` -------------------------------- ### Test definite assignment with complex conditionals in Java Source: https://vineflower.org/output-comparison Original test method demonstrating various definite assignment scenarios in Java. Shows complex conditional expressions with embedded assignments and control flow constructs. Used as input for comparing decompiler outputs. ```java void testAssignments(int n, boolean bool) { int a; if (bool && ((a = n) > 0 || (a = -n) > 100)) { System.out.println(a); } int b; if (bool || (b = (b = n) * b) > 0) { System.out.println("b"); } else { System.out.println(b); } { double cFake = 0.01; System.out.println(cFake); } double c; if (!((n < 1.0 - n) && (c = (n + 5)) > (c * c - c / 2)) ? n < 5.0 - (c = n) : n > c) { System.out.println(c); c += 2; } else { c += 5; } System.out.println(c); boolean x; double d; if (x = ((d = n) > 0)) { System.out.println(d); } } ``` -------------------------------- ### JD-GUI decompiled definite assignment test Source: https://vineflower.org/output-comparison JD-GUI's reconstruction of the definite assignment test method. Maintains some structural similarity to the original source. Uses explicit double literal suffixes (D) and simplified conditional expressions. ```java void testAssignments(int n, boolean bool) { int a; if (bool && ((a = n) > 0 || (a = -n) > 100)) System.out.println(a); int b; if (bool || (b = (b = n) * b) > 0) { System.out.println("b"); } else { System.out.println(b); } double cFake = 0.01D; System.out.println(cFake); double c; if (((c = (n + 5)) <= c * c - c / 2.0D) ? (n < 5.0D - (c = n)) : (n > c)) { System.out.println(c); c += 2.0D; } else { c += 5.0D; } System.out.println(c); boolean x; double d; if (x = ((d = n) > 0.0D)) System.out.println(d); } ``` -------------------------------- ### CFR Decompilation: Switch Loop with Labeled Break - Java Source: https://vineflower.org/output-comparison CFR fails to fully structure the code, using a for loop but approximating the labeled break with a goto label and continue statement. It assumes j is declared externally and includes diagnostic comments. Inputs: int i. Outputs: Prints with goto-based flow. Limitations: Relies on unstructured goto, incomplete variable scoping. ```java /* * Unable to fully structure code */ public void test8(int i) { switch (i) { case 0: { for (j = 0; j < 10; ++j) { if (j != 3) { continue; } ** GOTO lbl8 } System.out.println(0); lbl8: // 2 sources System.out.println("after"); } case 1: { System.out.println(1); } } System.out.println("after2"); } ``` -------------------------------- ### Decompile Super Wildcard Synthetic Cast Source: https://vineflower.org/output-comparison Demonstrates how decompilers handle synthetic casts, specifically related to super wildcards in generic types. The test aims to evaluate the decompression of code requiring type casts that are not explicitly present in the bytecode. ```Java public Class test(Inner inner) { Class t = (Class) inner.get(); return (Class) inner.get(); } // Not shown in decompiled output for space public class Inner { public Class get() { return null; } } ``` ```Java public Class test(Inner inner) { Class t = inner.get(); return inner.get(); } ``` ```Java public Class test(Inner inner) { Class t = inner.get(); return inner.get(); } ``` ```Java public Class test(final Inner inner) { final Class t = (Class)inner.get(); return (Class)inner.get(); } ``` ```Java public Class test(Inner inner) { Class t = inner.get(); return inner.get(); } ``` -------------------------------- ### Fernflower decompiled definite assignment test Source: https://vineflower.org/output-comparison Fernflower's reconstruction of the definite assignment test method. Shows labeled break constructs and explicit type casting behavior. Illustrates how Fernflower handles nested conditionals with goto-like structures. ```java void testAssignments(int n, boolean bool) { int a; if (bool && (n > 0 || (a = -n) > 100)) { System.out.println(a); } int b; if (!bool && (b = n * n) <= 0) { System.out.println(b); } else { System.out.println("b"); } double cFake; label38: { label55: { cFake = 0.01; System.out.println(cFake); if ((double)n < (double)1.0F - (double)n && (cFake = (double)(n + 5)) > cFake * cFake - cFake / (double)2.0F) { if ((double)n > cFake) { break label55; } } else if ((double)n < (double)5.0F - (cFake = (double)n)) { break label55; } cFake += (double)5.0F; break label38; } System.out.println(cFake); cFake += (double)2.0F; } System.out.println(cFake); double d; if ((d = (double)n) > (double)0.0F) { System.out.println(d); } } ``` -------------------------------- ### Procyon Decompilation: Switch Loop with Labeled Break - Java Source: https://vineflower.org/output-comparison Procyon's output incorrectly nests a for loop inside a while(true), leading to infinite loop potential and misplaced print statements for the labeled break. It adds final to parameters. Dependencies: None. Limitations: Distorts control flow, printing 'after' inside the if condition instead of after the loop. ```java public void test8(final int i) { switch (i) { case 0: { while (true) { for (int j = 0; j < 10; ++j) { if (j == 3) { System.out.println("after"); } } System.out.println(0); continue; } } case 1: { System.out.println(1); break; } } System.out.println("after2"); } ``` -------------------------------- ### Add Vineflower dependency in Gradle (Kotlin) Source: https://vineflower.org/usage-code Adds Vineflower as a dependency in a Gradle project using Kotlin DSL. Configures Maven Central repository and implementation dependency. ```Kotlin repositories { mavenCentral() } dependencies { implementation("org.vineflower:vineflower:1.11.2") } ``` -------------------------------- ### CFR Decompilation: Nameless Local Class - Java Source: https://vineflower.org/output-comparison CFR correctly uses var for the nameless local class and reconstructs the anonymous Object with the println method, similar to the source. It handles the method call properly. Dependencies: Java 10+ var support. Limitations: Minor formatting differences, but functionally accurate. ```java public void testNamelessTypeVirtual() { var printer = new Object(){ void println(String s) { System.out.println(s); } }; printer.println("goodbye, world!"); } ``` -------------------------------- ### Add Vineflower dependency in Gradle (Groovy) Source: https://vineflower.org/usage-code Adds Vineflower as a dependency in a Gradle project using Groovy DSL. Configures Maven Central repository and implementation dependency. ```Groovy repositories { mavenCentral() } dependencies { implementation "org.vineflower:vineflower:1.11.2" } ``` -------------------------------- ### Procyon Decompilation: Nameless Local Class - Java Source: https://vineflower.org/output-comparison Procyon infers the type as Object without using var, adding final to the local variable and parameter. It reconstructs the anonymous class but loses the var inference. Outputs: Prints the string. Limitations: Invalid without var, requires explicit Object type. ```java public void testNamelessTypeVirtual() { final Object printer = new Object() { void println(final String s) { System.out.println(s); } }; printer.println("goodbye, world!"); } ``` -------------------------------- ### Original Source: Switch Loop with Labeled Break Test - Java Source: https://vineflower.org/output-comparison This source code implements a switch statement containing a for loop with a labeled break to test decompiler handling of nested control flow. The method takes an int parameter i and prints values based on the case, exiting the loop early at j==3. Dependencies: Java standard library for System.out. Limitations: Tests specific to Java 8+ labeled statements. ```java public void test8(int i) { switch (i) { case 0: label: { for (int j = 0; j < 10; j++) { if (j == 3) { break label; } } System.out.println(0); } System.out.println("after"); case 1: System.out.println(1); } System.out.println("after2"); } ``` -------------------------------- ### Decompiling Java 15 Text Blocks Source: https://vineflower.org/output-comparison Text blocks are multi-line string literals introduced in Java 15, compiling to the same bytecode as concatenated strings. This snippet shows the original source text block and decompiled outputs from various tools, which mostly convert it to escaped newline strings except Procyon. No external dependencies; inputs are bytecode from the source, outputs are readable Java code with potential loss of original formatting. ```Java private final String text = """ Hello! This is a text block! It's multiple lines long. I can use "quotes" in it. It's rather cool. """; ``` ```Java private final String text = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n"; ``` ```Java private final String text = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n"; ``` ```Java private final String text = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n"; ``` ```Java private final String text = """ Hello! This is a text block! It's multiple lines long. I can use "quotes" in it. It's rather cool. """; ``` ```Java private final String text = "Hello!\nThis is a text block!\nIt's multiple lines long.\nI can use \"quotes\" in it.\nIt's rather cool.\n"; ``` -------------------------------- ### Decompile Local Enums in Java Source: https://vineflower.org/output-comparison Demonstrates how different decompilers handle Java 16 local enums. Local enums are created within a method and have scope limited to that method. This tests the decompilers' ability to recognize and reproduce this feature accurately. ```Java public void test(int i) { enum Type { VALID, INVALID } Type type = i == 0 ? Type.VALID : Type.INVALID; } ``` ```Java public void test(int i) { enum Type { VALID, INVALID; } Type type = i == 0 ? Type.VALID : Type.INVALID; } ``` ```Java public void test(int i) { final class Type extends Enum { VALID, INVALID; // $FF: synthetic method private static Type[] $values() { return new Type[]{VALID, INVALID}; } } Type type = i == 0 ? Type.VALID : Type.INVALID; } ``` ```Java public void test(int i) { static enum Type { VALID, INVALID; } Type type = i == 0 ? Type.VALID : Type.INVALID; } ``` ```Java public void test(final int i) { enum Type { VALID, INVALID; } final Type type = (i == 0) ? Type.VALID : Type.INVALID; } ``` ```Java public void test(int i) { Type type = (i == 0) ? Type.VALID : Type.INVALID; } ``` -------------------------------- ### CFR decompiled definite assignment test Source: https://vineflower.org/output-comparison CFR's reconstruction of the definite assignment test method. Uses goto statements and block labels to represent complex control flow. Indicates inability to fully structure some code segments with explicit comments. ```java /* * Unable to fully structure code */ void testAssignments(int n, boolean bool) { block6: { if (bool && ((a = n) > 0 || (a = -n) > 100)) { System.out.println(a); } if (bool) ** GOTO lbl-1000 b = n; if ((b *= b) > 0) lbl-1000: // 2 sources { System.out.println("b"); } else { System.out.println(b); } cFake = 0.01; System.out.println(cFake); if ((double)n < 1.0 - (double)n && (c = (double)(n + 5)) > c * c - c / 2.0) break block6; c = n; if (!((double)n < 5.0 - v0)) ** GOTO lbl-1000 ** GOTO lbl-1000 } if ((double)n > c) lbl-1000: // 2 sources { System.out.println(c); c += 2.0; } else lbl-1000: // 2 sources { c += 5.0; } System.out.println(c); d = n; x = v1 > 0.0; if (x) { System.out.println(d); } } ``` -------------------------------- ### Vineflower Decompilation: Switch Loop with Labeled Break - Java Source: https://vineflower.org/output-comparison Vineflower's output reconstructs the control flow using a while loop with condition checks for the loop bounds and labeled break, correctly placing prints after the loop. It takes int i as input and outputs prints accordingly. Limitations: Converts for loop to while loop, losing original iteration structure. ```java public void test8(int i) { switch (i) { case 0: int j = 0; while (true) { if (j >= 10) { System.out.println(0); break; } if (j == 3) { break; } j++; } System.out.println("after"); case 1: System.out.println(1); } System.out.println("after2"); } ``` -------------------------------- ### Java: Shift left operation on long array Source: https://vineflower.org/output-comparison Demonstrates the decompilation of a loop involving a left shift operation on a long array element. Fernflower fails to decompile this snippet due to a bug in its statement resugaring, while Vineflower, CFR, Procyon, and JD-GUI successfully decompile it. ```java public static void test(long[] l) { long x = l[0]; for (int i = 1; i < 2; i++) { x <<= 3; } x = l[4]; } ``` ```java public static void test(long[] l) { // $FF: Couldn't be decompiled } ``` ```java public static void test(long[] l) { long x = l[0]; for (int i2 = 1; i2 < 2; ++i2) { x <<= 3; } x = l[4]; } ``` ```java public static void test(final long[] l) { long x = l[0]; for (int i = 1; i < 2; ++i) { x <<= 3; } x = l[4]; } ``` ```java public static void test(long[] l) { long x = l[0]; for (int i = 1; i < 2; i++) x <<= 3L; x = l[4]; } ``` -------------------------------- ### Fernflower Decompilation: Nameless Local Class - Java Source: https://vineflower.org/output-comparison Fernflower struggles with type inference, using placeholders for the var variable and casting. It reconstructs the anonymous class but fails to name the local variable properly. Outputs: Prints the string via the method. Limitations: Unresolvable types lead to compilation errors. ```java public void testNamelessTypeVirtual() { printer = ()(new Object() { void println(String s) { System.out.println(s); } }); printer.println("goodbye, world!"); } ``` -------------------------------- ### Add Vineflower dependency in Maven Source: https://vineflower.org/usage-code Adds Vineflower as a dependency in a Maven project. Specifies the group ID, artifact ID, and version for Maven Central. ```XML org.vineflower vineflower 1.11.2 ``` -------------------------------- ### Fernflower Decompilation: Switch Loop with Labeled Break - Java Source: https://vineflower.org/output-comparison Fernflower's decompilation uses a while loop similar to Vineflower, with increment via ++j and explicit casts on println arguments. It preserves the control flow but does not recover the for loop. Dependencies: Java runtime. Limitations: Adds unnecessary type casts like (int)0. ```java public void test8(int i) { switch (i) { case 0: int j = 0; while(true) { if (j >= 10) { System.out.println((int)0); break; } if (j == 3) { break; } ++j; } System.out.println("after"); case 1: System.out.println((int)1); } System.out.println("after2"); } ``` -------------------------------- ### Java: Double casted float precision handling Source: https://vineflower.org/output-comparison Compares how different Java decompilers handle the implicit casting of a float constant to a double. Vineflower, Fernflower, and CFR correctly represent the constant as a float, while Procyon and JD-GUI use a rounded double literal. Fernflower also includes an unnecessary explicit cast. ```java public void test() { double x = 0.2F; } ``` ```java public void test() { double x = (double)0.2F; } ``` ```java public void test() { double x = 0.2f; } ``` ```java public void test() { final double x = 0.20000000298023224; } ``` ```java public void test() { double x = 0.20000000298023224D; } ```