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>

실행 가능한 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>

만약 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)


“Invalid signature file” 해결

manifesto 가 있는 jar 파일의 경우 shade 플러그인으로 묶을 때 다음과  같은 에러가 발생할 수 있음

Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes


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>


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>

<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


Ref