これは、なにをしたくて書いたもの?
このところ、WildFlyを使ったりしている時に毎回毎回Maven War Pluginの設定を書いていたのですが、その理由は
failOnMissingWebXmlをpropertiesに書いても効かなくなっていたからです。
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties>
とはいえ、Maven War Pluginを毎回書くのも微妙だなぁと思ってどうしたらいいのか少し調べてみました。
Maven War Plugin 3.1.0から、failOnMissingWebXmlのデフォルト値の動きが変わっていたという話
Maven War Pluginのwar:warゴールにあるfailOnMissingWebXmlの説明を見ると、プロジェクトの依存関係に
Servlet 3.0より新しいAPIに依存しているかどうかで、デフォルト値が変わると書かれています。
Starting with 3.1.0, this property defaults to false if the project depends on the Servlet 3.0 API or newer.
war:war / Parameter Details / failOnMissingWebXml
早い話が、プロジェクトの依存関係にServlet 3.0以上があるとデフォルト値がfalseになるということですね。
それはそうと、properties直下で指定した時に効かなくなったのが気になるのですが、このあたりが怪しいですね。
Mavenのコアとパッケージ名が衝突していたので、リネームしたんですって。
この挙動はMaven War Plugin 3.0以降でしょうか?
どちらにしてももう効かないみたいなので、あまり過去に遡ろうとは思いませんが。
では、少し確認してみましょう。
環境
今回の環境はこちら。
$ java --version openjdk 21.0.5 2024-10-15 OpenJDK Runtime Environment (build 21.0.5+11-Ubuntu-1ubuntu124.04) OpenJDK 64-Bit Server VM (build 21.0.5+11-Ubuntu-1ubuntu124.04, mixed mode, sharing) $ mvn --version Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 21.0.5, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "6.8.0-52-generic", arch: "amd64", family: "unix"
サンプルコード
確認用のWARプロジェクトを作成します。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>war-test</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.release>21</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-core</artifactId> <version>6.2.11.Final</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-servlet-initializer</artifactId> <version>6.2.11.Final</version> </dependency> </dependencies> <build> <finalName>ROOT</finalName> </build> </project>
動作確認用にRESTEasyを依存関係に加えていますが、RESTEasyの推移的依存関係にServlet APIは現れません。
以下はmvn dependency:treeの結果です。
[INFO] --- dependency:3.7.0:tree (default-cli) @ war-test --- [INFO] org.littlewings:war-test:war:0.0.1-SNAPSHOT [INFO] +- org.jboss.resteasy:resteasy-core:jar:6.2.11.Final:compile [INFO] | +- org.jboss.logging:jboss-logging:jar:3.5.3.Final:compile [INFO] | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile [INFO] | +- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.1.0:compile [INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:3.0.1:compile [INFO] | +- org.jboss:jandex:jar:2.4.5.Final:compile [INFO] | +- org.jboss.resteasy:resteasy-core-spi:jar:6.2.11.Final:compile [INFO] | +- org.reactivestreams:reactive-streams:jar:1.0.4:compile [INFO] | +- jakarta.activation:jakarta.activation-api:jar:2.1.3:compile [INFO] | +- org.eclipse.angus:angus-activation:jar:2.0.2:compile [INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:compile [INFO] | \- com.ibm.async:asyncutil:jar:0.1.0:compile [INFO] \- org.jboss.resteasy:resteasy-servlet-initializer:jar:6.2.11.Final:compile [INFO] ------------------------------------------------------------------------
Jakarta RESTful Web Servicesのコードも加えておきますが、動作確認は省略します。
src/main/java/org/littlewings/war/HelloResource.java
package org.littlewings.war; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @Path("/hello") public class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN) public String message() { return "Hello World"; } }
src/main/java/org/littlewings/war/RestApplication.java
package org.littlewings.war; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class RestApplication extends Application { }
web.xmlは用意していません。
いろいろ設定を変えて試してみる
まずpropertiesにfailOnMissingWebXmlを追加してみます。
<properties> <maven.compiler.release>21</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <failOnMissingWebXml>false</failOnMissingWebXml> </properties>
パッケージング。
$ mvn package
Maven War Pluginについては特になにも指定していませんが、Apache Maven 3.9.9ではMaven War Plugin 3.4.0が
動作するようです。
[INFO] --- war:3.4.0:war (default-war) @ war-test ---
で、これは失敗します。
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:3.4.0:war (default-war) on project war-test: Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode) -> [Help 1]
いったんpropertiesに追加したfailOnMissingWebXmlは削除。
<properties> <maven.compiler.release>21</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties>
Maven War Pluginを明示的に追加し、ここにfailOnMissingWebXmlを設定。
<build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build>
今度は成功します。
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
ですが、これだけのために前は書いていなかったMaven War Pluginを追加したくないな、と。
ここで、Maven War Pluginの設定をコメントアウト。
<!-- <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> -->
プロジェクトの依存関係に、Jakarta Servletを追加します。
<dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency>
すると、ビルドができるようになります。
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
確かにデフォルト値が変わっているようです。
どうやって判定しているかというと、プロジェクトのクラスパス上にjavax.servlet.annotation.WebServletまたは
jakarta.servlet.annotation.WebServletがあるかどうかを見ているようです。
というわけで、Jakarta Servletへの依存関係は入れておいた方がよさそうですね。
おわりに
Maven War PluginのfailOnMissingWebXmlの挙動でちょっと困っていた、という話でした。
前のようにfailOnMissingWebXmlをpropertiesの直下に書いても効かなくなったのはちょっと扱いにくくなりましたが、
仕方ないかなと。
最近、Jakarta EEのAPIを使ってWebアプリケーションを書いている時はJakarta RESTful Web Servicesや
Jakarta Contexts and Dependency Injectionなどを依存関係に書いても、Jakarta Servletを明示的に書くことは
少なかったので、よくこの問題を踏んでいたんですよね。
特になにも考えずにMaven War Pluginの設定をしていたのですが、今後はJakarta Servletを依存関係に入れるように
していきましょう。Jakarta Servletが使えないランタイム上で使うことはそうそうないと思いますし、そもそも
Jakarta Servletが使えない環境下だと扱うのはWARファイルではないでしょう。