Install
After you buy a license, grab wuuvy.jar from your dashboard. That one jar is the whole thing. You need Java 8 or newer on your machine (check with java -version), and that's it.
You've got two ways to use it:
- Just run it.
java -jar wuuvy.jar app.jarprotectsapp.jarright there. Nothing to set up. Great for a quick try or for CI. - Or install it once so you can type
wuuvyfrom anywhere. Double-clickwuuvy.jar(or runjava -jar wuuvy.jar install). A small installer window opens — click Install.
The installer copies wuuvy into ~/.wuuvy/ and adds three commands to your PATH: wuuvy, ofc-jar, and ofc-jar-inside. They work in cmd, PowerShell, bash, WSL, and the terminal built into IntelliJ or VS Code. Open a new terminal afterwards so it picks up the PATH change.
Quick start
Once it's installed, protecting a jar is one line in any terminal:
wuuvy writes the protected jar next to the original with an _ofc suffix, plus a matching .mapping file (keep that one — it's how you read crash reports later). Your original jar is never touched. No source changes, no runtime agent, nothing for your users to install.
wuuvy app.jar runs the fortify preset — the strong, safe default that doesn't rename classes, so it's the least likely to upset reflection or frameworks. Want more or less? See presets.Requirements
- Java: JRE or JDK 8 or newer to run wuuvy.
- What it can output: class files for Java 8 all the way up to Java 24.
- Servers and CI: the command line is fully headless — no screen needed. The only window wuuvy ever opens is the installer, and you can skip that entirely with
java -jar wuuvy.jar app.jar. - Memory: the default heap is fine for jars under ~100 MB. For bigger ones, give it more room with
java -Xmx2g -jar wuuvy.jar ....
Commands
These are the commands the installer puts on your PATH. Anywhere you see wuuvy, you can also write java -jar wuuvy.jar if you skipped the install step.
| Command | What it does |
|---|---|
wuuvy <jar> | Protect a jar with the default fortify preset. Add a preset flag or -t to change that. Writes <name>_ofc.jar. |
ofc-jar <what> <jar> | Same idea, but you lead with the preset or technique list: ofc-jar mod my-mod.jar. |
ofc-jar-inside | Build the project you're standing in, then protect whatever it produced. Handy mid-development. |
wuuvy list | Print every technique name, grouped by what it's for. |
wuuvy doctor <jar> | Look over a jar and suggest a preset (spots frameworks, reflection, mods). |
wuuvy template | Write a starter config file you can edit and reuse. |
wuuvy mapping | Turn an obfuscated stack trace back into readable names using a .mapping file. |
wuuvy install / uninstall | Open the installer, or remove wuuvy from your PATH again. |
wuuvy version / help | Show the version, or the full list of commands and flags. |
Run wuuvy help any time for the complete list — there are more small tools in there (verify, compare, info, and friends) than most people need day to day.
Picking techniques by hand
Most of the time a preset is all you want. But if you'd rather choose the exact passes, run wuuvy list to see every name, then pass them with -t (comma-separated, no spaces). Each name is also explained on the Techniques page.
ofc-jar
ofc-jar is the same obfuscator as wuuvy <jar>, just with the preset (or technique list) out front. Use whichever reads nicer to you. The first argument is a preset name (fortify, light, methods, turbo, all, mod, mod-strict, paranoid) or a comma-separated list of techniques.
Bad technique names fail fast with unknown technique: foo instead of being silently dropped. The result jar is <name>_ofc.jar in the current directory unless you give an explicit output path.
wuuvy <jar>
This is the plain command-line way in: no window, works in scripts and CI. Point it at a jar and it writes <name>_ofc.jar (plus the .mapping) into the folder you're in. With no preset given, it uses fortify.
ofc-jar-inside (build + obfuscate in one step)
ofc-jar-inside is an alias for wuuvy inside. You run it from inside a project directory - it walks up looking for a pom.xml, build.gradle(.kts), an IntelliJ .idea folder, or the newest built jar, runs the right build command, then obfuscates the result.
The output JAR is dropped into the current working directory (not target/ / build/libs/), so it doesn't clash with your build outputs and is easy to attach to a release.
Maven Projects
When ofc-jar-inside finds a pom.xml at (or above) the current directory, it invokes Maven directly:
It then takes the newest JAR in target/ and obfuscates it. A typical run looks like:
For repeat builds, wire wuuvy into the package phase of your pom.xml with the snippet generated by wuuvy maven-init. Then a normal mvn package produces both the regular jar in target/ and the obfuscated <name>_ofc.jar next to it.
Gradle Projects
When a build.gradle or build.gradle.kts is detected, ofc-jar-inside runs the project's own Gradle wrapper if present, otherwise the installed gradle:
It then picks the newest JAR under build/libs/ (skipping -sources.jar, -javadoc.jar, and any previously-obfuscated *_ofc.jar) and obfuscates it. Shadow/fat jars work - the newest-modified jar wins, so if your shadowJar task produces build/libs/app-all.jar, that's what gets picked up.
For repeat builds, wire wuuvy into your Gradle build with the snippet generated by wuuvy gradle-init. Then ./gradlew obfuscate produces both jars in build/libs/.
wuuvy integrate (Gradle / Maven plugin in one command)
wuuvy integrate auto-detects the build system in your current directory and writes a ready-to-paste integration snippet:
Gradle
The Gradle generator detects whether you have build.gradle (Groovy) or build.gradle.kts (Kotlin DSL) and emits the matching syntax. The generated wuuvy.gradle adds an obfuscate task that runs after jar:
Output is build/libs/<name>_ofc.jar. Uncomment the tasks.named('build') { dependsOn 'obfuscate' } line at the bottom of the snippet to make every ./gradlew build produce the obfuscated jar automatically.
Maven
The Maven generator writes a wuuvy-pom-snippet.xml with a complete <plugin> block built on exec-maven-plugin, bound to the package phase. Paste it into <build><plugins>...</plugins></build>:
Output is target/<name>_ofc.jar. The snippet reads ${user.home}/.wuuvy/wuuvy.jar - i.e. the install you already have - so there is no Maven Central artifact to depend on, and offline builds work as long as install has been run on the build agent.
java -jar ~/.wuuvy/wuuvy.jar ofc-jar <techs> <in> <out>. There's no plugin artifact to download and no transitive dependencies dragged into your build. If ~/.wuuvy/wuuvy.jar is missing, the task fails loudly with a clear message rather than silently producing an unprotected jar.CI/CD
CI runners don't have a screen, which is fine — wuuvy's command line doesn't need one. You don't even have to install it; just run the jar after your build step. A typical pattern:
- Stage
wuuvy.jarin a trusted location (artifact cache, internal release bucket, or the repo itself under.ci/). - On the agent, run
java -jar wuuvy.jar <your-built.jar> -methods -o dist/app.jarafter your normal build step. Noinstallis needed -java -jaris sufficient for one-shot invocations. - Upload the resulting
_ofc.jaras your release artifact.
A few things worth knowing:
- Exit codes: the CLI returns
0on success,2if the input jar isn't found,3ifinsidecouldn't locate or build a jar, non-zero for any other failure. Your pipeline's default "fail on non-zero" behaviour is sufficient. - No display needed: only the interactive
Mainentry opens a Swing window. ThewuuvyCLI (theWuuvyentry point) andwuuvy insiderun fully headless. You do not needxvfb. - Non-determinism: the seed defaults to
System.currentTimeMillis(), so renaming and layout differ run-to-run. If you need byte-reproducible output, keep the output jar as the released artifact rather than trying to reproduce it. - Caching: wuuvy has no build-avoidance of its own. If you want to skip re-obfuscation when inputs haven't changed, gate the step in your pipeline by hashing the input jar.
Presets
A preset is just a bundle of techniques picked to work well together, so you don't have to. There are eight. With wuuvy <jar> you pass one as a flag (-light); with ofc-jar you put the name first (ofc-jar light app.jar). If you pick none, you get fortify.
| Preset | What you get | Reach for it when |
|---|---|---|
fortify (default) | The strong, safe default. Renames methods and fields but not classes, and never adds anything that could stop your jar from running. | almost always. Start here. It's the best mix of "hard to read" and "won't surprise you." |
light | The gentle option: rename things, strip debug info, a couple of shape-preserving passes. | you want a quick cleanup that's safe for basically any framework, or you're cold-start sensitive. |
methods | Focuses on method bodies — rename, shuffle, light control-flow tweaks — and leaves your strings, classes, and layout alone. | you want method-level protection without touching anything else. |
turbo | Built for speed: string encryption, renaming, and a few cheap tricks, but skips the expensive control-flow flattening. Roughly 1.1× runtime. | your code is compute-heavy and you can't spare the runtime cost of the heavier modes. |
all | Everything, class renaming included. The strongest setting. | you want maximum protection and you've tested the result — renaming classes can break apps that look classes up by name (reflection, ServiceLoader). |
mod | Minecraft-safe. Skips anything that would upset a loader, and automatically leaves entry points, mixins, and reflected names intact. | you're shipping a Forge / Fabric / NeoForge mod. See Minecraft mods. |
mod-strict | mod turned up — more layered techniques on top. | you want to push a mod harder; test it against your loader and fall back to mod if anything acts up. |
paranoid | all plus a self-defense layer (tamper checks, anti-debug, and gates). It will refuse to run unless the jar is signed, the OFC_RUN_KEY environment variable matches, and it's on the machine it was built for. | you're building for exactly one machine and one runtime. Do not use it for a jar you hand out — it's designed to not run anywhere else. |
wuuvy doctor app.jar — it reads your jar and tells you which preset fits.Config file
Typing flags every time gets old. You can put your choices in a file instead and point wuuvy at it. There are two formats — pick whichever you like.
1. A quick text profile
The simplest one. Each line turns a technique on with {Y} or off with {N}, with an optional strength number after a dash. Lines like key: value set the basics. Anything after // or # is a comment, and =names in equals signs= are just section labels for your own eyes.
Run it like this:
If you save a file at ~/.wuuvy/CONFIGS.txt, wuuvy uses it automatically whenever you run ofc-jar app.jar with no other instructions — a nice way to set your personal defaults once.
2. A JSON config
If you'd rather have something tidy to commit to your repo, use the JSON form. Generate a starter file (it comes fully commented) and edit it:
The JSON form is strict on purpose: a misspelled technique or unknown setting stops the build with a clear message, so a typo never quietly ships an unprotected jar. (The text profile is more relaxed — it just warns and skips names it doesn't recognise.)
Keeping names safe
Obfuscation only bites you when it renames something another part of your program — or a framework — looks up by its original name. wuuvy handles most of that for you:
- The default never renames classes.
fortifyleaves class names alone, which is exactly the thing reflection and service loaders care about most. That's why it's the default. - Reflected names are detected. When wuuvy sees a string handed to
Class.forName,getDeclaredMethod, and friends, it leaves that name as-is. - The
modpresets go further and automatically protect loader entry points, mixins, and anything referenced from mod metadata.
For the stubborn cases, you can hand wuuvy a plain list of class names to leave completely untouched by pointing the WUUVY_KEEP_VERBATIM_FILE environment variable at a text file (one name per line). And the honest fallback that always works: if a heavy preset breaks something, drop to fortify or light and the problem usually goes away.
Minecraft Mods
Minecraft mods have hard constraints - reflection-heavy loaders (Forge / Fabric / NeoForge), Sponge Mixin transformers, annotation-driven entry points. The mod preset is hand-tuned to compose with these.
The obfuscator already has Mod awareness built in:
- Mod entry points are protected from rename: classes referenced from
fabric.mod.json,META-INF/mods.toml,META-INF/neoforge.mods.toml, and any*.mixins.jsonare auto-collected and excluded from class renaming. - Mixin classes are skipped: any class with the
@Mixinannotation is preserved verbatim.boze.mixins.jsonstill resolves its targets by name after obfuscation. - Reflection-protected names:
Class.forName/getDeclaredMethod/getDeclaredFieldstring arguments are scanned across the jar and added to the no-rename set.
Ship the auto-emitted ProGuard-format .mapping file with releases - without it, user crash reports become unreadable obfuscated stack traces.
anno-strip strips @Mod / @SubscribeEvent; access-max breaks final invariants Forge relies on; resource-enc would encrypt textures, sounds, and lang files; main-rename is a no-op (mods have no Main-Class); debug strips line numbers so user crash reports become unreadable.Troubleshooting
Double-clicking the jar does nothing (or the installer won't open)
Almost always the wrong Java. wuuvy needs Java 8 or newer — check with java -version. If the installer still won't appear, open a terminal and run java -jar wuuvy.jar so you can see the actual error. And remember you never have to open the installer: java -jar wuuvy.jar app.jar protects a jar without it.
Installed it, but my terminal says wuuvy isn't a command
Terminals only read your PATH when they start, so the one that was already open won't see the new command. Close it and open a fresh one. On macOS/Linux you can also source the file the installer told you it edited.
ClassNotFoundException / NoSuchMethodError at runtime
Almost always caused by reflection or service loading in the protected app. Reproduce with a lighter preset to confirm - rerun with -light, and if the error disappears, renaming or stripping is hitting a reflectively-loaded class. Launching the protected app with -verbose:class will show exactly which class the JVM failed to find.
Protected JAR launches but throws at a specific method
Likely one aggressive pass conflicting with your code. Bisect with -t to isolate the culprit - start by removing cff, opaque-pred, indy-hide-*, and const-math. When the failing pass is identified, fall back to a technique list that excludes it (for example, build on top of -methods or -light rather than -all).
Slower startup after obfuscation
Expected if you enabled string-enc, clinit-finals, or any indy-hide-* pass - decryption and trampoline code runs at class load. For cold-start-sensitive apps (AWS Lambda, serverless), drop to -methods or -light and profile before adding heavier passes back.
ofc-jar-inside: "could not find or build a jar under <dir>"
The auto-detector couldn't find a pom.xml, build.gradle(.kts), IntelliJ artifact output under out/artifacts/, or a plain jar within three directories of where you ran it. Either run from inside the project root, pass --root, or build the jar yourself and call wuuvy <path-to-jar> directly.
My framework's reflection stops working
Most frameworks need reflection-touched classes to keep their original names. Common problem areas:
- Spring:
@Component,@Service,@Repository,@Controllerclasses, and the fields Spring injects into them. - Jackson / Gson: every DTO/POJO you (de)serialize - field names are the wire format.
- JPA / Hibernate:
@Entityclasses and their fields. - JavaFX / FXML: controllers referenced by
fx:controller.
Good news: the default fortify preset doesn't rename classes, so most of this never comes up unless you reach for all. If it does, see Keeping names safe — and the quickest fix is always to drop back to fortify or light. Making reflection-heavy apps "just work" on the heavier presets is near the top of the what's-next list.