
Pure-Go Java デコンパイラおよびシリアライゼーション演算子
ポータブルな純Go製Javaツールキット — yaklangから抽出・整理されたもので、次の4点に焦点を当てています:
.class / .jar / .war / .zip → 読みやすいJavaソース。.dex / .apk → 決定論的な.jar、または外部のdex2jarツールを呼び出さずに直接読みやすいJavaソースへ。.classファイルの構造(定数プール、フィールド、メソッド、バージョン、アクセスフラグ)を検査。ポータビリティと組み込みやすさを重視して構築:
javajiveファサードパッケージが4つの機能すべてをラップ。高度な用途向けにサブパッケージも利用可能。decompile、dex2jar、classinfo、serialサブコマンドを標準ライブラリ上に構築。javac/javaで実際の.class / .jarおよびJDKでシリアライズしたブロブをコンパイルし、JavaJiveの出力を検証します(HARNESS-WORKFLOW.md参照)。utils / codec / log / go-funkは、最小限で自己完結したinternal/コアとして再実装。完全な38-JAR差分監査は、記録されたリグレッションがゼロであることを固定ベースラインに対して示しています。以前にコンパイルが通っていた20個のJARはすべて維持され、26個が完全にコンパイルできるようになりました。ベースラインの欠陥と4つの既存メソッドスタブは引き続き可視化されています。JARごとの結果と再現手順を参照してください。
250件の分離されたセマンティックラウンドトリップは、コンパイル、JVM検証、スタブ、実行時等価性を個別に記録します。元のアプリケーションクラスは再構築されたクラスパスに存在しません。CIはJDK 17と21でセマンティック監査を実行し、完全な履歴比較、およびOS/Goとレースのマトリクスも実行します。これらのチェックは、すべてのライブラリメソッドの等価性を証明するものではありません。実装と残る境界を参照してください。
以下の数値は2026-09-05にv0.3.0について報告されたものです。これらは現行バージョンの受け入れ結果でも、動作等価性の証明でもありません。
34個の実世界のjar(18,759個のフラット化ユニット)に対して、デコンパイル → javac --release 8再コンパイル → 再パッケージ → JVM検証という手順で測定:
Outer$Inner.java)が javac エラーゼロで再コンパイルされ、全 34 jar にわたって 構文エラー 0(CI で強制されるハードアサーションのため、レクサー障害の背後に型エラーが隠れることはありません)。-Xverify:all のクラス単位検証がエンドツーエンドで成功(コーデックは呼び出し差分において元の jar とバイト単位で同一)。provenClean に固定済み。完全な方法論、jar ごとの表、再現コマンドについては BENCHMARK.md を参照してください。
# CLI
go install github.com/yaklang/javajive/cmd/javajive@latest
# Library
go get github.com/yaklang/javajive@latest
ソースからビルドする場合:
git clone https://github.com/yaklang/javajive
cd javajive
go build -o javajive ./cmd/javajive
Go 1.22+ が必要です。
javajive <command> [arguments]
Commands:
decompile decompile Java artifacts or the strict DEX 035 subset into Java source
dex2jar convert the strict DEX 035 subset in a DEX/APK to a deterministic JAR
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
# DEX or APK: run the native DEX-to-JAR pipeline and decompile the result.
# The default output directory is "<input>.src".
javajive decompile classes.dex
javajive decompile app.apk -o ./app-src
# Directory: recursively decompile .class files (requires -o output dir).
javajive decompile ./classes -o ./src
javajive dex2jar -o classes.jar classes.dex
javajive dex2jar -o app.jar app.apk
入力はファイル名の拡張子ではなくマジックによって検出されます。出力は再現可能なJARです。dex2jarは、サポートされていない、または不正な形式のクラスやメソッドがあると変換全体を失敗させます。宛先を置き換える前に同一ディレクトリ内の一時ファイルに書き込み、メソッドスタブで代用することは決してありません。
ネイティブDEX変換は現在、厳格な最初の垂直スライスであり、汎用的なAndroidアプリケーションコンバータではありません。テスト済みのサブセットは、通常の整数/参照の制御フロー、フィールドとinvoke、安全にペア化されたnew-instance/コンストラクタ初期化、および基本的な配列を備えた標準DEX 035です。生成されたクラスファイルはパーサーテストおよびJVM検証済みであり、実行可能な分岐、フィールド、invoke、コンストラクタ、およびint[]のパスを含みます。
未サポート: try/catchおよびmonitor操作、float、long、doubleの値またはオペコード、switch、ペイロード命令、およびfilled配列、DEX 038以降の動的invokeとメソッド定数、アノテーションとデバッグメタデータ、CompactDex、およびAPKリソースやネイティブライブラリ。APK入力とは、正規の名前を持つclasses.dex、classes2.dex、...エントリのみが変換されることを意味します。選択されたすべてのDEXファイルはトランザクション的に成功する必要があり、そうでなければJARは生成されません。
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
統合ファサードパッケージを使用してください。1回のインポートで4つの機能すべてをカバーできます:
import (
"os"
"github.com/yaklang/javajive"
)
// Translate DEX or APK bytes in memory.
jarBytes, report, err := javajive.DexToJar(dexOrAPKBytes, javajive.DexOptions{})
if err == nil {
err = os.WriteFile("app.jar", jarBytes, 0o644)
_ = report.Classes
}
// Translate a file and atomically write the JAR.
report, err = javajive.DexFileToJar("app.apk", "app.jar", javajive.DexOptions{})
// Translate through a private temporary JAR and decompile directly to source.
err = javajive.DecompileDEXFile("classes.dex", "app-src", javajive.DexOptions{})
// Decompile a single class, or a whole Java 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...)