Spring Boot 2.1.x の Web アプリを 2.2.x へバージョンアップする ( その4 )( Spring Boot を 2.1.11 → 2.2.2 へバージョンアップする )
概要
記事一覧はこちらです。
Spring Boot 2.1.x の Web アプリを 2.2.x へバージョンアップする ( その3 )( Gradle を 5.6.4 → 6.0.1 へバージョンアップする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Spring Boot を 2.1.11 → 2.2.2 へバージョンアップします。
参照したサイト・書籍
Issue 438464: json displayed with wrong encoding (i.e. not unicode)
https://bugs.chromium.org/p/chromium/issues/detail?id=438464Bug 197369 - JSON displayed with wrong encoding when loaded in a frame (browser default instead of UTF-8)
https://bugs.webkit.org/show_bug.cgi?id=197369Deprecate MediaType.APPLICATION_JSON_UTF8 in favor of APPLICATION_JSON
https://github.com/spring-projects/spring-framework/issues/22788Upgrading to Spring Framework 5.x - Upgrading to Version 5.2
https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x#upgrading-to-version-52What's New in Spring Framework 5.x - What's New in Version 5.2
https://github.com/spring-projects/spring-framework/wiki/What's-New-in-Spring-Framework-5.x#whats-new-in-version-52
目次
手順
Spring Initializr で 2.2.2 のプロジェクトを作成する
Spring Initializr で 2.2.2 のプロジェクトを作成して、生成された build.gradle を見て反映した方が良い点があるか確認します。
以下の build.gradle が作成されました。今回は Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その3 )( build.gradle を変更する ) で実施した時のような「Import Module from Gradle」ダイアログは表示されませんでした。
plugins { id 'org.springframework.boot' version '2.2.2.RELEASE' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { developmentOnly runtimeClasspath { extendsFrom developmentOnly } compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-freemarker' implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.session:spring-session-data-redis' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.projectlombok:lombok' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } testImplementation 'org.springframework.security:spring-security-test' } test { useJUnitPlatform() }
以下の点はこれまで見たことがなかったので build.gradle に反映します。
configurations { ... }
の記述が追加されている。- dependencies block で
org.springframework.boot:spring-boot-devtools
を指定する時の記述がdevelopmentOnly
になっている。 testImplementation('org.springframework.boot:spring-boot-starter-test')
にexclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
が記述されている。
build.gradle を変更する
buildscript { ext { group "ksbysample" version "2.2.2-RELEASE" } repositories { mavenCentral() maven { url "https://repo.spring.io/release/" } gradlePluginPortal() } } plugins { id "java" id "eclipse" id "idea" id "org.springframework.boot" version "2.2.2.RELEASE" id "io.spring.dependency-management" version "1.0.8.RELEASE" id "groovy" id "checkstyle" // id "com.github.spotbugs" version "1.6.9" id "pmd" id "net.ltgt.errorprone" version "0.7.1" id "com.gorylenko.gradle-git-properties" version "2.2.0" } .......... configurations { developmentOnly runtimeClasspath.extendsFrom developmentOnly compileOnly.extendsFrom annotationProcessor // annotationProcessor と testAnnotationProcessor、compileOnly と testCompileOnly を併記不要にする testAnnotationProcessor.extendsFrom annotationProcessor testImplementation.extendsFrom compileOnly // for Doma 2 domaGenRuntime } .......... dependencyManagement { imports { // mavenBom は以下の URL のものを使用する // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.2.2.RELEASE/ // bomProperty に指定可能な property は以下の URL の BOM に記述がある // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.2.2.RELEASE/spring-boot-dependencies-2.2.2.RELEASE.pom mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) { // Spring Boot の BOM に定義されているバージョンから変更する場合には、ここに以下のように記述する // bomProperty "thymeleaf.version", "3.0.9.RELEASE" } mavenBom("org.junit:junit-bom:5.5.2") } } dependencies { def jdbcDriver = "org.postgresql:postgresql:42.2.9" def spockVersion = "1.3-groovy-2.5" def domaVersion = "2.26.0" def lombokVersion = "1.18.10" def errorproneVersion = "2.3.3" def powermockVersion = "2.0.4" // def spotbugsVersion = "3.1.11" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-data-redis") implementation("org.springframework.boot:spring-boot-starter-amqp") implementation("org.springframework.boot:spring-boot-starter-actuator") developmentOnly("org.springframework.boot:spring-boot-devtools") compileOnly("org.springframework.boot:spring-boot-configuration-processor") implementation("org.springframework.session:spring-session-data-redis") implementation("org.springframework.retry:spring-retry") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") implementation("org.apache.commons:commons-lang3") implementation("org.codehaus.janino:janino") implementation("io.micrometer:micrometer-registry-prometheus") testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude group: "org.junit.vintage", module: "junit-vintage-engine" } testImplementation("org.springframework.security:spring-security-test") testImplementation("org.yaml:snakeyaml") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの runtimeOnly("${jdbcDriver}") implementation("com.integralblue:log4jdbc-spring-boot-starter:2.0.0") implementation("org.simpleframework:simple-xml:2.7.1") implementation("com.univocity:univocity-parsers:2.8.4") implementation("com.google.guava:guava:28.1-jre") implementation("org.flywaydb:flyway-core:6.1.3") testImplementation("org.dbunit:dbunit:2.6.0") testImplementation("com.icegreen:greenmail:1.5.11") testImplementation("org.assertj:assertj-core:3.14.0") testImplementation("com.jayway.jsonpath:json-path:2.4.0") testImplementation("org.jsoup:jsoup:1.12.1") testImplementation("cglib:cglib-nodep:3.3.0") testImplementation("org.spockframework:spock-core:${spockVersion}") testImplementation("org.spockframework:spock-spring:${spockVersion}") // for lombok // testAnnotationProcessor、testCompileOnly を併記しなくてよいよう configurations で設定している annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma annotationProcessor("org.seasar.doma:doma:${domaVersion}") implementation("org.seasar.doma:doma:${domaVersion}") domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}") domaGenRuntime("${jdbcDriver}") // for JUnit 5 // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("org.junit.platform:junit-platform-launcher") // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}") // PowerMock testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}") testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}") // for SpotBugs // compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") // compileOnly("net.jcip:jcip-annotations:1.0") // compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}") // testImplementation("com.google.code.findbugs:jsr305:3.0.2") }
Spring Boot 2.2.2 へのバージョンアップとして以下の点を変更します。
- buildscript block の以下の点を変更します。
version "2.1.11-RELEASE"
→version "2.2.2-RELEASE"
- plugins block の以下の点を変更します。
id "org.springframework.boot" version "2.1.11.RELEASE"
→id "org.springframework.boot" version "2.2.2.RELEASE"
- configurations block に以下の3行を追加します。
developmentOnly
runtimeClasspath.extendsFrom developmentOnly
compileOnly.extendsFrom annotationProcessor
- dependencies block の以下の点を変更します。
runtimeOnly("org.springframework.boot:spring-boot-devtools")
→developmentOnly("org.springframework.boot:spring-boot-devtools")
testImplementation("org.springframework.boot:spring-boot-starter-test")
にexclude group: "org.junit.vintage", module: "junit-vintage-engine"
を追加します。
各種ライブラリのバージョンアップとして以下の点を変更します。
- plugins block の以下の点を変更します。
id "com.gorylenko.gradle-git-properties" version "2.0.0"
→id "com.gorylenko.gradle-git-properties" version "2.2.0"
- dependencyManagement の以下の点を変更します。
mavenBom("org.junit:junit-bom:5.4.1")
→mavenBom("org.junit:junit-bom:5.5.2")
- dependencies block の以下の点を変更します。
def jdbcDriver = "org.postgresql:postgresql:42.2.5"
→def jdbcDriver = "org.postgresql:postgresql:42.2.9"
def domaVersion = "2.24.0"
→def domaVersion = "2.26.0"
def lombokVersion = "1.18.6"
→def lombokVersion = "1.18.10"
def powermockVersion = "2.0.0"
→def powermockVersion = "2.0.4"
implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2")
→implementation("com.integralblue:log4jdbc-spring-boot-starter:2.0.0")
implementation("com.univocity:univocity-parsers:2.8.1")
→implementation("com.univocity:univocity-parsers:2.8.4")
implementation("com.google.guava:guava:27.1-jre")
→implementation("com.google.guava:guava:28.1-jre")
implementation("org.flywaydb:flyway-core:5.2.4")
→implementation("org.flywaydb:flyway-core:6.1.3")
testImplementation("com.icegreen:greenmail:1.5.10")
→testImplementation("com.icegreen:greenmail:1.5.11")
testImplementation("org.assertj:assertj-core:3.12.2")
→testImplementation("org.assertj:assertj-core:3.14.0")
testImplementation("org.jsoup:jsoup:1.11.3")
→testImplementation("org.jsoup:jsoup:1.12.1")
testImplementation("cglib:cglib-nodep:3.2.10")
→testImplementation("cglib:cglib-nodep:3.3.0")
build タスク実行時に出るエラーを修正する
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、build タスクでエラーが出るので修正します。
There were failing tests. See the report at: file:///D:/project-springboot/ksbysample-webapp-lending/build/reports/tests/test/index.html
というメッセージが表示されたので、リンクをクリックして HTML をブラウザで表示させてみるとテストが2つ失敗していました。
失敗したログを表示させてみると、どちらも Content type expected:<application/json;charset=UTF-8> but was:<application/json>
という理由でした。
テストでは Content-Type に application/json;charset=UTF-8
がセットされてくる想定でいましたが、
@RestController
が付加されたクラス内のメソッドの @RequestMapping
に value 属性しか指定していないと application/json;charset=UTF-8
ではなく application/json
が返ってくるようになったようです。
org.springframework.http.MediaType クラスを見てみると、APPLICATION_JSON_UTF8、APPLICATION_JSON_UTF8_VALUE に @Deprecated
が付いていました。
Upgrading to Spring Framework 5.x - Upgrading to Version 5.2 にも Deprecation of MediaType.APPLICATION_JSON_UTF8 and MediaType.APPLICATION_PROBLEM_JSON_UTF8 の記述がありました。
よって、ksbysample.webapp.lending.webapi.library.LibraryControllerTest のテストクラス内で期待する Content-Type の文字列を application/json;charset=UTF-8
→ application/json
に変更することにします。
@Test void 正しい都道府県を指定した場合には図書館一覧が返る() throws Exception { mvc.noauth.perform(get("/webapi/library/getLibraryList?pref=東京都")) .andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$.errcode", is(0))) .andExpect(jsonPath("$.errmsg", is(""))) .andExpect(jsonPath("$.content[0].address", startsWith("東京都"))) .andExpect(jsonPath("$.content[?(@.formal=='国立国会図書館東京本館')]").exists()); } @Test void 間違った都道府県を指定した場合にはエラーが返る() throws Exception { mvc.noauth.perform(get("/webapi/library/getLibraryList?pref=東a京都")) .andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$.errcode", is(-2))) .andExpect(jsonPath("$.errmsg", is("都道府県名が正しくありません。"))) .andExpect(jsonPath("$.content", hasSize(0))); }
application/json;charset=UTF-8
の件を変更した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると無事 "BUILD SUCCESSFUL" のメッセージが出力されました。
spring-boot-starter-test が JUnit 5 ベースに切り替わったのですが、Project Tool Window で src/test/groovy/ksbysample、src/test/java/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample'' with Coverage」を選択してテストを実行してもテストは全て成功しました。
なんかあっさりバージョンアップできました。
メモ書き
- What's New in Spring Framework 5.x - What's New in Version 5.2 を見ていたら
Support for transaction control via Vavr Try return type on @Transactional methods.
という記述を見つけました。面白そうなので、今度試してみます。
履歴
2019/12/31
初版発行。