Skip to content

Upgrade from Java 11 to Java 21 with Spring Boot 3.2.5#605

Open
devin-ai-integration[bot] wants to merge 8 commits into
masterfrom
devin/1779216519-java-21-spring-boot-3-upgrade
Open

Upgrade from Java 11 to Java 21 with Spring Boot 3.2.5#605
devin-ai-integration[bot] wants to merge 8 commits into
masterfrom
devin/1779216519-java-21-spring-boot-3-upgrade

Conversation

@devin-ai-integration
Copy link
Copy Markdown

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

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 / targetCompatibility21
  • Spring Boot 2.6.33.2.5, dependency-management 1.0.111.1.4
  • Gradle wrapper 7.48.7
  • Spotless 6.2.16.25.0 (scoped to src/ to fix Gradle 8 task dependency issue)

CI Workflow (.github/workflows/gradle.yml):

  • Java 1121
  • actions/checkout@v2v4, actions/setup-java@v2v4, actions/cache@v2v4

Namespace Migration (javax → jakarta):

  • All javax.validation.*jakarta.validation.*
  • All javax.servlet.*jakarta.servlet.*
  • javax.crypto.* left as-is (JDK package, not Jakarta EE)

Spring Security 6 Migration:

  • Replaced WebSecurityConfigurerAdapter with SecurityFilterChain bean
  • authorizeRequests() / antMatchers()authorizeHttpRequests() / requestMatchers()
  • Migrated to lambda-style DSL for CSRF, CORS, session management

DGS GraphQL:

  • Upgraded from DGS 4.9.21 to 8.7.1 with Spring for GraphQL integration
  • graphql-dgs-spring-boot-startergraphql-dgs-spring-graphql-starter
  • DGS codegen 5.0.66.2.1
  • Fixed PageInfo type: graphql.relay.DefaultPageInfoio.spring.graphql.types.PageInfo
  • Updated DataFetcherExceptionHandler.handleException() to return CompletableFuture

JWT (jjwt):

  • Upgraded from 0.11.20.12.5
  • Replaced deprecated API: setSubject()subject(), setExpiration()expiration(), parserBuilder()parser(), parseClaimsJws()parseSignedClaims(), getBody()getPayload()
  • Added explicit Jwts.SIG.HS512 to signWith() (required by 0.12.x key validation)

Other Dependency Upgrades:

  • MyBatis Spring Boot 2.2.23.0.3
  • Rest Assured 4.5.15.4.0
  • SQLite JDBC 3.36.0.33.45.3.0
  • Joda-Time 2.10.132.12.7

Spring Boot 3.x Config:

  • ResponseEntityExceptionHandler.handleMethodArgumentNotValid signature: HttpStatusHttpStatusCode
  • Added spring.graphql.schema.locations and spring.graphql.schema.inspection.enabled=false

Review & Testing Checklist for Human

  • Run ./gradlew clean build with Java 21 to confirm all 68 tests pass
  • Run ./gradlew bootRun and verify the app starts on port 8080
  • Test REST API endpoints: POST /users, POST /users/login, GET /articles, GET /tags
  • Test GraphQL endpoint at /graphql with a sample query

Notes

  • The Snyk security check failure is pre-existing and unrelated to this upgrade
  • The JWT secret in application.properties is 86 bytes, which exceeds the 64-byte minimum for HS512
  • The test JWT secret was extended from 60 to 78 bytes to meet the HS512 minimum key length requirement in jjwt 0.12.x
  • Verified locally: app starts on Java 21, user registration API works, all 68 tests pass

Link to Devin session: https://app.devin.ai/sessions/555bc4bb71b841df994923527e0bb024
Requested by: @davidbean-hash


Devin Review

Status Commit
⚪ Not started

Run Devin Review

💡 Connect your GitHub account to enable automatic code reviews.

Open in Devin Review (Staging)
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
- 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-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

…v4, actions/cache@v4

Co-Authored-By: david.bean <david.bean@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 +20 to +22
useEffect(() => {
loadArticles();
}, [activeTab, selectedTag]);
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.

🔴 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".

Suggested change
useEffect(() => {
loadArticles();
}, [activeTab, selectedTag]);
useEffect(() => {
loadArticles();
}, [activeTab, selectedTag, user]);
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.

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.

Comment on lines +106 to +111
const handleCommentDelete = async (commentId: string) => {
if (!slug) return;

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 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.

Suggested change
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));
};
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 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.

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