Skip to content

Comments

Migrate build.gradle from Java 11 to Java 17#354

Open
devin-ai-integration[bot] wants to merge 2 commits intomasterfrom
devin/1771271778-java-17-migration
Open

Migrate build.gradle from Java 11 to Java 17#354
devin-ai-integration[bot] wants to merge 2 commits intomasterfrom
devin/1771271778-java-17-migration

Conversation

@devin-ai-integration
Copy link

@devin-ai-integration devin-ai-integration bot commented Feb 16, 2026

Migrate build.gradle from Java 11 to Java 17

Summary

Upgrades the project from Java 11 to Java 17 by bumping sourceCompatibility/targetCompatibility and upgrading dependencies for Java 17 compatibility. Also updates the CI workflow to build with JDK 17.

Dependency changes:

Dependency Before After
Spring Boot 2.6.3 2.7.18
Spring Dependency Management 1.0.11 1.1.6
Netflix DGS 4.9.21 5.5.1 (via platform BOM)
DGS Codegen plugin 5.0.6 5.6.9
JJWT 0.11.2 0.12.6
MyBatis Spring Boot Starter 2.2.2 2.3.2
SQLite JDBC 3.36.0.3 3.42.0.1
joda-time 2.10.13 2.12.7
Spotless 6.2.1 6.25.0
Rest Assured 4.5.1 4.5.1 (unchanged — DGS BOM conflicts with 5.x)

Code changes:

  • DefaultJwtService.java: Migrated to JJWT 0.12.x API (subject(), expiration(), parseSignedClaims(), getPayload()). Replaced SecretKeySpec + hardcoded HS512 with Keys.hmacShaKeyFor() which auto-selects HMAC algorithm based on key size.
  • ArticleDatafetcher.java / CommentDatafetcher.java: Replaced graphql.relay.DefaultPageInfo with DGS-generated io.spring.graphql.types.PageInfo to fix type incompatibility in DGS 5.x.
  • Added dependencyManagement block importing the DGS platform BOM to override Spring Boot 2.7's graphql-java 18.x with 19.x (required by DGS 5.5.1's federation library).
  • .github/workflows/gradle.yml: Updated CI from JDK 11 to JDK 17.

Review & Testing Checklist for Human

  • JJWT signing algorithm change (HIGH RISK): Keys.hmacShaKeyFor() auto-selects HS256/HS384/HS512 based on key byte length instead of always using HS512. Existing tokens signed with HS512 will fail to verify if the new code selects a different algorithm due to a shorter key. Verify all environments have a jwt.secret of ≥64 bytes to get HS512. The default secret in application.properties is 88 chars (fine), but check staging/production.
  • GraphQL PageInfo field mapping: Verify that the DGS-generated PageInfo builder fields (startCursor, endCursor, hasPreviousPage, hasNextPage) match the GraphQL schema expectations. Test cursor-based pagination queries end-to-end (e.g., articles feed with first/after arguments).
  • DGS graphql-java override: The DGS BOM forces graphql-java 18.x → 19.x. Spot-check GraphQL queries/mutations for any behavioral changes not covered by unit tests.
  • Run ./gradlew bootBuildImage --imageName spring-boot-realworld-example-app to verify Docker image builds successfully with Java 17.

Suggested manual test plan:

  1. Start app with ./gradlew bootRun and verify it starts on Java 17
  2. Test /tags endpoint: curl http://localhost:8080/tags
  3. Test user registration/login flow (JWT token generation/verification)
  4. Test GraphQL cursor pagination queries (articles feed with first: 10, after: "cursor")

Notes

  • All 68 unit tests pass locally and in CI.
  • CI build checks pass. Snyk security check fails (non-required, external) — likely flagging a pre-existing or newly introduced vulnerability in a dependency upgrade. Worth investigating separately.
  • Rest Assured was kept at 4.5.1 (not upgraded to 5.x) due to version conflicts with DGS BOM's transitive dependencies. 4.5.1 is Java 17 compatible.
  • Spring Boot 2.7.x was chosen over 3.x to avoid the massive javax → jakarta namespace migration. Note: 2.7.x reaches EOL in Nov 2025.
  • Local testing confirmed: ./gradlew bootRun starts successfully, /tags endpoint responds with {"tags":[]}.

Link to Devin run: https://app.devin.ai/sessions/be1f0b06a6bd4bc280becc8a7302fc31
Requested by: @shayanshafii


Open with Devin

- Update sourceCompatibility/targetCompatibility to 17
- Upgrade Spring Boot 2.6.3 -> 2.7.18
- Upgrade Spring Dependency Management 1.0.11 -> 1.1.6
- Upgrade Netflix DGS 4.9.21 -> 5.5.1 with platform BOM
- Upgrade DGS Codegen plugin 5.0.6 -> 5.6.9
- Upgrade JJWT 0.11.2 -> 0.12.6 (new API: subject/expiration/parseSignedClaims)
- Upgrade MyBatis Spring Boot Starter 2.2.2 -> 2.3.2
- Upgrade SQLite JDBC 3.36.0.3 -> 3.42.0.1
- Upgrade joda-time 2.10.13 -> 2.12.7
- Upgrade Spotless 6.2.1 -> 6.25.0
- Fix DGS PageInfo type compatibility in ArticleDatafetcher and CommentDatafetcher
- Use Keys.hmacShaKeyFor() for JJWT 0.12.x key handling

Co-Authored-By: shayan@cognition.ai <shayan@cognition.ai>
@devin-ai-integration
Copy link
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Co-Authored-By: shayan@cognition.ai <shayan@cognition.ai>
Copy link
Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

this.sessionTime = sessionTime;
signatureAlgorithm = SignatureAlgorithm.HS512;
this.signingKey = new SecretKeySpec(secret.getBytes(), signatureAlgorithm.getJcaName());
this.signingKey = Keys.hmacShaKeyFor(secret.getBytes());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Keys.hmacShaKeyFor() silently changes signing algorithm for secrets shorter than 64 bytes

The migration from explicit SignatureAlgorithm.HS512 + SecretKeySpec to Keys.hmacShaKeyFor() introduces an implicit algorithm selection based on key byte length. Any deployment with a jwt.secret between 32-63 bytes will silently switch from HS512 to HS256/HS384, making all previously-issued JWT tokens unverifiable.

Detailed Explanation

The old code at DefaultJwtService.java:27-28 (before this PR) always used HS512:

signatureAlgorithm = SignatureAlgorithm.HS512;
this.signingKey = new SecretKeySpec(secret.getBytes(), signatureAlgorithm.getJcaName());

The new code at DefaultJwtService.java:25 uses Keys.hmacShaKeyFor() which auto-selects the algorithm:

  • 32-47 bytes → HS256
  • 48-63 bytes → HS384
  • ≥64 bytes → HS512

The default secret in application.properties is 86 bytes (safe, maps to HS512). However, a concrete example exists in the test at DefaultJwtServiceTest.java:16:

jwtService = new DefaultJwtService("123123123123123123123123123123123123123123123123123123123123", 3600);

This secret is 60 bytes, so the test now uses HS384 instead of HS512. The test still passes because should_get_null_with_expired_jwt fails for algorithm mismatch rather than expiration — masking the behavioral change.

Impact: Any production environment with a jwt.secret shorter than 64 bytes will have all existing user sessions invalidated after deployment, as tokens signed with HS512 cannot be verified with HS384/HS256. Users would need to re-authenticate.

Suggested change
this.signingKey = Keys.hmacShaKeyFor(secret.getBytes());
this.signingKey = Keys.hmacShaKeyFor(java.util.Arrays.copyOf(secret.getBytes(), 64));
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant