Core Java

Java Decompiler Example

In this article, we are going to explain what a Java Decompiler is and how to decompile classes using examples.

1. What is a Java Decompiler?

As the name suggests, a decompiler is the opposite of a compiler. This reads .java source files and transforms them into .class files; a Java decompiler reads .class files as input and produces equivalent Java source code from them.

A Java decompiler can help you understand or debug executable Java code for which the source code is not available. There are a variety of Java decompilers available, both as plugins for Java IDEs and for standalone use from the command line.

2. Why Would I Need a Decompiler?

In the best of all possible worlds, you wouldn’t need a decompiler. Every bit of source code you ever wrote would be stashed away in version control. The version control archives would be regularly backed up. And just in case the building burns down, backup copies would routinely be taken safely off-site.

But here in the real world, we know the procedures and protocols intended to safeguard source code aren’t always followed rigorously and consistently. And so, in spite of everything, source code still manages to go missing from time to time. Consider this somewhat contrived, but reasonably plausible scenario:

  • Colleague A writes QuadSolver, a library that solves quadratic equations, and deploys it as a jar artifact to the corporate Maven repository. However, Colleague A neither commits the source to version control, nor deploys a source-code jar to the Maven repo.
  • You write QuadDemo, which depends on QuadSolver; you check your source into version control.
  • Colleague A’s desktop HD unexpectedly dies, taking with it the only copy of the source of QuadSolver.
  • QuadDemo is now producing some confusing results. Because QuadSolver does all the heavy lifting for QuadDemo, you’ll need to debug QuadSolver in order to isolate the problem.

At this point, you would find Java decompiler quite useful.

3. The Example Code

We’ve provided the code for QuadSolver and QuadDemo so that you can reproduce the example scenario for yourself.

QuadSolver

The QuadSolver library consists of a single class, also called QuadSolver,. QuadSolver has one static method, solve, which accepts the three real coefficients of a quadratic equation and returns the solution as a pair of complex numbers, each represented as a two-element int array. Here are the source code and the POM file:

QuadSolver.java

package jcg.examples.quadsolver;

public class QuadSolver
{
    public static double[][] solve(double a, double b, double c)
    {
        double[][] roots = new double[2][2];
        double d = b * b - 4 * a * c;
        if (d > 0) {
            roots[0][0] = (0 - b + Math.sqrt(d)) / (2 * a);
            roots[1][0] = (0 - b - Math.sqrt(d)) / (2 * a);
        } else {
            roots[0][0] = roots[1][0] = 0 - (b / (2 * a));
            if (d != 0) {
                // d < 0
                roots[0][1] = Math.sqrt(0 - d) / (2 * a);
                roots[1][1] = 0 - roots[0][1];
            }
        }
        return roots;
    }
}

QuadSolver.pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jcg.examples</groupId>
    <artifactId>quadsolver</artifactId>
    <version>3.0.0</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

QuadDemo

QuadDemo is a simple command-line application that uses QuadDemo to solve a few hard-coded equations. Here are the code and POM:

QuadDemo.java

package jcg.examples.quaddemo;

import jcg.examples.quadsolver.QuadSolver;

public class QuadDemo
{
    public static void main(String[] args)
    {
        double[][] eqns = {
            {2, 3, 5}, {1, 3, 1}, {1, 2, 1}
        };
        for (double[] eq : eqns) {
            double[][] roots = QuadSolver.solve(eq[0], eq[1], eq[2]);
            System.out.printf("Equation: %gx^2%+gx%+g = 0, roots: %g%+gi, %g%+gi%n",
                eq[0], eq[1], eq[2],
                roots[0][0], roots[0][1],
                roots[1][0], roots[1][1]);
        }
    }
}

QuadSolver.pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.kaa</groupId>
    <artifactId>quaddemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>jcg.examples</groupId>
            <artifactId>quadsolver</artifactId>
            <version>3.0.0</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>14</maven.compiler.source>
        <maven.compiler.target>14</maven.compiler.target>
    </properties>
</project>

4. Using a decompiler in Eclipse

Eclipse supports debugging of executable Java code without accompanying source code, using either its inbuilt Class File Editor or a Java decompiler plug-in. The standard Eclipse distribution does not come with a decompiler pre-installed, so you’ll need to choose one from the Eclipse Marketplace and install it if you want decompiler functionality.

For this example, we’ll use the Enhanced Class Decompiler, or ECD, plug-in. It’s not the only decompiler available for Eclipse, but it’s the most popular (by number of downloads), and is actively supported by the Eclipse community. To download it, go the the Eclipse Marketplace and search for “ECD”.

Once you install ECD, you’ll need to configure Eclipse to use it. Go to Window > Preferences, then choose General > Editors > File Associations from the menu on the left. Select Class Decompiler Viewer to be the default editor for both the *.class and *.class without source file types if it isn’t already:

Java Decompiler - Enhanced Class Decompiler configuration
Fig 1: Enhanced Class Decompiler configuration

To see ECD in action, first download and prepare the example code as described in Download the source code at the end of this article. Set a breakpoint at line 13 in QuadDemo.java and start it running:

Java Decompiler - Ready to step into method with missing source
Fig 2: Ready to step into method with missing source

Now single-step into the solve method of QuadSolver. Without ECD, you’d see Eclipse’s standard Class File Editor:

Java Decompiler - Eclipse Class File Viewer
Fig 3: Eclipse Class File Viewer

Here, you get a summary of the solve method’s public API, along with a listing of the disassembled bytecode: interesting, perhaps, but not very helpful. You’re also limited in the amount of debugging you can do: you can’t set breakpoints, single-step or examine variables.

But with ECD installed and configured, it’s an entirely different story. When you step into solve you see readable Java source code:

Java Decompiler - Debugging decompiled source in Eclipse
Fig 4: Debugging decompiled source in Eclipse

What’s more, you can debug the decompiled code just as if it were the original: breakpoints and single-stepping work, you can examine local variables, etc. You can also save the reconstructed source as a .java file by right-clicking and choosing Export source…

5. Using a decompiler in IntelliJ IDEA

IntelliJ IDEA 2020.2 comes right from the box with JetBrains’ own Java decompiler, Fernflower, already bundled in. There’s nothing more you need to do in order to use it. Just step into any piece of code for which the source is unavailable and the decompiler automatically goes to work.

Here’s a screenshot of Fernflower in action:

Java Decompiler - Debugging decompiled source in IntelliJ IDEA
Fig 5: Debugging decompiled source in IntelliJ IDEA

As with Eclipse and ECD, you can debug the decompiled source exactly as if it were the original. IntelliJ IDEA doesn’t provide a specific “export source” command, so you’ll have to resort to cut-and-paste if you want to save the decompiled source.

6. Using a decompiler from the command line

Decompiler plugins for IDEs are geared toward making it easy to “peek into” individual classes. But if you need to reconstruct source code on a more industrial scale (say, a JAR file containing hundreds of classes), you may want to consider a command-line-based decompiler.

Just to give you the general flavor, here are examples of using two different CLI-based decompilers, jd-cli and CFR to decompile the example QuadSolver JAR file which has been deployed to the local Maven repository:

Java Decompiler - jd-cli example
Fig 6: jd-cli example
Java Decompiler - CFR Example
Fig 7: CFR Example

7. Summary

In this article, you’ve learned that a Java decompiler is able to generate Java code from compiled Java classes. You’ve also seen examples of decompilation used in some typical settings. While having original source code available is always preferable, a Java decompiler can be a handy safety net when, for whatever reason, that isn’t possible.

To prepare the example, follow these steps:

  • Extract the source code to any convenient directory; the top-level directory contains two Maven project folders: QuadSolver and QuadDemo.
  • Import the QuadSolver project into your IDE and build it up to the install lifecycle phase.
  • Remove the QuadSolver project from the workspace (Eclipse)/close it (IDEA).
  • Import the QuadDemo project and build it.
  • Open QuadDemo.java and set a breakpoint at line 13.

8. Download the Source Code

Download

Download a ZIP archive of the source code here:
Java Decompiler Example

Kevin Anderson

Kevin has been tinkering with computers for longer than he cares to remember.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button