Introduction
The Maven Shade Plugin relocates dependency classes to avoid conflicts by renaming their packages. When relocation rules are incomplete or reflection is used to load relocated classes, ClassNotFoundException occurs at runtime even though the build succeeds.
This error is common in projects that create uber-jars for deployment and use reflection, SPI, or configuration files that reference original class names.
Symptoms
- Application throws ClassNotFoundException at runtime for a class that exists in the dependency
- Maven build succeeds but running the shaded jar fails
- Error references the original class name, not the relocated name
Common Causes
- Shade plugin relocates a package but some classes are not included in the relocation rule
- Reflection-based class loading uses original class names that no longer exist
- Service Provider Interface (SPI) files reference non-relocated class names
Step-by-Step Fix
- 1.Verify shade plugin relocation configuration: Ensure all necessary packages are relocated.
- 2.```xml
- 3.<plugin>
- 4.<groupId>org.apache.maven.plugins</groupId>
- 5.<artifactId>maven-shade-plugin</artifactId>
- 6.<version>3.5.1</version>
- 7.<executions>
- 8.<execution>
- 9.<phase>package</phase>
- 10.<goals><goal>shade</goal></goals>
- 11.<configuration>
- 12.<relocations>
- 13.<relocation>
- 14.<pattern>com.google.common</pattern>
- 15.<shadedPattern>myproject.shaded.com.google.common</shadedPattern>
- 16.</relocation>
- 17.</relocations>
- 18.<transformers>
- 19.<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
- 20.<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- 21.<mainClass>com.example.Main</mainClass>
- 22.</transformer>
- 23.</transformers>
- 24.</configuration>
- 25.</execution>
- 26.</executions>
- 27.</plugin>
- 28.
` - 29.Use ServicesResourceTransformer for SPI files: Transform META-INF/services files to use relocated class names.
- 30.```xml
- 31.<transformers>
- 32.<!-- Transforms service provider files to use relocated class names -->
- 33.<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
- 34.</transformers>
# After adding transformer, rebuild: mvn clean package
# Verify the shaded jar contains relocated classes: jar tf target/myapp-shaded.jar | grep "shaded" ```
- 1.Inspect the shaded jar contents: Verify that classes are properly relocated.
- 2.```bash
- 3.# List classes in the shaded jar:
- 4.jar tf target/myapp-1.0-shaded.jar | grep -i guava
# Should show relocated paths: # myproject/shaded/com/google/common/collect/ImmutableList.class
# Check for original (non-relocated) classes: jar tf target/myapp-1.0-shaded.jar | grep "com/google/common" # If this shows results, relocation is incomplete ```
Prevention
- Always include ServicesResourceTransformer when using SPI-dependent libraries
- Test the shaded jar independently from the build environment
- Use jar -tf to verify relocation results after each build
- Document which dependencies are shaded and why in the project README