Java: EasyBuggy Boot - Spring Tools 4 Eclipseで開発・デバッグする

# EasyBuggy Bootとは

メモリリーク、デッドロック、JVMクラッシュ、SQLインジェクションなど、バグや脆弱性の動作を理解するためにつくられたバグだらけのWebアプリケーションです。Apache 2.0ライセンスで公開されています。

https://github.com/k-tamura/easybuggy4sb/blob/master/README.jp.md

# 開発・デバッグできるようにするまで

作者が[EASYBUGGY BOOTのトリセツ](https://t246osslab.wordpress.com/2017/08/27/easybuggy-boot%E3%81%AE%E3%83%88%E3%83%AA%E3%82%BB%E3%83%84/)に情報をまとめている。
しかし、2021年現在の私の環境では、そのまま実行してもうまくいかなかった。
このため、本記事にて改めて開発、デバッグできるようにするまでの手順をまとめる。

本記事では、Spring Tools 4 for Eclipse(Windows 64-BIT)を利用している。

## 前提

Java(JDK) 8とmavenがインストールされていること。
インストールされていない場合は、下記の記事を参考に。

https://qiita.com/kurukuruz/items/3425a6f7a836433ca9f8

## Spring Tools 4 for Eclipseのダウンロード

下記ページから`Spring Tools 4 for Eclipse`を選択し、`spring-tool-suite-4-4.9.0.RELEASE-e4.18.0-win32.win32.x86_64.self-extracting.jar`(2021年3月10日時点)をダウンロードする。

https://spring.io/tools

## ファイルの解凍(展開)

ダウンロードされたjarファイルを、Spring Tools 4を配置する任意のフォルダに移動させる。
ダブルクリックして実行すると、`sts-4.9.0.RELEASE`フォルダが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/1f5cd5d2-aa99-6ff8-3dea-adf108813c7a.png)

## Spring Tools 4の実行

フォルダ内の`SpringToolSuite4.exe`を実行する。
すると、スプラッシュスクリーンが表示されるので、しばらく待つ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/4db289f6-c065-a049-ef09-77d61439b135.png)

## ワークスペースディレクトリの選択

特に希望がなければこのままでよい。Launchボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/e931d9f8-3003-1d2e-9a5e-82aad12455d2.png)

## Spring Tools 4メイン画面の確認

特に問題がなければ、このような画面が表示される。
左上に表示されているPackage Explorer内の選択肢から、`Import projects...` を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/5eb99b47-ec8a-c0b2-7ef3-bd8d3613387b.png)

## プロジェクトのインポート

Importダイアログ内の`Git > Projects from Git(with smart import)` を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/9bf9a1f3-df1d-638c-76ee-4b8db0ff3433.png)

`Clone URI`を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/e6a839ba-3358-f1ba-ff35-29662b57fc1b.png)

`Location > URI`に`https://github.com/k-tamura/easybuggy4sb.git`を入力する。Nextボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/553fd796-cd51-97e9-6aa3-69390e664bf5.png)

Nextボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/3ed04a30-25c3-3fc7-9403-b319d0c45972.png)

Nextボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/d3be0b88-b35e-310e-8eae-3bb58a2d1db3.png)

Finishボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/550d9cce-0bae-6935-afc7-958897301a43.png)

## Mavenプロジェクトのビルド

自動的にMavenプロジェクトとしてビルドされるので、しばらく待つ。(5分程度)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/00189e03-5fa8-0ce3-9789-dc34a753d1dd.png)

## 起動(に失敗する)

`Boot Dashboard`ペイン内の`Start or restart the process associated with the selected elements in debug mode` ボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/5b14dec8-1536-2828-220a-8c3f76f23e82.png)
・・・と、`ClassCastException`が発生して終了してしまう。

```
Exception in thread "main" java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')
	at org.springframework.boot.devtools.restart.DefaultRestartInitializer.getUrls(DefaultRestartInitializer.java:93)
	at org.springframework.boot.devtools.restart.DefaultRestartInitializer.getInitialUrls(DefaultRestartInitializer.java:56)
	at org.springframework.boot.devtools.restart.Restarter.<init>(Restarter.java:140)
	at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:546)
	at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:67)
	at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:45)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:122)
	at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:69)
	at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:48)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:292)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
	at org.t246osslab.easybuggy4sb.Easybuggy4sbApplication.main(Easybuggy4sbApplication.java:15)
```

## DevToolsを削除する

仕方がないので、回避策をとる。
`Package Explorer`内の`easybuggy4sb`プロジェクトを右クリックし、 `Spring > Remove DevTools` を選択する。

DevToolsを削除した後に、再度起動を試みる。

しかし、今度は別のエラーが発生してしまう。

```
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2021-03-10 23:56:56.503 ERROR 27856 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'halMessageConverterSupportedMediaTypeCustomizer': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/hateoas/mvc/TypeConstrainedMappingJackson2HttpMessageConverter
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:137) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration.createChildManagementContext(EndpointWebMvcAutoConfiguration.java:193) ~[spring-boot-actuator-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration.afterSingletonsInstantiated(EndpointWebMvcAutoConfiguration.java:156) ~[spring-boot-actuator-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:781) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) ~[spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.t246osslab.easybuggy4sb.Easybuggy4sbApplication.main(Easybuggy4sbApplication.java:15) ~[classes/:na]
Caused by: java.lang.NoClassDefFoundError: org/springframework/hateoas/mvc/TypeConstrainedMappingJackson2HttpMessageConverter
	at org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration$HalMessageConverterSupportedMediaTypesCustomizer.configureHttpMessageConverter(HypermediaHttpMessageConverterConfiguration.java:83) ~[spring-boot-autoconfigure-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration$HalMessageConverterSupportedMediaTypesCustomizer.configureHttpMessageConverters(HypermediaHttpMessageConverterConfiguration.java:77) ~[spring-boot-autoconfigure-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration$HalMessageConverterSupportedMediaTypesCustomizer.configureHttpMessageConverters(HypermediaHttpMessageConverterConfiguration.java:67) ~[spring-boot-autoconfigure-1.5.7.RELEASE.jar:1.5.7.RELEASE]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134) ~[spring-beans-4.3.11.RELEASE.jar:4.3.11.RELEASE]
	... 24 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606) ~[na:na]
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168) ~[na:na]
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
	... 34 common frames omitted
```

## Spring Bootのバージョンを上げる

pom.xmlを開き、`spring-boot-starter-parent`のversionを最新に書き換える。

```xml:Before
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.6.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
```

```xml:After
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.22.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
```

## (ようやく)起動成功

Consoleに下記のようなログが出力されたら成功。

```
2021-03-11 00:07:43.360  INFO 17724 --- [           main] o.t.e.Easybuggy4sbApplication            : Started Easybuggy4sbApplication in 5.688 seconds (JVM running for 6.237)
```

[http://localhost:8080/](http://localhost:8080/)にアクセスすると、EasyBuggyのメインページが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/6d553596-b386-11e5-76a0-9e58eed7e814.png)

おつかれさまでした。

# 関連記事

- [バグだらけのWebアプリケーションのクローンをSpring Bootでつくってみました](https://qiita.com/tamura__246/items/c8229d68ef199890827b)
- [EasyBuggyとEasyBuggy BootをEclipseから同時に開発・デバッグできるようにするまで](https://qiita.com/flyaway/items/4922af5dbaafa1942e88)