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)
Dex to Java decompiler
A standalone Java Decompiler GUI
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
- Basic decompilation:
import org.benf.cfr.reader.api.CfrDriver;
CfrDriver driver = new CfrDriver.Builder().build();
driver.analyse(Arrays.asList("path/to/MyClass.class"));
- 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"));
- 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.
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.
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.
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 designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
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 classmypackage.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.
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)
Dex to Java decompiler
A standalone Java Decompiler GUI
An Open Source Java Decompiler Gui for Procyon
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot