読者です 読者をやめる 読者になる 読者になる

maven central に存在しない 3rd party 製 jar の扱い方

概要

ビルドシステムとして maven を使用している場合に、maven central に存在しない 3rd party 製 jar を扱う方法をいくつか考察してみました。

  1. 3rd party に頼んで jar を central repository にアップしてもらう
  2. 社内リポジトリに jar を deploy する
  3. ローカルリポジトリに jar を install する
  4. system scope で扱う
  5. localRepositoryPath を使用する
  6. localRepositoryPath と maven-shade-plugin を併用する

各方法の考察

3rd party に頼んで jar を central repository にアップしてもらう

これが最初に考慮すべき方法で、最も理想的な方法です。

しかし、時間的余裕が無い場合やNDAを前提としてjarが配布される場合などは、選択肢に含まれないかもしれません。

社内リポジトリに jar を deploy する

開発環境が社内に閉じている場合は、この方法がセカンドベストです。アクセス制限なども可能となるので、NDAを前提としてjarが配布される場合などにも対応が可能です。

しかし、開発環境が社内に閉じていない場合には何らかの対策が必要になります。

ローカルリポジトリに jar を install する

各自が何らかの方法で jar を取得してローカルリポジトリに install する方法は、さまざまな開発環境に柔軟に対応できます。

しかし、独自に jar を取得する手間と、その jar をローカルリポジトリに install する手間がかかります。また、VCS からチェックアウトした直後にコンパイルが通らないためバグと勘違いされて無用な工数をかけてしまう可能性もあります。

例:

mvn install:install-file -Dfile=[your jar file] -DgroupId=[groupId] -DartifactId=[artifactId] -Dversion=[version] -Dpackaging=jar

参考:http://maven.apache.org/plugins/maven-install-plugin/install-file-mojo.html

system scope で扱う

packaging が war や apk のように、ライブラリとして外部参照されるものでない場合はには優れた方法です。jar をプロジェクト内部に入れておけば、VCS からチェックアウトした状態でコンパイルを通すことができます。

しかし、packaging が jar の場合など、ライブラリとして外部から参照される場合には、参照する側が 3rd party の jar を取得できないという問題があります。*1

参考:http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#System_Dependencies

localRepositoryPath を使用する

system scope で扱う場合に似た特徴を持ちますが、install する手間がかかります。

対象の jar をプロジェクト内リポジトリに install する例

プロジェクト内の repo ディレクトリ以下に 3rd party 製の jar を install して VCS 上にコミット:

project.basedir からコマンドラインで install する場合:

mvn install:install-file -DlocalRepositoryPath=repo -DcreateChecksum=true -Dpackaging=jar -Dfile=[your-jar] -DgroupId=[...] -DartifactId=[...] -Dversion=[...]

ビルドシステムがプロジェクト内レポジトリを参照する場合の pom.xml設定例:

  <!-- Repositories : http://maven.apache.org/pom.html#Repositories -->
  <repositories>
    <repository>
      <id>repo</id>
      <releases>
        <enabled>true</enabled>
        <checksumPolicy>ignore</checksumPolicy>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <url>file://${project.basedir}/repo</url>
    </repository>
  </repositories>

※マルチプロジェクトの場合は root の pom.xml だけに記述すればOKです

localRepositoryPath と maven-shade-plugin を併用する

packaging が jar の場合など、ライブラリとして外部から参照される場合にも対応可能な方法です。3rd party の jar の内容を自身の jar に含めてしまうため、このプロジェクトを参照する側に一切の仕掛けは必要ありません。

localRepositoryPath を使用する方法を採用し、さらに以下のように対象ライブラリを指定して、成果物の jar に含めてしまいます。

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <configuration>
          <artifactSet>
            <includes>
              <include>[target_lib_group]:[target_lib_artifact]</include>
            </includes>
          </artifactSet>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

この方法は、system scope では実現できないので、注意してください。*2

まとめ

ケースバイケースですね。

*1:たとえば、3rd party ライブラリが a.jar に含まれ、b.apk が a.jar を参照するが 3rd party ライブラリを直接参照していない場合、コンパイル時には問題を検出できず、実行時にいきなり NoClassDefFoundError 等で落ちます。

*2:system scope はあらゆるシステムに存在することが前提と考えられるため、maven-shade-plugin の対象にはなりません