Upgrade to Spring Boot 3.4.5 and Java 21#4
Conversation
- Bump Spring Boot parent from 2.7.18 to 3.4.5 - Upgrade Java target from 11 to 21 - Switch springdoc to springdoc-openapi-starter-webmvc-ui 2.8.6 - Upgrade jjwt from 0.11.5 to 0.12.6 and update API usage (claims/subject/issuedAt/expiration, parser().verifyWith().parseSignedClaims()) - Add flyway-database-postgresql module (required in Flyway 10.x for Postgres) - Bump maven-compiler-plugin to 3.13.0 - Migrate javax.persistence/validation/servlet -> jakarta.* - Rewrite SecurityConfig to lambda DSL (cors/csrf/sessionManagement/authorizeHttpRequests, requestMatchers, Customizer) - Drop explicit Hibernate dialect in application*.yml (Hibernate 6 auto-detects) - Bump CI Java version to 21
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
🟡 Redis property namespace not updated for Spring Boot 3
In Spring Boot 3.x, Redis configuration properties moved from spring.redis.* to spring.data.redis.*. The application.yml still uses the old namespace (spring.redis.host, spring.redis.port at lines 24-26), which Spring Boot 3.4.5 will silently ignore. Redis auto-configuration will fall back to defaults. Currently this has no visible impact because (a) the configured values match the defaults (localhost:6379) and (b) dev/test profiles exclude Redis auto-configuration entirely — but the configuration is effectively dead and would silently fail if someone changes these values expecting them to take effect.
(Refers to lines 24-26)
Was this helpful? React with 👍 or 👎 to provide feedback.
| .subject(subject) | ||
| .issuedAt(now) | ||
| .expiration(expiryDate) | ||
| .signWith(getSigningKey()) |
There was a problem hiding this comment.
🔴 JWT signing algorithm silently downgraded from HS512 to HS256
The migration from jjwt 0.11.5 to 0.12.6 changed .signWith(getSigningKey(), SignatureAlgorithm.HS512) to .signWith(getSigningKey()). In jjwt 0.12.x, the single-argument signWith(Key) auto-selects the HMAC algorithm based on key length: HS256 for 256-383 bit keys, HS384 for 384-511 bit keys, HS512 for ≥512 bit keys. The default secret dev-secret-key-change-in-production is 35 bytes (280 bits), and the test secret aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is 34 bytes (272 bits) — both fall in the HS256 range. This silently downgrades the signing algorithm from HS512 to HS256. Additionally, any existing tokens signed with HS512 by the old code will have "alg":"HS512" in their header, while new tokens will have "alg":"HS256" — a mixed-algorithm state after deployment.
Correct jjwt 0.12.x migration for explicit HS512
The explicit algorithm form in 0.12.x is signWith(key, Jwts.SIG.HS512), but this requires the secret key to be at least 64 bytes. If keeping the shorter secrets, the downgrade to HS256 should be an intentional, documented decision.
Prompt for agents
In JwtTokenProvider.java line 52, the migration changed .signWith(getSigningKey(), SignatureAlgorithm.HS512) to .signWith(getSigningKey()), which auto-selects the algorithm based on key size. For the default secrets (34-35 bytes), this results in HS256 instead of HS512.
To fix this properly:
1. If you want to keep HS512: change to .signWith(getSigningKey(), Jwts.SIG.HS512) AND ensure the JWT secret is at least 64 bytes (512 bits) in all environments (application.yml medchart.security.jwt.secret, and application-test.yml).
2. If HS256 is acceptable: add a code comment explicitly noting the algorithm change from HS512, and document this as a known behavioral change of the migration.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Upgrades the backend from Spring Boot 2.7.18 / Java 11 to Spring Boot 3.4.5 / Java 21 and migrates the breaking API changes that ride along with it.
pom.xml
spring-boot-starter-parent3.4.5java.version/ compiler source & target → 21springdoc-openapi-ui1.7.0 →springdoc-openapi-starter-webmvc-ui2.8.6jjwt-*0.11.5 → 0.12.6flyway-database-postgresql(required by Flyway 10+ to run against Postgres)maven-compiler-plugin3.11.0 → 3.13.0Code
javax.persistence,javax.validation, andjavax.servletimports to theirjakarta.*equivalents across 33 files (keptjavax.cryptointact — it's a JDK package, not Jakarta EE).SecurityConfigrewritten to the Spring Security 6 lambda DSL (cors(Customizer.withDefaults()),csrf(csrf -> csrf.disable()),sessionManagement(...),authorizeHttpRequests(...),requestMatchers(...)).JwtTokenProviderupdated to the jjwt 0.12.x fluent API (claims/subject/issuedAt/expiration,Jwts.parser().verifyWith(...).parseSignedClaims(...).getPayload()).hibernate.dialectfromapplication.yml,application-dev.yml, andapplication-test.yml(Hibernate 6 auto-detects).CI
.github/workflows/ci.ymlbumped tojava-version: '21'.Local
mvn clean compilesucceeds on JDK 21. Tests have not been run locally yet; relying on CI (mvn test,mvn verify) for runtime validation.Review & Testing Checklist for Human
signWith(key, SignatureAlgorithm.HS512)was replaced withsignWith(key), which in jjwt 0.12.x auto-selects the algorithm based on the key's bit length. The default dev secret (dev-secret-key-change-in-production, 36 bytes) will now select HS256, not HS512. Any existing HS512 tokens in flight will fail verification after deploy, and downstream consumers that assert on thealgheader will see a different value. If HS512 is required, either restore the explicit algorithm or ensureJWT_SECRETis ≥ 64 bytes in every environment./swagger-ui.htmlto/swagger-ui/index.html(and the API docs default changed). Verify any bookmarks, reverse-proxy rules, frontend links, or healthchecks that point at the old URLs.flyway-database-postgresqlmodule is required at runtime; without it Flyway fails to start against Postgres. Confirm migrations insrc/main/resources/db/migration/V1..V3still apply cleanly against the Neon dev DB (thedevprofile usesbaseline-on-migrate: true).mvn spring-boot:run -Dspring-boot.run.profiles=dev, hit/api/actuator/health, log in viaAuthControllerto verify JWT issuance + validation end-to-end, and exercise a patient read (GET /api/v1/patients/{id}) to confirm JPA entities still map correctly under Jakarta Persistence / Hibernate 6.application-test.ymlno longer setshibernate.dialect; Hibernate 6 should auto-detect H2 from the driver, but please confirmmvn testpasses in CI and that no test relies on the removed dialect property.Notes
SecurityConfigstill permits all requests (requestMatchers("/**").permitAll()) — unchanged from before the upgrade, but worth a second look now that the DSL has been rewritten.AvoidStarImportwarnings on files touched by thejavax → jakartarename; these were warnings before the change (violationSeverity=errorfilters them out) and the build still reports 0 violations.@Builderwarnings onUser.javaand MapStructUnmapped target propertieswarnings onPatientMapperare pre-existing and not introduced here.Link to Devin session: https://app.devin.ai/sessions/80d0566784c642d49d7d97e1f88c9b49
Requested by: @clivingston-cognition