I need to create fat jar in Gradle project with tests where Main method is under src/test. Now I have Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser
when I run fat jar created by 'gradle bootJar'.
My Gradle:
plugins {
id 'org.springframework.boot' version '2.1.7.RELEASE'
}
apply plugin: 'io.spring.dependency-management'
dependencies {
compile group: 'org.springframework', name: 'spring-context', version: '5.1.9.RELEASE'
compile group: 'org.springframework', name: 'spring-web', version: '5.1.9.RELEASE'
compile group: 'org.springframework', name: 'spring-aop', version: '5.1.9.RELEASE'
compile group: 'org.springframework', name: 'spring-aspects', version: '5.1.9.RELEASE'
compile group: 'org.springframework', name: 'spring-test', version: '5.0.5.RELEASE'
compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
}
bootJar {
manifest {
attributes 'Start-Class': 'com.company.MainRunner'
}
from sourceSets.test.output.classesDirs
}
My spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy/>
<bean> ... </bean>
<bean> ... </bean>
</beans>
Exception:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser
Previously following 'gradle shadowJar' code worked well until I added AspectJ to the project
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
}
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
manifest {
attributes 'Main-Class': 'com.company.MainRunner'
}
from sourceSets.test.output.classesDirs
configurations = [project.configurations.testRuntime]
}
And error appeared on running 'gradle shadowJar'
Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/aop]
Somewhere I found that shadowJar doesn't work properly with Spring
How can I create fat jar for Spring project with main class under src/test?
This Gradle shadowJar works for me
import com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer
shadowJar {
mergeServiceFiles()
transform(AppendingTransformer) { resource = 'META-INF/spring.handlers' }
transform(AppendingTransformer) { resource = 'META-INF/spring.schemas' }
manifest {
attributes 'Main-Class': 'com.company.MainRunner'
}
from sourceSets.test.output.classesDirs
configurations = [project.configurations.testRuntime]
}
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser
According to the above error, it seems like you have a missing library ( Apache Commons-CLI ) in your classpath. So add that library and try again.
And about this error,
Unable to locate Spring NamespaceHandler for XML schema namespace [ http://www.springframework.org/schema/aop]
The problem occurs when using the aop
namespace without having the necessary aop
spring library on the classpath.
But I see you have imported that library.
Another cause is you are trying to create a fat.jar file, so spring.handlers / spring.schemas
get overwritten when merging multiple spring dependencies into a single jar file.
So I suggest to use Apache Maven Shade Plugin and rebuild the project. And this is the Gradle version of Apache Maven's Shade Plugin .
The Shadow Plugin for gradle has a problem: You have to tell it how to handle file collisions, ie files with the same name. While this is not hard, like @Roman Harasymenko mentioned and I use it (Kotlin DSL):
tasks.withType<ShadowJar> {
mergeServiceFiles()
append("META-INF/spring.handlers")
append("META-INF/spring.schemas")
append("META-INF/spring.tooling")
transform(
PropertiesFileTransformer().apply {
paths = mutableListOf("META-INF/spring.factories")
mergeStrategy = "append"
})
}
it doesn't tell in its current version when such a conflict occurs, so you have to waste big amounts of time finding the conflicts yourself. But there is a pull request that it tells if there is a collision: https://github.com/johnrengelman/shadow/pull/773 . Until the pull request gets merged you could use the forked branch to be always informed about file collisions: https://github.com/JD-CSTx/shadow/tree/chapmajs-collision_logging
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.