uber-jar 를 만들기 위한 maven shade plugin
소개
의존성을 포함한 실행 가능한 single jar(이하 uber-jar) 파일을 생성해 주는 플러그인. maven assembly plugin 대신 shade plugin 사용하는게 좋음.
uber-jar 의미
사용
실행 가능 jar 만들기
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.sonatype.haven.HavenCli</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
CODE
실행 가능한 jar 를 만들기 위해 transformer 에 mainClass 를 설정
Spring app
spring 을 사용한 console app 를 shade 플러그인을 사용하여 uber jar 로 생성하는 예제.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.app.MinimalSpringApp</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
XML
만약 assembly plugin 으로 single jar 파일을 만들면 다음과 같이 spring xml 스키마를 찾지 못하는 예외 발생
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
Offending resource: URL [jar:file:/home/lesstif/proj/target/proj-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/application-config.xml]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
CODE
“Invalid signature file” 해결
manifesto 가 있는 jar 파일의 경우 shade 플러그인으로 묶을 때 다음과 같은 에러가 발생할 수 있음
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
CODE
manifest signature 를 제외하는 내용 추가
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<!-- Additional configuration. -->
</configuration>
XML
junit 까지 포함하여 jar 만들기
junit 테스트 케이스가 포함된 jar 를 만들고 싶은 경우 junit.jar를 포함해서 최종 jar 를 생성해야 한다. <configuration> 항목에 filters 로 포함할 패키지와 제외할 패키지를 설정할 수 있다.
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/**</include>
<include>org/junit/**</include>
</includes>
</filter>
<filter>
<artifact>org.hamcrest:hamcrest-all</artifact>
<includes>
<include>org/hamcrest/**</include>
<include>com/thoughtworks//**</include>
</includes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
XML
<dependency> 설정에서 junit 의 scope 이 <test> 면 포함되지 않으므로 <scope>test</scope> 항목을 주석 처리해야 한다.
생성한 uber-jar 는 다음과 같이 junit 테스트 케이스를 바로 실행할 수 있다. (TestCase 는 실행할 junit 테스트)
java -cp target/myproj-1.0.1.jar org.junit.runner.JUnitCore TestCase
CODE
Ref
- http://maven.apache.org/plugins/maven-shade-plugin/
- http://stackoverflow.com/questions/11947037/what-is-an-uber-jar/11947093#11947093
- http://stackoverflow.com/questions/15110671/unable-to-locate-spring-namespacehandler-error
- http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar/6743609#6743609