
Pure-Go Java Decompiler and Serialization Operator
A portable, pure-Go Java toolkit — extracted and trimmed from yaklang — that does three things and nothing else:
.class / .jar / .war / .zip → readable Java source..class file (constant pool,
fields, methods, version, access flags).Built for portability and embedding:
javajive facade package wraps all three
capabilities; the sub-packages remain available for advanced use.decompile, classinfo, and serial subcommands,
built on the standard library..class / .jar and
JDK-serialized blobs with javac/java, then verifies JavaJive against them
(see HARNESS-WORKFLOW.md).utils / codec / log / go-funk are
reimplemented as a minimal, self-contained internal/ core.The complete 38-JAR differential audit reports zero recorded regressions against the fixed baseline: all 20 previously compile-clean JARs are retained and 26 now compile in full. Baseline defects and 4 existing method stubs remain visible. See the per-JAR results and reproduction.
250 isolated semantic round trips record compilation, JVM verification, stubs and runtime equality separately; original application classes are absent from rebuilt classpaths. CI runs the semantic audit on JDK 17 and 21, the full historical comparison, and the OS/Go and race matrices. These checks do not prove equivalence of every library method. See the implementation and remaining boundaries.
The following figures were reported for v0.3.0 on 2026-09-05. They are not current-version acceptance results or proof of behavioral equivalence.
Measured on 34 real-world jars (18,759 flattened units) via decompile → javac --release 8
recompile → repackage → JVM verify:
Outer$Inner.java)
recompile with zero javac errors, and 0 syntax errors across all 34 jars (a CI-enforced
hard assertion, so no type error can hide behind a lexer failure).-Xverify:all per-class verification passes end-to-end (codec is byte-identical to the
original jar under a call differential). Locked in provenClean.See BENCHMARK.md for the full methodology, per-jar tables and reproduction commands.
# CLI
go install github.com/yaklang/javajive/cmd/javajive@latest
# Library
go get github.com/yaklang/javajive@latest
Or build from source:
git clone https://github.com/yaklang/javajive
cd javajive
go build -o javajive ./cmd/javajive
Requires Go 1.22+.
javajive <command> [arguments]
Commands:
decompile decompile .class/.jar/.war/.zip or a directory into Java source
classinfo print the structure of a .class file (version, fields, methods)
serial Java serialization tools (subcommands: tojson, fromjson)
version print the version
help show help
# Single class: prints to stdout by default, or -o to write a file.
javajive decompile Foo.class
javajive decompile Foo.class -o Foo.java
# Archive: defaults to a "<input>.src" directory, or -o to choose one.
javajive decompile app.jar
javajive decompile app.war -o ./app-src
# Directory: recursively decompile .class files (requires -o output dir).
javajive decompile ./classes -o ./src
javajive classinfo Foo.class
class: InvisibleAnnoSeed
super: java/lang/Object
version: 61.0
access: public
constants: 18
fields (0):
methods (2):
<init>()V
run()I
# Serialized binary -> JSON. (-hex: input is a hex string, -: read from stdin)
javajive serial tojson dump.bin
printf 'aced000574000568656c6c6f' | javajive serial tojson -hex -
# JSON -> serialized binary. (default prints hex; with -o writes raw bytes)
javajive serial fromjson dump.json -o out.bin
javajive serial fromjson dump.json # prints hex
Use the unified facade package — one import covers all three capabilities:
import "github.com/yaklang/javajive"
// Decompile a single class, or a whole archive into a directory.
src, err := javajive.Decompile(classBytes)
err = javajive.DecompileArchive("app.jar", "app-src")
// Inspect class structure.
obj, err := javajive.ParseClass(classBytes)
_ = obj.GetClassName()
// Java serialization: binary -> JSON -> binary.
objs, _ := javajive.ParseSerialized(raw) // or ParseSerializedHex(hexStr)
jsonBytes, _ := javajive.SerializedToJSON(objs...)
restored, _ := javajive.SerializedFromJSON(jsonBytes)
out := javajive.MarshalSerialized(restored...)
| Function | Purpose |
|---|---|
Decompile(classBytes) (string, error) | Decompile one .class's bytes |
DecompileFile(path) (string, error) | Decompile one .class from disk |
DecompileWithResolver(classBytes, resolve) | Decompile with a class-bytes resolver |
DecompileArchive(src, dst) error | Decompile a .jar/.war/.zip into a directory |
ParseClass(classBytes) (*ClassObject, error) | Parse one .class's bytes |
ParseClassFile(path) (*ClassObject, error) | Parse one .class from disk |
ParseSerialized(raw) ([]JavaSerializable, error) | Parse a serialization stream |
ParseSerializedHex(hexStr) ([]JavaSerializable, error) | Parse a hex-encoded stream |
MarshalSerialized(objs...) []byte | Re-encode objects to the wire format |
MarshalSerializedHex(objs...) string | Re-encode to hex |
SerializedToJSON(objs...) ([]byte, error) | Convert objects to JSON |
SerializedFromJSON(raw) ([]JavaSerializable, error) | Rebuild objects from JSON |