Convert Figma logo to code with AI

leibnitz27 logocfr

This is the public repository for the CFR Java decompiler

2,014
260
2,014
151

Top Related Projects

IntelliJ IDEA Community Edition & IntelliJ Platform

Unofficial mirror of FernFlower Java decompiler (All pulls should be submitted upstream)

A Java 8+ Jar & Android APK Reverse Engineering Suite (Decompiler, Editor, Debugger & More)

41,326

Dex to Java decompiler

14,011

A standalone Java Decompiler GUI

4,999

An Open Source Java Decompiler Gui for Procyon

Quick Overview

CFR (Class File Reader) is a Java decompiler and static analysis tool. It aims to produce high-quality Java source code from compiled class files, with a focus on accuracy and readability. CFR is designed to handle modern Java features and obfuscated code.

Pros

  • Supports latest Java features, including Java 17 and beyond
  • Handles complex and obfuscated code effectively
  • Produces highly readable and well-formatted output
  • Actively maintained and regularly updated

Cons

  • Can be slower than some other decompilers for large projects
  • May struggle with certain types of heavily obfuscated code
  • Limited GUI options, primarily command-line based
  • Documentation could be more comprehensive

Code Examples

  1. Basic decompilation:
import org.benf.cfr.reader.api.CfrDriver;

CfrDriver driver = new CfrDriver.Builder().build();
driver.analyse(Arrays.asList("path/to/MyClass.class"));
  1. Customizing output options:
import org.benf.cfr.reader.api.CfrDriver;
import org.benf.cfr.reader.api.OutputSinkFactory;

OutputSinkFactory outputSinkFactory = new CustomOutputSinkFactory();
CfrDriver driver = new CfrDriver.Builder()
    .withOutputSink(outputSinkFactory)
    .withOptions(Map.of("showversion", "false", "hideutf", "true"))
    .build();
driver.analyse(Arrays.asList("path/to/MyClass.class"));
  1. Analyzing a JAR file:
import org.benf.cfr.reader.api.CfrDriver;

CfrDriver driver = new CfrDriver.Builder().build();
driver.analyse(Arrays.asList("path/to/myapp.jar"));

Getting Started

To use CFR in your Java project, add the following dependency to your Maven pom.xml:

<dependency>
    <groupId>org.benf</groupId>
    <artifactId>cfr</artifactId>
    <version>0.152</version>
</dependency>

For Gradle, add this to your build.gradle:

implementation 'org.benf:cfr:0.152'

Then, you can use CFR in your Java code as shown in the examples above.

Competitor Comparisons

IntelliJ IDEA Community Edition & IntelliJ Platform

Pros of intellij-community

  • Larger and more active community with frequent updates and contributions
  • Comprehensive IDE functionality with extensive features for Java development
  • Well-documented codebase with clear architecture and design patterns

Cons of intellij-community

  • Significantly larger codebase, which can be overwhelming for new contributors
  • Higher complexity and steeper learning curve for understanding the project structure
  • Requires more resources to build and run locally

Code Comparison

intellij-community (Java):

public class PsiJavaFileImpl extends PsiJavaFileBaseImpl implements PsiJavaFile {
  @Override
  public PsiElement[] getChildren() {
    return CachedValuesManager.getCachedValue(this, () ->
      CachedValueProvider.Result.create(super.getChildren(), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT));
  }
}

cfr (Java):

public class Dumper {
    public Dumper dump(JavaTypeInstance type) {
        return dump(type, TypeContext.None);
    }
    public Dumper dump(JavaTypeInstance type, TypeContext typeContext) {
        return type.dumpInto(this, typeContext);
    }
}

The intellij-community code showcases advanced caching mechanisms for performance optimization, while cfr demonstrates a simpler approach to type dumping. intellij-community's code reflects its more complex architecture, whereas cfr's code is more straightforward and focused on its specific decompilation tasks.

Unofficial mirror of FernFlower Java decompiler (All pulls should be submitted upstream)

Pros of Fernflower

  • More actively maintained with regular updates and bug fixes
  • Better support for newer Java language features
  • Produces more readable decompiled code in many cases

Cons of Fernflower

  • Slower decompilation speed compared to CFR
  • May struggle with heavily obfuscated code
  • Less customizable output options

Code Comparison

Fernflower:

public class Example {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

CFR:

public class Example {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

In this simple example, both decompilers produce identical output. However, for more complex code, Fernflower often generates more readable and structurally accurate results, especially with newer Java features. CFR, on the other hand, may produce more compact code in some cases and handle certain obfuscation techniques better.

Both decompilers have their strengths and weaknesses, and the choice between them often depends on the specific use case and the complexity of the code being decompiled. Fernflower is generally preferred for its readability and support for modern Java features, while CFR is valued for its speed and ability to handle some obfuscated code more effectively.

A Java 8+ Jar & Android APK Reverse Engineering Suite (Decompiler, Editor, Debugger & More)

Pros of bytecode-viewer

  • Comprehensive GUI with multiple decompiler options
  • Supports various file formats beyond just Java class files
  • Includes additional tools like searching and editing capabilities

Cons of bytecode-viewer

  • Larger file size and more complex setup
  • May be overwhelming for users who only need Java decompilation
  • Potentially slower for quick, single-file decompilation tasks

Code Comparison

While a direct code comparison is not particularly relevant due to the different nature of these projects, we can look at how they might be used:

bytecode-viewer (GUI-based):

// No direct code usage; launched via GUI

cfr (Command-line usage):

java -jar cfr.jar MyClass.class

Summary

bytecode-viewer is a feature-rich GUI tool with multiple decompilers and additional functionality, while cfr is a focused, command-line Java decompiler. bytecode-viewer offers more versatility but may be overkill for simple Java decompilation tasks, where cfr excels in simplicity and ease of use for quick decompilations.

41,326

Dex to Java decompiler

Pros of jadx

  • Provides a graphical user interface (GUI) for easier navigation and analysis
  • Supports multiple output formats, including Java and XML
  • Offers a command-line interface for batch processing and automation

Cons of jadx

  • May struggle with heavily obfuscated code
  • Can be slower for large-scale decompilation tasks
  • Less frequent updates compared to cfr

Code comparison

jadx:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

cfr:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

In this simple example, both decompilers produce identical output. However, differences may become apparent with more complex code structures or obfuscation techniques.

Summary

jadx and cfr are both Java decompilers with their own strengths. jadx offers a user-friendly GUI and multiple output formats, making it suitable for interactive analysis. cfr, on the other hand, focuses on command-line usage and may handle certain obfuscation techniques better. The choice between the two depends on specific project requirements and personal preferences.

14,011

A standalone Java Decompiler GUI

Pros of jd-gui

  • User-friendly graphical interface for easy navigation and decompilation
  • Supports drag-and-drop functionality for quick file analysis
  • Allows for easy searching and cross-referencing within decompiled code

Cons of jd-gui

  • Less actively maintained compared to CFR
  • May produce less accurate decompilations for newer Java features
  • Limited command-line options and automation capabilities

Code Comparison

CFR:

public class Example {
    public static void main(String[] args) {
        System.out.println("Hello, CFR!");
    }
}

jd-gui:

public class Example {
  public static void main(String[] paramArrayOfString) {
    System.out.println("Hello, jd-gui!");
  }
}

Both decompilers produce similar output for simple code, but CFR often provides more accurate variable names and handles complex scenarios better. jd-gui may sometimes generate less readable code, especially for newer Java features or complex lambda expressions.

While jd-gui offers a convenient GUI for quick code inspection, CFR provides more robust decompilation results and is better suited for advanced users or automated workflows. The choice between the two depends on the specific use case and the complexity of the code being analyzed.

4,999

An Open Source Java Decompiler Gui for Procyon

Pros of Luyten

  • User-friendly GUI for decompiling Java bytecode
  • Supports drag-and-drop functionality for easy file loading
  • Includes a search feature for finding specific classes or methods

Cons of Luyten

  • Less actively maintained compared to CFR
  • May struggle with more complex or obfuscated bytecode
  • Limited command-line options for automation

Code Comparison

Luyten (Java Swing GUI initialization):

private void initComponents() {
    mainWindow = new MainWindow(this);
    mainWindow.setVisible(true);
    interpreterThread = new Thread(this);
    interpreterThread.start();
}

CFR (Command-line argument parsing):

private static OptionsImpl getOptions(String[] args) {
    GetOptParser getOptParser = new GetOptParser();
    Map<String, String> opts = getOptParser.parse(args, OptionsImpl.getFactory());
    return new OptionsImpl(opts);
}

Both projects aim to decompile Java bytecode, but they take different approaches. Luyten focuses on providing a graphical interface for ease of use, while CFR emphasizes command-line functionality and handling complex decompilation scenarios. The code snippets highlight these differences, with Luyten initializing a GUI and CFR parsing command-line arguments.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

CFR - Another Java Decompiler \o/

This is the public repository for the CFR decompiler, main site hosted at benf.org/other/cfr

CFR will decompile modern Java features - including much of Java 9, 12 & 14, but is written entirely in Java 6, so will work anywhere! (FAQ) - It'll even make a decent go of turning class files from other JVM languages back into java!

To use, simply run the specific version jar, with the class name(s) you want to decompile (either as a path to a class file, or as a fully qualified classname on your classpath). (--help to list arguments).

Alternately, to decompile an entire jar, simply provide the jar path, and if you want to emit files (which you probably do!) add --outputdir /tmp/putithere.

Getting CFR

The main site for CFR is benf.org/other/cfr, where releases are available with a bunch of rambling musings from the author.

Since 0.145, Binaries are published on github along with release tags.

You can also download CFR from your favourite maven repo, though releases are published a few days late usually, to allow for release regret.

Issues

If you have an issue, please DO NOT include copyright materials. I will have to delete your issue.

Building CFR

Dead easy!

Just ensure you have Maven installed. Then mvn compile in the root directory of this project will get you what you need.

Note: If you encounter a maven-compiler-plugin...: Compilation failure error while trying to compile the project then your JAVA_HOME environment variable is probably pointing to a JDK version that doesn't support 6 for the source or target compile options. Fix this by pointing JAVA_HOME to a JDK version that still supports compiling to Java 1.6 such as JDK 11. Also note, the version of Java on your JAVA may need to be greater than 1.6 if you are using Maven version >=3.3.1 which requires Java 1.7. The best solution is to use JDK 8, 9, 10 or 11 for both your PATH and JAVA_HOME.

The main class is org.benf.cfr.reader.Main, so once you've built, you can test it out (from target/classes)

java org.benf.cfr.reader.Main java.lang.Object

to get CFR to decompile java.lang.Object.

Decompilation tests

As part of the Maven build automatic decompilation tests are performed. They verify that the current decompiled output of CFR matches the expected previous output. The test data (Java class and JAR files) are part of a separate Git repository; it is therefore necessary to clone this repository with git clone --recurse-submodules. The expected output and CFR test configuration is however part of this repository to allow altering it without having to modify the corresponding test data. The test data is in the decompilation-test/test-data directory, and the respective expected data and custom configuration is in the decompilation-test/test-data-expected-output directory (with a similar directory structure, see Expected data structure below).

The decompilation tests are also performed by the GitHub workflow, and in case of test failures the unified diff is available in a workflow artifact called "decompilation-test-failures-diff".

The expected output is not the gold standard, it merely describes the currently expected output. There is nothing wrong with adjusting the expected output, if the changes to the decompilation results are reasonable.

The test class is org.benf.cfr.test.DecompilationTest. It can be modified to adjust the test directories, or to ignore certain class files or JARs. Additionally it is possible to directly execute the tests there from the IDE. This usually gives better output than what is shown by Maven, and allows using the built-in IDE functionality for showing differences between the expected and the actual data.

Options file

The decompilation process can be customized by adding an options file. Each line of it specifies a CFR option, with key and value separated by a space. Empty lines and lines starting with # are ignored and can be used for comments.

Example:

# Enable identifier renaming
renameillegalidents true

See Expected data structure below for how to name the file and where to place it.

Expected data structure

Class files

For class files the expected data and custom configuration is in the same respective location under test-data-expected-output, with the file names being based on the class file name.

For example, for the class file test-data/classes/subdir/MyClass.class the following files can be used:

  • test-data-expected-output/classes/subdir/
    • MyClass.expected.java
      Contains the expected decompiled Java output, optionally with decompilation notes.
    • MyClass.options
      An optional options file customizing decompilation.
    • MyClass.expected.summary
      Contains the expected summary reported by the CFR API. Can be omitted when no summary is produced.
    • MyClass.expected.exceptions
      Contains the expected exceptions reported by the CFR API. Can be omitted when no exception is reported.

JAR files

For JAR files the expected data and custom configuration is inside a directory with the name of the JAR file in the respective location under test-data-expected-output. Expected Java output files include the package name in their file name, for example mypackage.MyClass.java. The options file and the expected summary and exceptions file use the "file name" _. For multi-release JARs the directory contains subdirectories for version specific classes. The directory name has the form java-<version>.

For example, for the multi-release JAR file test-data/jars/subdir/MyJar.jar the following files can be used:

  • test-data-expected-output/jars/subdir/MyJar/
    • mypackage.MyClass.java
      Contains the expected decompiled Java output for the class mypackage.MyClass, optionally with decompilation notes.
    • java-11/mypackage.MyClass.java
      Contains the expected decompiled Java output for a class file specific to Java 11 and higher (for multi-release JARs).
    • _.options
      An optional options file customizing decompilation.
    • _.expected.summary
      Contains the expected summary reported by the CFR API. Can be omitted when no summary is produced.
    • _.expected.exceptions
      Contains the expected exceptions reported by the CFR API. Can be omitted when no exception is reported.

Decompilation note comments

The expected Java output files support comments representing decompilation notes. They are ignored during comparison with the actual Java output and can for example be used to indicate incorrect or improvable CFR output. There are two kinds of decompilation notes:

  • Line: Start with //# (optionally prefixed with whitespace)
  • Inline: /*# ... #*/

Line decompilation notes should be used sparingly, especially in large files, because they shift line numbers for the diff files (due to being removed during comparison), which can be confusing.

Example:

//# Line decompilation note
public class MyClass {
    public static void main(String[] stringArray/*# Inline decompilation note #*/) {
        ...
    }
}

Updating / creating expected data

When adding a lot of new classes or JAR files for the decompilation tests or when a change to CFR affects the output for a lot of classes or JAR files, manually creating or updating the expected output can be rather cumbersome. For these cases the following system properties exist which help with this. They can be set with -D<system-property> when running tests. However, when these system properties are set, the respective tests will still fail (but the expected data is updated) to prevent accidentally using them for regular test execution.

  • cfr.decompilation-test.create-expected
    Generates all missing expected test data based on the current CFR output.
  • cfr.decompilation-test.update-expected
    Updates the expected test data to match the actual data produced by CFR. Note that this does not work for expected Java output using decompilation notes because those comments would get lost. The affected tests have to be updated manually.