Skip to content

Commit af2cb20

Browse files
FM-496 - Upgrade to Spring Boot 4 (#4699)
## Summary This PR upgrades the API to spring boot 4. An 'non squashed' version of the PR is available for reference [here](#4666) ## Upgrade build.gradle for spring boot 4 ## Update jdbctemplate usage to reflect null response ## Use updated arguments for ContentCachingFilter ## Update Redis Config Namespace ## Add missing caching request wrapper to filter ## Force nullability on implementation of ConverterFactory Annotations like @nullable on a Java generic bound do not propagate into Kotlin’s type system for type parameters. Because the Converter interface has been updated to use this construct Kotlin can no longer infer nullabliity ``` public interface Converter<S, T extends @nullable Object> { T convert(S source); } ``` ## Use latest health interface ## Update common paging code for new interfaces ## replace SpykBean with MockkSpykBean This is required for mockk upgrade, see https://github.com/Ninja-Squad/springmockk/blob/master/README.md#migrating-to-version-5x ## Block first can now return null values ## queryParam is now nullable ## connection pool imports have changed ## Fix exception handling test exceptions ## Fix use of jsonPath.value ## Junit callbacks are no longer nullable ## ApplicationContextInitializer is no longer nullable ## Repository.save can no longer return null ## Fix exception handling unit ## Fix IT data source configuration ## Update spring jackson configuration This also removes the `serialization` configuration for jackson 3 because it is no longer supported the `spring.jackson` configuration now applies to jackson3, not jackson2. `SerializationFeature.WRITE_DATES_AS_TIMESTAMPS now known as DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS has been changed to false to serialize dates as ISO-8601 strings.` for this reason, we remove the `WRITE_DATES_AS_TIMESTAMPS` config for jackson 3 Jackson 2 configuration has been added as `spring.jackson2`, matching the pre spring-boot-4 upgrade configuration. ## Explicitly add and configure webtestclient ## Ensure JPA Attributes are serializable The JPA specification requires that the entity attributes are Serializable` ## Remove unused dependencies ## Handle Jackson3 Exception Handling Before the spring boot 4 upgrade Jackson 2 was used by Spring MVC, meaning our exception handling responding to unmarshalling issues deal with Jackson 2 classes. Spring Boot 4 uses jackson 3 for Spring MVC. This commit updates exception handling to work solely using Jackson3 for exception handling. It also simplifies how we use Spring’s `ProblemDetail` type, which is now correctly placing properties at the top level of the returned JSON instead of in a ‘properties’ attribute. This is mostly likely due to the upgrade to Jackson 3. This allows us to simplify the expected problem JSON in our integration tests, making the JSON match the returned values we saw from Zalando Problem before moving to Spring Problem ## Method Argument Mismatch now produces a problem Before upgrading to spring boot 4 `MethodArgumentTypeMismatchException` would return a generic error. It now returns a JSON Problem, which is preferred. ## Use Jackson 3 for API `Any` types As of Spring Boot 4 API marshalling is handled by Jackson 3. In many places JSON ‘blobs’ are represented in our API model with an ‘Any’ type: For example, in `ApprovedPremisesApplication` we have `val document: Any? = null,` This is populated as follows: 1. Pull JSON from the database as a String 2. Use Jackson to unmarshall this is into an internal Jackson Type 3. Set this value on the `Any` property 4. Spring Web MVC marshalls the `Any` value into JSON in the response This works fine when the version of Jacksonused in step 2 and 4 are the same. But if Step 2 uses Jackson2 and Step 4 uses Jackson3 (which is the configuration we have after upgrading to Spring 4), Jackson3 doesn’t recognise the Jackson2 native value in the `Any` property and falls back to default serialization, resulting in something like the following: `{"array":false,"bigDecimal":false,"bigInteger":false,"binary":false,"boolean":false,"containerNode":true,"double":false,"empty":true,"float":false,"floatingPointNumber":false,"int":false,"integralNumber":false,"long":false,"missingNode":false,"nodeType":"OBJECT","null":false,"number":false,"object":true,"pojo":false,"short":false,"textual":false,"valueNode":false} ` For this reason we’ve upgraded all places that use Jackson to populate the `Any` value to use Jackson 3. Other uses of Jackson will upgraded in subsequent commits ## Migrate some benign jackson2 usage to jackson3 ## Pin openapi starter version working version springdoc/springdoc-openapi#3256 significantly changed our generated schema, making it incompatible with the typescript generators and in some places it was incorrect. We're pinning version 3.0.2 until a new version is available reverting this change, as proposed by springdoc/springdoc-openapi#3276
2 parents e461694 + 5dd51a9 commit af2cb20

104 files changed

Lines changed: 396 additions & 493 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle.kts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
plugins {
2-
id("uk.gov.justice.hmpps.gradle-spring-boot") version "9.7.0"
3-
kotlin("plugin.spring") version "2.2.21"
4-
kotlin("plugin.jpa") version "2.2.21"
2+
id("uk.gov.justice.hmpps.gradle-spring-boot") version "10.2.3"
3+
kotlin("plugin.spring") version "2.3.20"
4+
kotlin("plugin.jpa") version "2.3.20"
55
id("dev.detekt") version "2.0.0-alpha.2"
66
id("org.owasp.dependencycheck") version "12.2.1"
77
}
@@ -21,29 +21,35 @@ configurations.matching { it.name == "detekt" }.all {
2121
}
2222

2323
dependencies {
24-
implementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter:1.8.2")
24+
implementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter:2.2.0")
25+
implementation("org.springframework.boot:spring-boot-starter-flyway")
2526
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
2627
implementation("org.springframework.boot:spring-boot-starter-webflux")
2728
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
2829
implementation("org.springframework.retry:spring-retry")
29-
implementation("io.hypersistence:hypersistence-utils-hibernate-63:3.10.3")
30-
// this should match the version of hibernate provided by spring
31-
implementation("org.hibernate:hibernate-spatial:6.6.4.Final")
30+
implementation("io.hypersistence:hypersistence-utils-hibernate-71:3.15.2")
31+
implementation("org.hibernate.orm:hibernate-spatial")
3232
implementation("org.hibernate.orm:hibernate-jcache")
33-
implementation("org.flywaydb:flyway-core")
3433
implementation("org.springframework.boot:spring-boot-starter-data-redis")
3534
implementation("org.springframework.boot:spring-boot-starter-cache")
3635
implementation("com.github.ben-manes.caffeine:caffeine")
3736
implementation("com.google.guava:guava:33.6.0-jre")
3837
implementation("org.postgresql:postgresql:42.7.10")
3938
implementation("org.javers:javers-core:7.11.0")
4039

41-
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.14")
40+
// https://github.com/springdoc/springdoc-openapi/pull/3256 significantly changed our
41+
// generated schema, making it incompatible with the typescript generators and in some
42+
// places it was incorrect. We're pinning version 3.0.2 until a new version is available
43+
// reverting this change, as proposed by https://github.com/springdoc/springdoc-openapi/pull/3276
44+
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.2")
45+
// this is a transitive dependency of uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-autoconfigure
46+
// so we need to force a different version
47+
implementation("org.springdoc:springdoc-openapi-starter-common:3.0.2")
4248

4349
implementation("org.springframework.boot:spring-boot-starter-security")
4450
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
4551
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
46-
implementation("io.sentry:sentry-spring-boot-starter-jakarta:8.33.0")
52+
implementation("io.sentry:sentry-spring-boot-4:8.40.0")
4753

4854
runtimeOnly("org.ehcache:ehcache")
4955
runtimeOnly("org.flywaydb:flyway-database-postgresql")
@@ -52,10 +58,6 @@ dependencies {
5258

5359
implementation("com.github.doyaaaaaken:kotlin-csv-jvm:1.10.0")
5460

55-
// This is purely to fix slack notifications as part of OWASP
56-
// once we have spring boot 4 we can remove this.
57-
implementation("org.webjars:swagger-ui:5.32.2")
58-
5961
implementation("org.jetbrains.kotlinx:dataframe:0.15.0") {
6062
exclude(group = "org.jetbrains.kotlinx", module = "dataframe-openapi")
6163
}
@@ -65,20 +67,21 @@ dependencies {
6567

6668
implementation("com.opencsv:opencsv:5.12.0")
6769

68-
implementation("net.javacrumbs.shedlock:shedlock-spring:6.9.2")
69-
implementation("net.javacrumbs.shedlock:shedlock-provider-redis-spring:6.9.2")
70+
implementation("net.javacrumbs.shedlock:shedlock-spring:7.7.0")
71+
implementation("net.javacrumbs.shedlock:shedlock-provider-redis-spring:7.7.0")
7072
implementation("org.jetbrains.kotlinx:dataframe-excel:0.15.0")
7173

7274
testImplementation("io.github.bluegroundltd:kfactory:1.0.0")
7375
testImplementation("io.mockk:mockk:1.14.9")
74-
testImplementation("com.github.tomakehurst:wiremock-standalone:3.0.1")
76+
testImplementation("org.wiremock.integrations:wiremock-spring-boot:4.2.1")
7577

76-
testImplementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter-test:1.8.2")
78+
testImplementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter-test:2.2.0")
7779

78-
testImplementation("com.ninja-squad:springmockk:4.0.2")
80+
testImplementation("com.ninja-squad:springmockk:5.0.1")
81+
testImplementation("org.springframework.boot:spring-boot-webtestclient")
7982
testImplementation("org.zalando:logbook-spring-boot-starter:4.0.3")
8083

81-
implementation("uk.gov.justice.service.hmpps:hmpps-sqs-spring-boot-starter:5.6.3")
84+
implementation("uk.gov.justice.service.hmpps:hmpps-sqs-spring-boot-starter:7.3.1")
8285

8386
implementation("uk.gov.service.notify:notifications-java-client:5.2.1-RELEASE")
8487
}

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas1/migration/Cas1CapacityPerformanceTestJob.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas1.migration
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import org.slf4j.LoggerFactory
54
import org.springframework.stereotype.Service
5+
import tools.jackson.databind.json.JsonMapper
66
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ApprovedPremisesRepository
77
import uk.gov.justice.digital.hmpps.approvedpremisesapi.migration.MigrationJob
88
import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.cas1.Cas1PremisesService

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas1/seed/Cas1RedactAssessmentDetailsSeedJob.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas1.seed
22

3-
import com.fasterxml.jackson.databind.JsonNode
4-
import com.fasterxml.jackson.databind.json.JsonMapper
53
import org.slf4j.LoggerFactory
64
import org.springframework.data.repository.findByIdOrNull
75
import org.springframework.stereotype.Component
6+
import tools.jackson.databind.JsonNode
7+
import tools.jackson.databind.json.JsonMapper
88
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.AssessmentRepository
99
import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.SeedJob
1010
import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.cas1.Cas1ApplicationTimelineNoteService

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2/controller/Cas2ApplicationsController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.controller
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import jakarta.transaction.Transactional
54
import org.springframework.http.ResponseEntity
65
import org.springframework.web.bind.annotation.GetMapping
@@ -9,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping
98
import org.springframework.web.bind.annotation.PutMapping
109
import org.springframework.web.bind.annotation.RequestBody
1110
import org.springframework.web.bind.annotation.RequestParam
11+
import tools.jackson.databind.json.JsonMapper
1212
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.AssignmentType
1313
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NewApplication
1414
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.SortDirection

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2/service/Cas2ApplicationService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.service
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import jakarta.transaction.Transactional
54
import org.springframework.beans.factory.annotation.Value
65
import org.springframework.stereotype.Service
6+
import tools.jackson.databind.json.JsonMapper
77
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEvent
88
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEventDetails
99
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEventDetailsSubmittedBy

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2/transformer/Cas2ApplicationsTransformer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.transformer
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import org.springframework.stereotype.Component
4+
import tools.jackson.databind.json.JsonMapper
55
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationOrigin
66
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationStatus
77
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ServiceType

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2/transformer/SubmissionsTransformer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.transformer
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import org.springframework.stereotype.Component
4+
import tools.jackson.databind.json.JsonMapper
55
import uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.jpa.entity.Cas2ApplicationEntity
66
import uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.jpa.entity.Cas2ApplicationSummaryEntity
77
import uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2.model.Cas2SubmittedApplication

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2v2/controller/Cas2v2ApplicationController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2v2.controller
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import jakarta.transaction.Transactional
54
import org.springframework.http.ResponseEntity
65
import org.springframework.web.bind.annotation.GetMapping
@@ -9,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping
98
import org.springframework.web.bind.annotation.PutMapping
109
import org.springframework.web.bind.annotation.RequestBody
1110
import org.springframework.web.bind.annotation.RequestParam
11+
import tools.jackson.databind.json.JsonMapper
1212
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Application
1313
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationOrigin
1414
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NewCas2v2Application

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2v2/service/Cas2v2ApplicationService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2v2.service
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import jakarta.transaction.Transactional
54
import org.springframework.beans.factory.annotation.Value
65
import org.springframework.data.jpa.domain.Specification
76
import org.springframework.stereotype.Service
7+
import tools.jackson.databind.json.JsonMapper
88
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEvent
99
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEventDetails
1010
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.events.cas2.model.Cas2ApplicationSubmittedEventDetailsSubmittedBy

src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/cas2v2/transformer/Cas2v2ApplicationsTransformer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package uk.gov.justice.digital.hmpps.approvedpremisesapi.cas2v2.transformer
22

3-
import com.fasterxml.jackson.databind.json.JsonMapper
43
import org.springframework.stereotype.Component
4+
import tools.jackson.databind.json.JsonMapper
55
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationOrigin
66
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationStatus
77
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas2v2Application

0 commit comments

Comments
 (0)