Using ProGuard, Xjar, and ClassFinal to Obfuscate and Encrypt Java JARs in Spring Boot Projects
This article explains how to protect Java server-side code from decompilation by applying ProGuard shrinking/obfuscation and Xjar/ClassFinal encryption, provides detailed Maven plugin configurations, sample pom.xml snippets, command‑line launch options, and demonstrates the resulting protected JARs with screenshots.
Background
The core modules of a project are deployed directly to user servers by copying JAR files, which can lead to source and bytecode leakage; therefore ProGuard and Xjar are used to obfuscate and encrypt the JARs.
Encryption raises the barrier for reverse engineering but is not absolute; the appropriate level of protection should balance security and operational cost.
Introduction
ProGuard is a free tool that compresses, optimizes, and obfuscates Java bytecode, removing unused classes, fields, methods, and renaming remaining ones with meaningless short names. It is commonly used in Android projects to increase decompilation difficulty.
Xjar is a Spring Boot JAR security tool that encrypts JAR resources and uses a custom ClassLoader to decrypt them at runtime, preventing source leakage and decompilation.
ClassFinal is another Java class encryption tool that can encrypt JAR/WAR packages without modifying source code, compatible with Spring Framework.
Features of Xjar
No code intrusion – just encrypt the compiled JAR.
Full in‑memory decryption to reduce the risk of bytecode leakage.
Supports all JDK built‑in encryption algorithms.
Selective encryption of bytecode or other resource files.
Provides a Maven plugin for convenient integration.
Generates a Go launcher to hide the password.
Features of ClassFinal
No source code changes required; encrypt the compiled JAR/WAR directly.
Works without modifying Tomcat, Spring, etc.
Supports plain JAR, Spring Boot JAR, and standard WAR packages.
Compatible with frameworks that scan annotations or generate bytecode at startup.
Provides a Maven plugin for automatic encryption during packaging.
Can encrypt dependencies located under WEB-INF/lib or BOOT-INF/lib .
ClassFinal Integration Example
1. Add the ClassFinal plugin to the module pom.xml :
<plugin>
<groupId>net.roseboy</groupId>
<artifactId>classfinal-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<password>#</password>
<packages>com.nick.gnss</packages>
<excludes>org.spring</excludes>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>classFinal</goal>
</goals>
</execution>
</executions>
</plugin>2. Launch the encrypted JAR:
• Without password:
java -jar gnss-server-1.0.0-encrypted.jar• With password:
java -javaagent:gnss-server-1.0.0-encrypted.jar="-pwd 123456" -jar gnss-server-1.0.0-encrypted.jarAfter decompilation, all methods return 0 or null , and the method bodies are empty.
ProGuard Integration
1. Add a proguard.cfg file to the module with the following options (excerpt):
# Java version
-target 1.8
# Disable shrinking and optimization
-dontshrink
-dontoptimize
# Keep class names case‑insensitive
-dontusemixedcaseclassnames
# Use unique member names
-useuniqueclassmembernames
# Adapt class strings for reflection
-adaptclassstrings
# Preserve annotations and exception information
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# Keep interface names
-keepnames interface ** { *; }
# Keep parameter names for Spring MVC / MyBatis
-keepparameternames
# Keep enum members
-keepclassmembers enum * { *; }
# Keep getters/setters
-keepclassmembers public class * { void set*(***); *** get*(); }
# Keep Spring annotations
-keep @org.springframework.context.annotation.Bean class * { *; }
-keep @org.springframework.context.beans.factory.annotation.Autowired class * { *; }
-keep @org.springframework.context.annotation.Value class * { *; }
-keep @org.springframework.stereotype.Service class * { *; }
-keep @org.springframework.stereotype.Component class * { *; }
-keep @org.springframework.web.bind.annotation.RestController class * { *; }
-keep @org.springframework.context.annotation.Configuration class * { *; }
# Suppress warnings
-ignorewarnings
-dontnote
-printconfiguration
# Do not obfuscate the main class
-keep class com.nick.GnssApplication { public static void main(java.lang.String[]); }2. Add the ProGuard Maven plugin (must be placed before the repackage plugin):
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<inLibsFilter>!META-INF/**,!META-INF/versions/9/**.class</inLibsFilter>
<outputDirectory>${project.basedir}/target</outputDirectory>
</configuration>
</plugin>Xjar Integration
1. Add the Xjar Maven plugin to the parent pom.xml (must be the last plugin to execute):
<plugin>
<groupId>com.github.core-lib</groupId>
<artifactId>xjar-maven-plugin</artifactId>
<version>v2.0.7</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
<configuration>
<password>44889951235894612351265ABD123</password>
<mode>1</mode>
<sourceDir>${project.build.directory}</sourceDir>
<targetJar>${project.build.finalName}_x.jar</targetJar>
<includes>
<include>com/nick/**</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>2. The same configuration is added to each module pom.xml after the other plugins.
Full Parent POM Example
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nick</groupId>
<artifactId>nick-server</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<modules>
<module>gnss-server</module>
</modules>
<dependencyManagement>…</dependencyManagement>
<build>
<plugins>
…
<!-- ProGuard plugin (must run before repackage) -->
<plugin>…proguard‑maven‑plugin configuration…</plugin>
<!-- Spring Boot repackage plugin -->
<plugin>…spring‑boot‑maven‑plugin configuration…</plugin>
<!-- Xjar plugin (last) -->
<plugin>…xjar‑maven‑plugin configuration…</plugin>
</plugins>
</build>
</project>Verification
After building the project with mvn package , the resulting JAR is both obfuscated by ProGuard and encrypted by Xjar (or ClassFinal). Decompiling the JAR shows methods returning 0 or null and empty bodies, confirming the protection works.
The article concludes that combining ProGuard and Xjar provides a practical solution for protecting Java backend code while keeping deployment straightforward.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.