jeo-maven-plugin is a Maven plugin dedicated to disassembling Java bytecode. The process involves translating the Java bytecode into the EO programming language. The plugin also provides the ability to assemble EO back into Java bytecode.
You need at least Maven 3.1+ and Java 11+ to run the plugin. (Actually, the plugin requires Java 8+, but since the main dependency eo requires Java 11, we are obligated to use it as well.)
The plugin can convert compiled .class
files into EO by using
the disassemble
goal.
The assemble
goal can convert EO back into bytecode.
The default phase for the plugin
is process-classes.
To optimize java bytecode you need to use both goals in the following order:
disassemble
create EO files in thetarget/generated-sources
directory.- Provide your optimizations are applied to the EO files
in the
target/generated-sources
directory. assemble
scans thetarget/generated-sources
directory for EO files and converts them back to Java bytecode.
More details about plugin usage you can find in our Maven site.
You can run the plugin directly from the command line using the following commands:
mvn jeo:disassemble
or
mvn jeo:assemble
You can run the plugin from the Maven lifecycle by adding the following
configuration to your pom.xml
file:
<build>
<plugins>
<plugin>
<groupId>org.eolang</groupId>
<artifactId>jeo-maven-plugin</artifactId>
<version>0.7.1</version>
<executions>
<execution>
<id>bytecode-to-eo</id>
<phase>process-classes</phase>
<goals>
<goal>disassemble</goal>
</goals>
</execution>
<execution>
<id>eo-to-bytecode</id>
<phase>process-classes</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
In order to include debug information in the generated EO files, you can set
debug
option.
<configuration>
<mode>debug</mode>
</configuration>
This option will add line numbers and local variable names to the EO files together with their corresponding labels.
Each time the plugin converts EO back to bytecode, it verifies it. If the
verification fails, the build also fails. You can disable this verification by
setting the skipVerification
parameter to true
:
<configuration>
<skipVerification>true</skipVerification>
</configuration>
At times, it might be beneficial to generate intentionally flawed bytecode.
After generation XMIR or before assemble
goal,
you might need to check its correctness.
We do it by using objectionary/lints
repository.
By default, the plugin does not run lints.
To enable them, you need to set xmirVerification
to true
:
<configuration>
<xmirVerification>true</xmirVerification>
</configuration>
The plugin can transform Java bytecode into EO and back. Usually, the plugin
transforms each bytecode class file into a separate EO file, maintaining a
one-to-one relationship. If the Java class has name Application.class
, the EO
file will have Application.xmir
file.
For example, consider the following Java class:
package org.eolang.jeo;
public class Application {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
with the following bytecode representation:
{
public org.eolang.jeo.Application();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lorg/eolang/jeo/Application;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String Hello, World!
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 5: 0
line 6: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
}
After running the jeo:disassemble
goal, the plugin will generate the
following EO:
+package j$org.j$eolang.j$jeo
jeo.class > j$Application
jeo.int > version
00-00-00-00-00-00-00-34
jeo.int > access
00-00-00-00-00-00-00-21
"java/lang/Object" > supername
jeo.seq.of0 > interfaces-696199744
jeo.method > j$object@init@-%28%29V
jeo.int
00-00-00-00-00-00-00-01
"()V"
""
jeo.seq.of0 > aca3ae21-f727-41cc-b8df-791e7031904e-1635871459
jeo.maxs
jeo.int
00-00-00-00-00-00-00-01
jeo.int
00-00-00-00-00-00-00-01
jeo.params
jeo.seq.of0 > annotations-1586121642
jeo.seq.of3 > body-1998918745
jeo.opcode.aload
jeo.int
00-00-00-00-00-00-00-19
jeo.int
00-00-00-00-00-00-00-00
jeo.opcode.invokespecial
jeo.int
00-00-00-00-00-00-00-B7
"java/lang/Object"
"<init>"
"()V"
jeo.bool
00-
jeo.opcode.return
jeo.int
00-00-00-00-00-00-00-B1
jeo.seq.of0 > trycatchblocks-object@init@-1849817803
jeo.seq.of0 > local-variable-table-1794934203
jeo.method > j$main-%28%5BLjava%2Flang%2FString%3B%29V
jeo.int
00-00-00-00-00-00-00-09
"([Ljava/lang/String;)V"
""
jeo.seq.of0 > f6c6c536-0b96-4357-bbba-d2966968b266-658978372
jeo.maxs
jeo.int
00-00-00-00-00-00-00-02
jeo.int
00-00-00-00-00-00-00-01
jeo.params
jeo.param > param-%5BLjava%2Flang%2FString%3B-arg0-0-0-1064778491
jeo.seq.of0 > param-annotations-0-666850426
jeo.seq.of0 > annotations-639467587
jeo.seq.of4 > body-1023152593
jeo.opcode.getstatic
jeo.int
00-00-00-00-00-00-00-B2
"java/lang/System"
"out"
"Ljava/io/PrintStream;"
jeo.opcode.ldc
jeo.int
00-00-00-00-00-00-00-12
"Hello, World!"
jeo.opcode.invokevirtual
jeo.int
00-00-00-00-00-00-00-B6
"java/io/PrintStream"
"println"
"(Ljava/lang/String;)V"
jeo.bool
00-
jeo.opcode.return
jeo.int
00-00-00-00-00-00-00-B1
jeo.seq.of0 > trycatchblocks-main-727934521
jeo.seq.of0 > local-variable-table-2134319645
jeo.seq.of0 > annotations-785801830
jeo.seq.of0 > attributes-744976367
As you can see, there are many EO objects that represent the Java bytecode
primitives, like jeo.opcode
, jeo.int
, jeo.method
, etc.
During decompilation, the jeo-maven-plugin
creates a set of objects
representing bytecode primitives.
These objects provide a way to handle various aspects of Java bytecode.
Below is the full list of these objects, grouped by category:
jeo.opcode.*
Represents a single bytecode instruction likeaload_0
,iconst_0
, etc.
jeo.class
Represents a Java class.jeo.method
Represents a Java method.jeo.field
Represents a Java field.jeo.params
Represents method parameters.jeo.param
Represents a single method parameter.jeo.maxs
Represents the maximum stack and local variable sizes.
jeo.int
- Represents an integer value.jeo.bool
- Represents a boolean value.jeo.string
- Represents a string value.jeo.float
- Represents a float value.jeo.double
- Represents a double value.jeo.long
- Represents a long value.jeo.char
- Represents a char value.jeo.short
- Represents a short value.jeo.byte
- Represents a byte value.jeo.bytes
- Represents a byte array.
jeo.nullable
Represents an object that can benull
.jeo.array
Represents an array of objects.jeo.type
Represents a Java type.jeo.seq.*
Represents a sequence of objects with a specific size, likejeo.seq.of0
,jeo.seq.of1
, etc.
jeo.annotation
Represents a Java annotation.jeo.annotation-property
Represents a single annotation element.jeo.annotation-default-value
Represents a default value of a Java interface method or annotation property.jeo.inner-class
Represents a Java inner class annotation property.
jeo.local-variable
Represents a local variable entry.jeo.try-catch
Represents a try-catch block.
jeo.label
Represents a Java label.jeo.handle
Represents a Java method handle.jeo.frame
Represents a stack frame.
To build the plugin from the source code, you need to clone the repository and run the following command:
$ mvn clean install -Pqulice,long
Pay attention to the qulice
profile, which activates the static analysis
tools. The long
profile is optional and runs the full test suite, including
long-running integration tests.
Fork repository, make changes, then send us
a pull request.
We will review your changes and apply them to the master
branch shortly,
provided they don't violate our quality standards. To avoid frustration,
before sending us your pull request please run full Maven build:
$ mvn clean install -Pqulice
You will need Maven 3.3+ and Java 11+ installed.