Glassfish 4.x に Spring Boot 2.4 アプリケーションをデプロイするには

古いバージョンの Glassfish を使うのはどうなの？というのはあるかもしれませんが、大人の事情でサーバーのバージョンを変えられない場合の対処方法です。

# glassfish-web.xml の同梱

Spring Initilizr(Packaging は war) で作成したままのプロジェクトを Glassfish 4.x にデプロイしようとすると以下のエラーが発生して失敗します。

---

Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Cannot inherit from final class. Please see server.log for more details

---

これは、

- [Glassfish4.1上でJacksonを含むアプリを動かす際の注意事項 - Qiita](https://qiita.com/yukyu2nd/items/ca3c46b0075106ebc4b2)
- [glasssfish4.1.2でspring bootアプリのデプロイについて｜teratail](https://teratail.com/questions/185325)

などにある通り、Glassfish にデフォルトで付属している Jackson のバージョンが古くデプロイするパッケージに含まれるものより、先に読み込まれてしまうのが原因のようです。(前者のように Glassfish 側のライブラリを置き換えてしまうという手もあるようですが、以下はそれができない場合の説明です。)

そのため、デプロイするパッケージに 以下のような Glassfish 用の設定ファイル glassfish-web.xml を含める必要があります。

```xml
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
	<class-loader delegate="false" />
</glassfish-web-app>
```

ソースでの配置場所は src\main\webapp\WEB-INF です。

なお、Eclipse 等で http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd が有効な URL ではないため、エラー扱いになってしまいますが、特に問題ありません。(気になるようであれば、[glassfish.org は消滅したので DTD が読み込めなくなったのですケド - A Memorandum](https://blog1.mammb.com/entry/2018/02/20/124236) にある方法を試してみてください。)

## 参考文献

- [java - Error while deploying spring boot app on glassfish 4.1 - Stack Overflow](https://stackoverflow.com/questions/59069204/error-while-deploying-spring-boot-app-on-glassfish-4-1)
- [Class Loader Delegation (Oracle GlassFish Server 3.0.1 Application Development Guide) ](https://docs.oracle.com/cd/E19798-01/821-1752/beagb/index.html)
- [Interstage Application Server 運用ガイド 2.2.1 アプリケーションの定義](https://software.fujitsu.com/jp/manual/manualfiles/m120022/b1wd3166/01z200/b3166-00-02-02-01.html)

# pom.xml の修正

前項の修正をしただけでは、デプロイ時に以下のエラーが発生します。

---

Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.cfg.beanvalidation.IntegrationException: Error activating Bean Validation integration. Please see server.log for more details.

---

これは、validation-api 周りのバージョンが合わないためのようです。

これを回避するために pom.xml を修正します。

まず、spring-boot-starter-validation と spring-boot-starter-web の依存パッケージから、hibernate-validator を除外します。

```xml
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
	  		<exclusions>
		  		<exclusion>
		  			<groupId>org.hibernate.validator</groupId>
		  			<artifactId>hibernate-validator</artifactId>
		  		</exclusion>
	  		</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
	  		<exclusions>
		  		<exclusion>
		  			<groupId>org.hibernate.validator</groupId>
		  			<artifactId>hibernate-validator</artifactId>
		  		</exclusion>
	  		</exclusions>
		</dependency>
```

そして、hibernate-validator と validation-api の古いバージョンを依存関係に加えます。

```xml
	  	<dependency>
	  		<groupId>org.hibernate</groupId>
	  		<artifactId>hibernate-validator</artifactId>
	  		<version>5.4.3.Final</version>
	  	</dependency>
	  	<dependency>
	  		<groupId>javax.validation</groupId>
	  		<artifactId>validation-api</artifactId>
	  		<version>1.1.0.Final</version>
	  	</dependency>
```

これらの修正を行い、 `mvn package` を実行すれば、Glassfish 4.x にデプロイできるようになりました。

## 参考文献

- [hibernate - java.lang.NoSuchMethodError: javax.validation.BootstrapConfiguration.getClockProviderClassName - Stack Overflow](https://stackoverflow.com/questions/48323244/java-lang-nosuchmethoderror-javax-validation-bootstrapconfiguration-getclockpro/59950466#59950466)