🍃

Spring Boot 4でwiremock-jetty12を使うときの注意点

に公開

環境

  • Spring Boot 4.0.1
  • wiremock-jetty12 3.13.2

今後のバージョンアップにより、本記事の対応が不要になる可能性があります。

発生した問題

普通にpom.xmlを記述した。

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>sample-function</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>25</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-restclient</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-restclient-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- WireMock -->
        <dependency>
            <groupId>org.wiremock</groupId>
            <artifactId>wiremock-jetty12</artifactId>
            <version>3.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!-- (以下略) -->
</project>

WireMockを使ったテストを書いた。

SampleClientTest.java
@SpringBootTest
class SampleClientTest {
    @RegisterExtension
    static WireMockExtension wireMock = WireMockExtension.newInstance()
            .options(wireMockConfig()
                    .port(9999)
            ).build();
    
    @Autowired
    SampleClient sampleClient;

    @Nested
    @DisplayName("getMessage()")
    class GetMessage {
        @Test
        @DisplayName("200: メッセージを取得できる")
        void success() {
            // WireMock設定
            stubFor(get("/api/message")
                    .willReturn(aResponse()
                            .withStatus(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody("""
                                    {"message":"Hello!"}
                                    """)
                    )
            );

            // 実行
            SampleResponse actual = sampleClient.getMessage();

            // 検証
            assertEquals(new SampleResponse("Hello!"), actual);
        }
    }
}

テストを実行すると、次のような例外になった🫠

実行結果
Test ignored.

Test ignored.

java.lang.NoSuchMethodError: 'org.eclipse.jetty.util.component.Environment org.eclipse.jetty.util.component.Environment.ensure(java.lang.String)'

	at org.eclipse.jetty.ee10.servlet.ServletContextHandler.<clinit>(ServletContextHandler.java:135)
	at com.github.tomakehurst.wiremock.jetty12.Jetty12HttpServer.addAdminContext(Jetty12HttpServer.java:256)
	at com.github.tomakehurst.wiremock.jetty12.Jetty12HttpServer.createHandler(Jetty12HttpServer.java:195)
	at com.github.tomakehurst.wiremock.jetty.JettyHttpServer.<init>(JettyHttpServer.java:101)
	at com.github.tomakehurst.wiremock.jetty12.Jetty12HttpServer.<init>(Jetty12HttpServer.java:74)
	at com.github.tomakehurst.wiremock.jetty12.Jetty12HttpServerFactory.buildHttpServer(Jetty12HttpServerFactory.java:33)
	at com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:75)
	at com.github.tomakehurst.wiremock.junit5.WireMockExtension.startServerIfRequired(WireMockExtension.java:233)
	at com.github.tomakehurst.wiremock.junit5.WireMockExtension.beforeAll(WireMockExtension.java:300)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)

原因

Maven Central Repositoryを確認したところ、wiremock-jetty12 3.13.2はJetty 12.0.30に依存している。

抜粋
  ...
  <version>3.13.2</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-bom</artifactId>
          <!-- これがJettyのバージョン -->
        <version>12.0.30</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty.ee10</groupId>
        <artifactId>jetty-ee10-bom</artifactId>
          <!-- これがJettyのバージョン -->
        <version>12.0.30</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  ...

しかし、先ほどテストしたアプリケーションの依存性を確認すると、Jetty 12.1.5になっている。これが原因っぽい。本来あるべき12.0.30とバージョンが異なるので、対象のメソッドが削除されていてもおかしくない。

なぜこうなっているかと言うと、Spring Boot 4.0.1が管理しているJettyのバージョンが12.1.5だから。

https://docs.spring.io/spring-boot/appendix/dependency-versions/coordinates.html

対策

ということで、Jettyのバージョンを無理やり12.0.30にすればよい。具体的には次のようにする。

pom.xml(修正後)
    ...
    <properties>
        <java.version>25</java.version>
    </properties>

    <!-- これを追加!!! -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-bom</artifactId>
                <version>12.0.30</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
    ...

これでJetty 12.0.30になり、JUnitテストも無事に実行できました。

Discussion