Skip to content

Upgrade to Java 17 / Spring Boot 3.2.5 with full dependency and source migration#559

Open
devin-ai-integration[bot] wants to merge 8 commits intomasterfrom
devin/1776602655-java17-springboot3-upgrade
Open

Upgrade to Java 17 / Spring Boot 3.2.5 with full dependency and source migration#559
devin-ai-integration[bot] wants to merge 8 commits intomasterfrom
devin/1776602655-java17-springboot3-upgrade

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot commented Apr 19, 2026

Summary

Upgrades the project from Java 11 / Spring Boot 2.6.3 to Java 17 / Spring Boot 3.2.5, including all transitive dependency updates and required source code migrations.

Build & tooling:

  • Java: 11 → 17, Gradle: 7.4 → 8.7, Spring Boot: 2.6.3 → 3.2.5
  • Spring Dependency Management: 1.0.11.RELEASE → 1.1.5
  • Spotless: 6.2.1 → 6.25.0, DGS codegen: 5.0.6 → 6.2.1
  • GitHub Actions: JDK 11 → 17, all actions v2 → v4

Dependency upgrades:

  • MyBatis Spring Boot Starter: 2.2.2 → 3.0.3
  • Netflix DGS runtime: 4.9.21 → 7.6.0
  • jjwt: 0.11.2 → 0.12.5
  • SQLite JDBC: 3.36.0.3 → 3.45.3.0
  • Rest Assured: 4.5.1 → 5.4.0

Source code migrations:

  • javax.validation/javax.servletjakarta.* across all source files
  • Spring Security: removed WebSecurityConfigurerAdapter, converted to SecurityFilterChain bean with lambda DSL, antMatchersrequestMatchers
  • CustomizeExceptionHandler: HttpStatusHttpStatusCode parameter for Spring 6 override
  • jjwt 0.12.x API: setSubject()subject(), parserBuilder()parser(), parseClaimsJws()parseSignedClaims(), getBody()getPayload()
  • DGS 7.x: graphql.relay.DefaultPageInfo → generated io.spring.graphql.types.PageInfo with builder API
  • DGS 7.x: DataFetcherExceptionHandler.onException()handleException() returning CompletableFuture
  • Test: longer secret key to satisfy jjwt 0.12.x HS512 minimum key length (64 bytes)

All 68 existing tests pass locally.

Review & Testing Checklist for Human

  • Verify jwt.secret in application.properties is ≥ 64 bytes. jjwt 0.12.x enforces minimum key sizes for HMAC algorithms. The test secret was updated but the production config was not touched by this PR — if the existing secret is shorter than 64 bytes, the app will crash at runtime with UnsupportedKeyException. This is the highest-risk item.
  • Verify Spring Security config equivalence. The CORS configuration source is now explicitly passed via cors -> cors.configurationSource(corsConfigurationSource()) instead of relying on auto-discovery. Confirm the security behavior (CORS, auth rules, session policy) is unchanged by testing authenticated and unauthenticated API calls.
  • Verify DGS PageInfo field mapping. The switch from graphql.relay.DefaultPageInfo (positional constructor) to io.spring.graphql.types.PageInfo (builder with hasPreviousPage/hasNextPage/startCursor/endCursor) must match the GraphQL schema field names. Test paginated queries to confirm cursor-based pagination still works.
  • Verify GraphQL exception handling. onExceptionhandleException with CompletableFuture return. Trigger validation errors and auth errors via GraphQL to confirm error responses are unchanged.

Recommended test plan: Run the app with ./gradlew bootRun, then exercise the REST API (create user, login, create/list articles with pagination) and the GraphQL endpoint (paginated queries, mutation with validation errors, unauthenticated access) to confirm end-to-end behavior.

Notes

  • javax.crypto imports were intentionally left unchanged — these are core Java APIs, not Jakarta EE.
  • The SignatureAlgorithm enum was removed in jjwt 0.12.x; the JCA algorithm name "HmacSHA512" is now passed directly to SecretKeySpec.

Link to Devin session: https://app.devin.ai/sessions/4addbf14b42f4d83b1ada891da336038
Requested by: @scottyandrade99


Open in Devin Review

gardnerjohnson-creator and others added 7 commits August 26, 2025 01:47
- Added a simple note confirming RealWorld API spec compliance
- This is a test change to verify PR workflow functionality

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
…st-dummy-change

Test: Add testing verification note to README
- Modern React 18 frontend with TypeScript and Tailwind CSS
- Complete RealWorld specification implementation
- User authentication with JWT token management
- Article management (create, view, edit, delete)
- Article feed with pagination
- User profiles and following functionality
- Comments system for articles
- Social features (favorites, following)
- Tag-based article categorization
- Responsive design with modern UI
- Full API integration with Spring Boot backend
- Development server on localhost:3000
- Production build support

Features implemented:
- User registration and login
- Article creation and editing with markdown support
- Global article feed
- User profiles and social following
- Comment system
- Article favoriting
- Tag filtering
- JWT authentication integration
- Error handling and validation
- Modern responsive UI design

The frontend successfully demonstrates all backend API functionality
through a visual web interface, replacing raw JSON responses with
a complete social blogging platform user experience.

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
- Remove node_modules from git tracking and add to .gitignore
- Configure environment variables for API base URL using VITE_API_BASE_URL
- Add TypeScript definitions for Vite environment variables
- Remove unused 'User' import to fix TypeScript error

Addresses the 5 critical issues identified in PR review:
1. ✅ Remove node_modules from git (added to .gitignore)
2. 🔄 Test complete user journey (next step)
3. ✅ Configure environment variables (VITE_API_BASE_URL)
4. 🔄 Verify CORS configuration (next step)
5. 🔄 Test authentication flow thoroughly (next step)

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
…d-react-frontend

Add React Frontend Application for RealWorld API
…e migration

- Java: 11 → 17 (sourceCompatibility/targetCompatibility)
- Spring Boot: 2.6.3 → 3.2.5
- Spring Dependency Management: 1.0.11.RELEASE → 1.1.5
- Gradle: 7.4 → 8.7
- MyBatis Spring Boot Starter: 2.2.2 → 3.0.3
- Netflix DGS: 4.9.21 → 7.6.0, codegen 5.0.6 → 6.2.1
- jjwt: 0.11.2 → 0.12.5
- SQLite JDBC: 3.36.0.3 → 3.45.3.0
- Rest Assured: 4.5.1 → 5.4.0
- Spotless: 6.2.1 → 6.25.0
- GitHub Actions: JDK 11 → 17, actions v2 → v4

Source code migration:
- javax.validation → jakarta.validation
- javax.servlet → jakarta.servlet
- Spring Security: WebSecurityConfigurerAdapter → SecurityFilterChain bean
- Spring Security: authorizeRequests/antMatchers → authorizeHttpRequests/requestMatchers
- Spring Security: chained .and() DSL → lambda DSL
- ResponseEntityExceptionHandler: HttpStatus → HttpStatusCode parameter
- jjwt 0.12.x API: setSubject→subject, setExpiration→expiration,
  parserBuilder→parser, parseClaimsJws→parseSignedClaims, getBody→getPayload
- DGS 7.x: graphql.relay.PageInfo → generated PageInfo type
- DGS 7.x: onException → handleException (CompletableFuture return)
- DefaultJwtServiceTest: use longer secret key for HS512 minimum requirement

Co-Authored-By: Scotty Andrade <scotty.andrade@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown
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: Scotty Andrade <scotty.andrade@cognition.ai>
Copy link
Copy Markdown
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 2 potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment on lines +109 to +110
await commentsApi.deleteComment(slug, commentId);
setComments(comments.filter(comment => comment.id !== commentId));
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔴 Stale closure in comment handlers causes deleted comments to reappear

handleCommentDelete and handleCommentSubmit capture the comments array from the render-time closure instead of using React's functional state updater pattern. When a user rapidly deletes two comments (e.g., comment A then comment B), both handlers capture the same stale comments = [A, B, C]. When the first API call completes, state becomes [B, C]. When the second completes, it filters the stale [A, B, C] producing [A, C] — comment A reappears in the UI even though it was deleted on the server. The same issue affects handleCommentSubmit when combined with a delete before re-render: the newly added comment can be lost.

Race condition trace for handleCommentDelete
  1. Render: comments = [A, B, C], both click handlers capture this
  2. User clicks delete on A → handleCommentDelete('A') awaits API
  3. User clicks delete on B → handleCommentDelete('B') awaits API (same closure, same comments)
  4. Delete A returns → setComments([A,B,C].filter(!=A)) → state = [B, C]
  5. Delete B returns → setComments([A,B,C].filter(!=B)) → state = [A, C] ← A reappears!

Fix: use functional updater setComments(prev => prev.filter(...))

Suggested change
await commentsApi.deleteComment(slug, commentId);
setComments(comments.filter(comment => comment.id !== commentId));
await commentsApi.deleteComment(slug, commentId);
setComments(prev => prev.filter(comment => comment.id !== commentId));
Open in Devin Review

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This file (frontend/src/pages/ArticleView.tsx) is not part of the Java 17 / Spring Boot 3 upgrade changes in this PR. It appears in the diff because it exists on the upstream fork's master branch but not on the COG-GTM master branch — it was added by a separate React frontend PR. The stale closure observation is valid but out of scope for this PR.

if (!slug) return;

const newComment = await commentsApi.addComment(slug, body);
setComments([newComment, ...comments]);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🟡 Stale closure in handleCommentSubmit can lose newly added comments

handleCommentSubmit uses setComments([newComment, ...comments]) where comments is captured from the closure at render time. If a delete operation is in-flight concurrently (user submits a comment then quickly deletes another before re-render), the delete handler's stale setComments call will overwrite the state and lose the newly submitted comment. Should use the functional updater form: setComments(prev => [newComment, ...prev]).

Suggested change
setComments([newComment, ...comments]);
setComments(prev => [newComment, ...prev]);
Open in Devin Review

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Same as above — this file is not part of this PR's changes. It's pre-existing code from the upstream fork's master branch.

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.

2 participants