Upgrade to Java 17 / Spring Boot 3.2.5 with full dependency and source migration#559
Upgrade to Java 17 / Spring Boot 3.2.5 with full dependency and source migration#559devin-ai-integration[bot] wants to merge 8 commits intomasterfrom
Conversation
- 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 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:
|
Co-Authored-By: Scotty Andrade <scotty.andrade@cognition.ai>
| await commentsApi.deleteComment(slug, commentId); | ||
| setComments(comments.filter(comment => comment.id !== commentId)); |
There was a problem hiding this comment.
🔴 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
- Render:
comments = [A, B, C], both click handlers capture this - User clicks delete on A →
handleCommentDelete('A')awaits API - User clicks delete on B →
handleCommentDelete('B')awaits API (same closure, samecomments) - Delete A returns →
setComments([A,B,C].filter(!=A))→ state =[B, C] - Delete B returns →
setComments([A,B,C].filter(!=B))→ state =[A, C]← A reappears!
Fix: use functional updater setComments(prev => prev.filter(...))
| 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)); |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
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]); |
There was a problem hiding this comment.
🟡 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]).
| setComments([newComment, ...comments]); | |
| setComments(prev => [newComment, ...prev]); |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
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.
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:
Dependency upgrades:
Source code migrations:
javax.validation/javax.servlet→jakarta.*across all source filesWebSecurityConfigurerAdapter, converted toSecurityFilterChainbean with lambda DSL,antMatchers→requestMatchersCustomizeExceptionHandler:HttpStatus→HttpStatusCodeparameter for Spring 6 overridesetSubject()→subject(),parserBuilder()→parser(),parseClaimsJws()→parseSignedClaims(),getBody()→getPayload()graphql.relay.DefaultPageInfo→ generatedio.spring.graphql.types.PageInfowith builder APIDataFetcherExceptionHandler.onException()→handleException()returningCompletableFutureAll 68 existing tests pass locally.
Review & Testing Checklist for Human
jwt.secretinapplication.propertiesis ≥ 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 withUnsupportedKeyException. This is the highest-risk item.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.graphql.relay.DefaultPageInfo(positional constructor) toio.spring.graphql.types.PageInfo(builder withhasPreviousPage/hasNextPage/startCursor/endCursor) must match the GraphQL schema field names. Test paginated queries to confirm cursor-based pagination still works.onException→handleExceptionwithCompletableFuturereturn. 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.cryptoimports were intentionally left unchanged — these are core Java APIs, not Jakarta EE.SignatureAlgorithmenum was removed in jjwt 0.12.x; the JCA algorithm name"HmacSHA512"is now passed directly toSecretKeySpec.Link to Devin session: https://app.devin.ai/sessions/4addbf14b42f4d83b1ada891da336038
Requested by: @scottyandrade99