GradleでServlet APIを除外設定する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Javaの小ネタが続く渡辺です。

つまり、そんな案件が続いているってことになります(笑)

Servlet API

Servlet APIはJava EEの基盤となるAPIですが、歴史は非常に古く、Version1が公開されたのは1997年です。 もうすぐ20年になる非常に古くからある仕様であり、現在はJavaEE 7に組み込まれている 3.1.0 が最新バージョンとなっています。

通常、Servlet APIはTomcat や Galssfishといったアプリケーションサーバ(Java EEアプリケーションサーバでなくてもOK)でバンドルされています。 したがって、WARファイルを作成する場合にはServlet APIのJARファイルを含めません。 これは、含めてしまうと、バージョンの異なるServlet APIが混在する可能性があり、予期せぬ挙動を引き起こす可能性があるからです。

Gradleでライブラリの依存関係の解決

Gradleでは、ライブラリ(JAR)の依存関係を解決します

あるライブラリが遡ってServlet APIを利用しているならば、自動的にServlet APIを依存ライブラリとして認識します。 通常はこの動きは妥当なのですが、Servlet APIのように、成果物(WAR)に含めたくないライブラリ(JAR)も存在します。 この時、ライブラリの設定ファイルで適切な設定が行われていれば、特別な設定をしなくとも、Servlet APIが成果物(WAR)に含まれません。 しかし、往々にして何らかのライブラリが依存関係の処理が甘い結果、Servlet APIがWARに紛れ込んでしまい、予期せぬ挙動をするものです。

明示的にexclude設定を行う

したがって、明示的にServlet APIを依存関係の自動適用から除外します。

次の設定は、build.gradleの一部です。

configurations {
    all*.exclude group: 'javax.servlet-api', module: 'servlet-api'
}

これで解決・・・するならば、こんなエントリーは不要ですね(´・ω・`)

このように設定したのに何故かServlet APIがWARに含まれました。 しかも3.1.0を指定しているのに、2系が・・・。

Servlet APIのGroupID

答えは、ライブラリのGroupIDにありました。

実は、Servlet APIのGroupIDは、2.X系まではjavax.servletであり、3.0以降はjavax.servlet-apiに変更されています。 Maven リポジトリでは、GroupID, ArtifactID, Versionでライブラリを一意に識別します。 javax.servlet-api:servlet-api:3.Xは、javax.servlet:servlet-api:2.Xの上位バージョンとして認識されません(怒)。 おまけに除外設定からすり抜けてきます(トホホ)

もれなく、Servlet APIを除外するには次のように記述しなければなりません。

configurations {
    // javax.servlet-api:servlet-api:3.X
    // javax.servlet:servlet-api:2.X
    all*.exclude group: 'javax.servlet-api', module: 'servlet-api'
    all*.exclude group: 'javax.servlet', module: 'servlet-api'
}

または、module(artifactID)のみを指定し、次のようにします。

configurations {
    // javax.servlet-api:servlet-api:3.X
    // javax.servlet:servlet-api:2.X
    all*.exclude module: 'servlet-api'
}

どうして、変更したし・・・(´・ω・`)