Skip to content

Repository files navigation

JavaJive — Pure-Go Java Toolkit: Decompile, Class Parse, Serialization

JavaJive

CI Pages Go Reference License: MIT

English | 简体中文 | Website

A portable, pure-Go Java toolkit — extracted and trimmed from yaklang — that does three things and nothing else:

  • Decompile.class / .jar / .war / .zip → readable Java source.
  • Parse classes — inspect the structure of a .class file (constant pool, fields, methods, version, access flags).
  • (De)serialize — parse and re-marshal the Java serialization (ObjectStream) wire format with byte fidelity, and convert it to/from JSON.

Built for portability and embedding:

  • Pure Go, single binaryno JDK, no cgo, no ANTLR runtime, no native libraries. Cross-compiles to linux / macOS / windows on amd64 and arm64.
  • One import — a unified javajive facade package wraps all three capabilities; the sub-packages remain available for advanced use.
  • First-class CLIdecompile, classinfo, and serial subcommands, built on the standard library.
  • Cross-tested against a real JDK — CI compiles real .class / .jar and JDK-serialized blobs with javac/java, then verifies JavaJive against them (see HARNESS-WORKFLOW.md).
  • Trimmed dependency graphutils / codec / log / go-funk are reimplemented as a minimal, self-contained internal/ core.

Validation of v0.4.0

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.

Historical benchmarks (v0.3.0)

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:

  • 100% unit-clean rate18,759 / 18,759 flattened units (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).
  • All 34 libraries fully round-trip — decompile → recompile → repackage → external JVM -Xverify:all per-class verification passes end-to-end (codec is byte-identical to the original jar under a call differential). Locked in provenClean.
  • 14 / 14 self-hosted algorithms (MD5 · SHA-256 · CRC32 · quicksort · Base64 · HeapSort · KMP · SwitchFSM · TryFinally · UnionFind · DiamondTryCatch · DiamondTryFinally · ForContinue · ComputeIfAbsent) round-trip byte-for-byte.
  • #1 in a fair 3-way comparison on the original 8-jar set — clean-unit rate 100% vs Vineflower 1.10.1 (90.8%) and CFR 0.152 (79.8%); winning all 8 jars against both.

See BENCHMARK.md for the full methodology, per-jar tables and reproduction commands.

Install

# 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+.

CLI

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

decompile

# 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

classinfo

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

serial

# 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

Library

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...)

Unified API

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

The sub-packages are also exported for advanced use: classparser, classparser/jarwar, serialization.

Differences from upstream yaklang

To stay portable and small, JavaJive makes a few deliberate trade-offs versus yaklang. See MIGRATE.md for the full mapping and migration guide.

Area yaklang (upstream) JavaJive
Decompiler ANTLR safety net re-validates dumped source via an ANTLR Java grammar; degrades members to stubs on failure removed (heavy dependency); validation is a no-op, output is emitted directly
Support layer (utils / codec / log / go-funk) shared monorepo packages minimal self-contained re-implementations under internal/
yso gadget generator included not included
String literal charset recovery (MatchMIMEType) optional GBK/GB18030 recovery stubbed (no-op); behaviour unchanged for the vast majority of cases

Third-party dependencies are confined to a small set of pure-Go libraries (gobwas/glob, go-viper/mapstructure, samber/lo, tidwall/gjson, segmentio/ksuid, yeka/zip, and a few golang.org/x/*).

Testing

go test ./...                 # unit tests + JDK cross-tests (skipped if no JDK)
go test ./... -race           # data-race free (linux)
go test ./test/cross/ -v      # Java cross-tests only (needs javac/java on PATH)

The JDK cross-tests compile real Java artifacts at test time and verify them against JavaJive; they t.Skip automatically when no JDK is present. See HARNESS-WORKFLOW.md for how the harness and CI work.

Project layout

javajive.go      unified facade package (import "github.com/yaklang/javajive")
serialization/   Java serialization/deserialization (from yaklang common/yserx)
classparser/     class parser + decompiler (from yaklang common/javaclassparser)
cmd/javajive/    CLI entry point
internal/        trimmed self-contained support layer (log / codec / funk / utils / filesys / ...)
test/cross/      JDK-backed cross-tests (javac/java)
site/            static landing page deployed to GitHub Pages

License

MIT © 2026 VillanCh. JavaJive is derived from yaklang.

About

Pure-Go Java Decompiler and Serialization Operator

Resources

Stars

16 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages