Skip to content

Migrate UserFront from Java 8 + Spring Boot 1.5.4 to Java 17 + Spring Boot 3.1.5#7

Open
devin-ai-integration[bot] wants to merge 5 commits into
masterfrom
devin/1778831776-spring-boot-3-java-17-migration
Open

Migrate UserFront from Java 8 + Spring Boot 1.5.4 to Java 17 + Spring Boot 3.1.5#7
devin-ai-integration[bot] wants to merge 5 commits into
masterfrom
devin/1778831776-spring-boot-3-java-17-migration

Conversation

@devin-ai-integration
Copy link
Copy Markdown

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

Summary

Comprehensive migration of the UserFront/ module from Java 8 + Spring Boot 1.5.4 to Java 17 + Spring Boot 3.1.5, covering all 8 migration sections plus runtime fixes discovered during testing:

  1. pom.xml: Updated spring-boot-starter-parent to 3.1.5, java.version to 17, renamed mysql-connector-javacom.mysql:mysql-connector-j, added H2 for local testing
  2. javax → jakarta: Migrated all javax.persistence.* and javax.servlet.* imports to jakarta.* across 10 files
  3. SecurityConfig: Removed WebSecurityConfigurerAdapter, replaced with @Bean SecurityFilterChain. Used explicit AntPathRequestMatcher instances to avoid multi-servlet ambiguity. Replaced @EnableGlobalMethodSecurity with @EnableMethodSecurity. Set defaultSuccessUrl("/userFront", true) to fix login redirect in Spring Security 6.x.
  4. application.properties: Removed deprecated testWhileIdle/validationQuery, updated Hibernate dialect to MySQLDialect
  5. GenerationType: Changed all GenerationType.AUTOGenerationType.IDENTITY in 8 entity classes
  6. Java 17 features: Applied var local variable type inference across controllers/services/domain
  7. Spring Boot 3.x breaking changes:
    • findOne()findById().orElse(null) with null guard in confirmAppointment()
    • JUnit 4 → JUnit 5
    • @Lazy to break circular bean dependencies (prohibited by default in Spring Boot 3.x)
    • @Table(name = "users") on User entity to avoid SQL reserved keyword conflict
    • data.sql seed file for H2 role initialization
  8. Build verification: mvn clean compile passes; app starts and runs E2E with H2 profile

28 files changed.

Review & Testing Checklist for Human

  • Start the app with mvn spring-boot:run -Dspring-boot.run.profiles=h2 and verify it boots without errors
  • Navigate to /signup, create a user, then login at /index — verifies SecurityFilterChain + BCrypt + UserDetailsService + login redirect
  • Deposit funds and verify balance updates on /userFront dashboard — verifies JPA entities with GenerationType.IDENTITY and @lazy dependency resolution
  • Test with MySQL (mvn spring-boot:run without H2 profile) against an onlinebanking database to verify production config

Notes

  • The circular dependency between UserServiceImplAccountServiceImplTransactionServiceImpl was hidden in Spring Boot 1.5.x (which allowed circular refs by default). Fixed with @Lazy injection.
  • The User entity needed @Table(name = "users") because user is a reserved SQL keyword in H2 and several other databases.
  • The SecurityConfig.requestMatchers() needed explicit AntPathRequestMatcher instances because H2 console registers a second servlet, causing Spring Security's auto-detection to fail.
  • Login redirect required defaultSuccessUrl("/userFront", true) — without alwaysUse=true, Spring Security 6.x follows stale saved requests instead of the configured URL.
  • H2 profile requires data.sql to seed ROLE_USER and ROLE_ADMIN since the in-memory database starts empty.

Link to Devin session: https://app.devin.ai/sessions/b0736040b00144189c0396a99781fea9
Requested by: @stephencornwell


Devin Review

Status Commit
⚪ Not started

Run Devin Review

💡 Connect your GitHub account to enable automatic code reviews.

Open in Devin Review (Staging)

… Boot 3.1.5

- Update pom.xml: Spring Boot 3.1.5, Java 17, mysql-connector-j
- Migrate javax.* to jakarta.* namespace in all domain/config files
- Refactor SecurityConfig: remove WebSecurityConfigurerAdapter, use SecurityFilterChain bean
- Replace @EnableGlobalMethodSecurity with @EnableMethodSecurity
- Update application.properties: remove deprecated HikariCP props, use MySQLDialect
- Change GenerationType.AUTO to GenerationType.IDENTITY in all entities
- Fix Spring Data 3.x API: findOne() -> findById().orElse(null)
- Migrate test class from JUnit 4 to JUnit 5
- Apply Java 17 var type inference across controllers, services, and domain

Co-Authored-By: Stephen Cornwell <stephen@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

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 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +31 to 33
var appointment = findAppointment(id);
appointment.setConfirmed(true);
appointmentDao.save(appointment);
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.

🔴 NullPointerException in confirmAppointment when appointment ID is not found

The findAppointment method at AppointmentServiceImpl.java:27 was migrated from findOne(id) to findById(id).orElse(null), which returns null when the appointment doesn't exist. The confirmAppointment method at line 31-33 calls findAppointment(id) and immediately dereferences the result (appointment.setConfirmed(true)) without a null check, causing a NullPointerException. This is reachable from the AppointmentResource.confirmAppointment REST endpoint (AppointmentResource.java:30-31), which takes the id from a path variable. When an admin sends a request with a non-existent appointment ID, the server will crash with an unhandled NPE.

Suggested change
var appointment = findAppointment(id);
appointment.setConfirmed(true);
appointmentDao.save(appointment);
var appointment = findAppointment(id);
if (appointment == null) {
throw new IllegalArgumentException("Appointment not found with id: " + id);
}
appointment.setConfirmed(true);
appointmentDao.save(appointment);
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.

Fixed in dbf52b8 — added null check with IllegalArgumentException as suggested. Good catch on this regression introduced by the findOne()findById().orElse(null) migration.

devin-ai-integration Bot and others added 3 commits May 15, 2026 08:03
…word, and multi-servlet security

- Add @lazy to break circular dependency between UserServiceImpl, AccountServiceImpl, and TransactionServiceImpl (prohibited by default in Spring Boot 3.x)
- Add @table(name="users") to User entity to avoid SQL reserved keyword conflict
- Use explicit AntPathRequestMatcher in SecurityConfig to resolve multi-servlet ambiguity
- Add H2 database dependency for local testing without MySQL

Co-Authored-By: Stephen Cornwell <stephen@cognition.ai>
- Add null guard in AppointmentServiceImpl.confirmAppointment() to prevent NPE when appointment ID doesn't exist (findById returns Optional.empty -> orElse(null))
- Add application-h2.properties for local testing with H2 in-memory database

Co-Authored-By: Stephen Cornwell <stephen@cognition.ai>
Co-Authored-By: Stephen Cornwell <stephen@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown
Author

End-to-End Test Results — Spring Boot 3 Migration

Ran the app locally with H2 in-memory database (mvn spring-boot:run -Dspring-boot.run.profiles=h2) and tested the full golden-path flow via browser.

Session: https://app.devin.ai/sessions/b0736040b00144189c0396a99781fea9

Escalation

  • Login redirect: After submitting the login form, Spring Security redirects to /error?continue (status 999) instead of /userFront. The user IS authenticated — navigating directly to /userFront loads the dashboard correctly. This is a Spring Security 6.x defaultSuccessUrl redirect behavior difference, not an auth failure. Minor UX issue worth investigating separately.

Test Results

  • App Startup: PASSED — Started in 3.4s, no errors
  • Signup Form: PASSED — /signup loads with all 6 fields
  • Create User: PASSED — Redirects to /index with "Please sign in"
  • Login: PASSED (with caveat) — Auth works, dashboard shows $0.00 balances; redirect goes to error page but direct nav works
  • Deposit $500: PASSED — Primary Balance updated to $500.00
  • View Transactions: PASSED — Shows "Deposit to Primary Account", 500.0, Finished
  • Logout: PASSED — Redirects to /index?logout with "You have been logged out."
Screenshots
Step Screenshot
Signup form signup
Dashboard ($0 balances) dashboard
After $500 deposit deposit
Transaction details transactions
Logout logout
Login redirect issue detail

After form submission to /index (POST), Spring Security authenticates successfully (Hibernate queries confirm user, accounts, and roles loaded) but the defaultSuccessUrl("/userFront") redirect results in /error?continue with {"status":999,"error":"None"}. Navigating directly to /userFront shows the user is authenticated. This may be related to Spring Security 6.x's handling of SavedRequest or the interaction between loginPage("/index") and defaultSuccessUrl.

error page

Spring Security 6.x's defaultSuccessUrl without alwaysUse=true
redirects to saved requests instead of the configured URL, causing
a status 999 error page in the browser. Setting alwaysUse=true
forces redirect to /userFront after successful authentication.

Co-Authored-By: Stephen Cornwell <stephen@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown
Author

End-to-End Test Results — Spring Boot 3 Migration (Updated)

Ran the app locally with H2 in-memory database (mvn spring-boot:run -Dspring-boot.run.profiles=h2) and tested the full golden-path flow via browser. All 7 tests passed.

Session: https://app.devin.ai/sessions/b0736040b00144189c0396a99781fea9

Bug Found & Fixed During Testing

Login redirect: initial testing revealed defaultSuccessUrl("/userFront") redirected to /error?continue (status 999) in the browser. Fixed in commit 627475c by setting defaultSuccessUrl("/userFront", true) — Spring Security 6.x needs alwaysUse=true to ignore stale saved requests.

🔴 Before Fix (status 999) 🟢 After Fix (dashboard loads)
before after

Test Results

  • App Startup: PASSED — Started in ~3.4s with no errors
  • Signup Form: PASSED — /signup loads with all 6 fields
  • Create User: PASSED — Redirects to /index with "Please sign in"
  • Login: PASSED — Redirects directly to /userFront dashboard with $0.00 balances
  • Deposit $500: PASSED — Primary Balance updated to $500.00
  • View Transactions: PASSED — "Deposit to Primary Account", 500.0, Finished
  • Logout: PASSED — Redirects to /index?logout with "You have been logged out."
Additional Screenshots

Dashboard after $500 deposit:
deposit

Transaction details:
transactions

Logout:
logout

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