Upgrade from Java 11 to Java 21 with Spring Boot 3.2.5#605
Upgrade from Java 11 to Java 21 with Spring Boot 3.2.5#605devin-ai-integration[bot] wants to merge 8 commits into
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
- Update sourceCompatibility/targetCompatibility to Java 21 - Upgrade Spring Boot from 2.6.3 to 3.2.5 - Upgrade Gradle wrapper from 7.4 to 8.7 - Migrate javax.* to jakarta.* namespace across all source files - Rewrite WebSecurityConfig for Spring Security 6 (SecurityFilterChain) - Update CustomizeExceptionHandler for Spring Boot 3.x API - Upgrade DGS GraphQL from 4.x to 8.7.1 (spring-graphql integration) - Upgrade jjwt from 0.11.2 to 0.12.5 with new API - Upgrade MyBatis Spring Boot starter from 2.2.2 to 3.0.3 - Upgrade Rest Assured from 4.5.1 to 5.4.0 - Upgrade SQLite JDBC, Joda-Time, Spotless, and other dependencies - Fix GraphQL PageInfo type compatibility - Fix JWT key size validation for HS512 - All 68 tests pass Co-Authored-By: david.bean <david.bean@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:
|
…v4, actions/cache@v4 Co-Authored-By: david.bean <david.bean@cognition.ai>
| useEffect(() => { | ||
| loadArticles(); | ||
| }, [activeTab, selectedTag]); |
There was a problem hiding this comment.
🔴 Missing user dependency in loadArticles useEffect causes stale feed articles after logout
The useEffect at frontend/src/pages/Home.tsx:20-22 depends on [activeTab, selectedTag], but the loadArticles function it calls also reads user (line 37). When a user logs out while on the Home page with the "Your Feed" tab active, user becomes null but the effect doesn't re-run because its dependencies didn't change. This leaves the authenticated user's feed articles visible after logout, with no active tab shown (the "Your Feed" button disappears but activeTab state remains 'feed'). The stale data persists until the user manually clicks "Global Feed".
| useEffect(() => { | |
| loadArticles(); | |
| }, [activeTab, selectedTag]); | |
| useEffect(() => { | |
| loadArticles(); | |
| }, [activeTab, selectedTag, user]); |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
These frontend files (frontend/src/pages/Home.tsx, frontend/src/pages/ArticleView.tsx) are not part of this PR's changes — this PR only modifies backend Java files, build config, and CI workflow. These files were added in a previous PR merged to master and are outside the scope of this upgrade.
| const handleCommentDelete = async (commentId: string) => { | ||
| if (!slug) return; | ||
|
|
||
| await commentsApi.deleteComment(slug, commentId); | ||
| setComments(comments.filter(comment => comment.id !== commentId)); | ||
| }; |
There was a problem hiding this comment.
🟡 Stale closure in handleCommentDelete causes deleted comments to reappear on rapid sequential deletions
Both handleCommentSubmit (line 103) and handleCommentDelete (line 110) capture comments from the render-time closure instead of using React's functional state updater. If a user deletes comment A and then quickly deletes comment B before the component re-renders from the first deletion, both deletions filter against the same original comments snapshot. When deletion B's setComments runs, it overwrites deletion A's state update, effectively re-adding comment A to the list.
| const handleCommentDelete = async (commentId: string) => { | |
| if (!slug) return; | |
| await commentsApi.deleteComment(slug, commentId); | |
| setComments(comments.filter(comment => comment.id !== commentId)); | |
| }; | |
| const handleCommentDelete = async (commentId: string) => { | |
| if (!slug) return; | |
| 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 is not part of this PR's diff — this PR only touches backend Java files, build.gradle, Gradle wrapper, and CI workflow. The frontend code was added in a previous PR and is outside the scope of this Java 21 / Spring Boot 3.x upgrade.
Summary
Full upgrade from Java 11 / Spring Boot 2.6.3 to Java 21 / Spring Boot 3.2.5. All 68 existing tests pass locally. Application starts and serves API requests.
Changes
Build & Tooling:
sourceCompatibility/targetCompatibility→212.6.3→3.2.5, dependency-management1.0.11→1.1.47.4→8.76.2.1→6.25.0(scoped tosrc/to fix Gradle 8 task dependency issue)CI Workflow (.github/workflows/gradle.yml):
11→21actions/checkout@v2→v4,actions/setup-java@v2→v4,actions/cache@v2→v4Namespace Migration (javax → jakarta):
javax.validation.*→jakarta.validation.*javax.servlet.*→jakarta.servlet.*javax.crypto.*left as-is (JDK package, not Jakarta EE)Spring Security 6 Migration:
WebSecurityConfigurerAdapterwithSecurityFilterChainbeanauthorizeRequests()/antMatchers()→authorizeHttpRequests()/requestMatchers()DGS GraphQL:
4.9.21to8.7.1with Spring for GraphQL integrationgraphql-dgs-spring-boot-starter→graphql-dgs-spring-graphql-starter5.0.6→6.2.1PageInfotype:graphql.relay.DefaultPageInfo→io.spring.graphql.types.PageInfoDataFetcherExceptionHandler.handleException()to returnCompletableFutureJWT (jjwt):
0.11.2→0.12.5setSubject()→subject(),setExpiration()→expiration(),parserBuilder()→parser(),parseClaimsJws()→parseSignedClaims(),getBody()→getPayload()Jwts.SIG.HS512tosignWith()(required by 0.12.x key validation)Other Dependency Upgrades:
2.2.2→3.0.34.5.1→5.4.03.36.0.3→3.45.3.02.10.13→2.12.7Spring Boot 3.x Config:
ResponseEntityExceptionHandler.handleMethodArgumentNotValidsignature:HttpStatus→HttpStatusCodespring.graphql.schema.locationsandspring.graphql.schema.inspection.enabled=falseReview & Testing Checklist for Human
./gradlew clean buildwith Java 21 to confirm all 68 tests pass./gradlew bootRunand verify the app starts on port 8080POST /users,POST /users/login,GET /articles,GET /tags/graphqlwith a sample queryNotes
application.propertiesis 86 bytes, which exceeds the 64-byte minimum for HS512Link to Devin session: https://app.devin.ai/sessions/555bc4bb71b841df994923527e0bb024
Requested by: @davidbean-hash
Devin Review