Skip to content

Migrate to Java 21 / Spring Boot 3.2.5#22

Open
devin-ai-integration[bot] wants to merge 6 commits into
masterfrom
devin/1777913688-java21-migration-base
Open

Migrate to Java 21 / Spring Boot 3.2.5#22
devin-ai-integration[bot] wants to merge 6 commits into
masterfrom
devin/1777913688-java21-migration-base

Conversation

@devin-ai-integration
Copy link
Copy Markdown

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

Summary

End-to-end migration of this repo from Java 8 / Spring Boot 2.0.2 to Java 21 / Spring Boot 3.2.5. Work was split across three child Devin sessions and merged onto an integration branch (devin/1777913688-java21-migration-base); this PR brings that integration branch into master.

Build configuration — Maven (child PR #20)

  • pom.xml
    • Spring Boot parent: 2.0.2.RELEASE3.2.5
    • <java.version>: 1.821
    • Removed spring-boot-properties-migrator (1.x→2.x migration aid; not published for 3.x)
    • Other deps (spring-boot-starter-web, spring-boot-starter-jdbc, h2) inherit compatible versions from the new parent BOM
  • .mvn/wrapper/maven-wrapper.properties: Maven 3.3.93.9.6 (3.9+ required for Java 21)

Build configuration — Gradle (child PR #19)

  • build.gradle
    • spring-boot-gradle-plugin: 2.0.2.RELEASE3.2.5
    • sourceCompatibility / targetCompatibility: 1.821
    • compile(...)implementation(...), testCompile(...)testImplementation(...)
    • bootJar { baseName / version }bootJar { archiveBaseName / archiveVersion }
  • gradle/wrapper/gradle-wrapper.properties: Gradle 4.68.7 (8.5+ required for Java 21)

Source — Application.java (child PR #21)

  • H2 2.x SQL syntax: DROP TABLE customers IF EXISTSDROP TABLE IF EXISTS customers
  • Replaced deprecated JdbcTemplate.query(sql, Object[], RowMapper) with the varargs-last query(sql, RowMapper, Object...)
  • Replaced defunct http://gturnquist-quoters.cfapps.io/api/random (both occurrences) with the placeholder https://jsonplaceholder.typicode.com/posts/1. RestTemplate retained.
  • Verified no javax.* imports under src/main/java/hello/ (none found, no jakarta.* rewrites needed)

Local verification under JDK 21

  • ./mvnw clean package -DskipTestsBUILD SUCCESS. Maven 3.9.6 was auto-downloaded by the wrapper, the Spring Boot 3.2.5 BOM resolved cleanly, all dependencies fetched. Caveat: the pom.xml carries <packaging>pom</packaging> (pre-existing), so this phase does NOT actually compile src/main/java/hello/*.java — it just runs the lifecycle to package for a pom-typed artifact. See "Pre-existing issues" below.
  • Direct javac of all 13 source files under JDK 21 against the maven-resolved classpath → succeeds (all 13 .class files produced under /tmp/javac-out). This is the strongest signal that the migration's source changes compile cleanly under Java 21 + Spring Boot 3.2.5.
  • ./gradlew build (Gradle 8.7 auto-downloaded) → fails at :compileJava because org.springframework.jdbc.core.JdbcTemplate is missing on the classpath. This is pre-existing, not introduced by this migration — see below.

Pre-existing issues (NOT introduced by this migration, but worth flagging)

  1. pom.xml has <packaging>pom</packaging> — wrong packaging for a Spring Boot app; ./mvnw package doesn't run maven-compiler-plugin. Out of scope per the original task spec, but a one-character follow-up (pomjar) would make ./mvnw clean package actually compile and produce a runnable jar.
  2. build.gradle is missing spring-boot-starter-jdbc and h2 dependencies — only spring-boot-starter-web is declared, so ./gradlew compileJava cannot resolve JdbcTemplate. Confirmed present on master before this PR. The Maven pom.xml has these deps, so Maven has always been the working build path for this repo.

Both are tiny pre-existing follow-ups; they do not block the Java 21 migration itself, which is verified by the direct javac compile under JDK 21.

Review & Testing Checklist for Human

  • Run ./mvnw clean package under JDK 21 locally — should print BUILD SUCCESS (with the pom-packaging caveat above; see follow-up Fix build and startup: correct packaging type, handle defunct external API #1 if you want a real compile + executable jar).
  • (Optional follow-up) Add spring-boot-starter-jdbc and h2 to build.gradle so ./gradlew build works as a second verification path. The fix is trivial: add implementation("org.springframework.boot:spring-boot-starter-jdbc") and runtimeOnly("com.h2database:h2"). Not in this PR because the user's task spec didn't authorize editing build.gradle beyond the four explicit bullets — happy to do it as a follow-up if desired.
  • Boot the app and exercise endpoints: ./mvnw spring-boot:run (or convert packaging to jar first), then hit GET /, GET /topic, GET /datetime. Confirm Spring Boot 3.2.5 starts, the customers table loads (logs show Inserting customer record for ...), and the JdbcTemplate.query(...) for first_name = 'Josh' returns rows — that's the live exercise of both H2 2.x DROP TABLE IF EXISTS customers and the new varargs JdbcTemplate.query().
  • Quote endpoint placeholder is intentional: jsonplaceholder.typicode.com/posts/1 returns {userId, id, title, body}, which won't fully populate Quote's type/value fields. The startup log line will print a Quote{type='null', value=null}. If you want real data flowing, swap to a local @RestController stub or introduce a new Post model — both out of scope for this PR.

Notes

Link to Devin session: https://app.devin.ai/sessions/e43cac2398914ee9a147ef4405dcffb3
Requested by: @dr-phil


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

devin-ai-integration Bot and others added 6 commits May 4, 2026 16:57
- Bump spring-boot-gradle-plugin from 2.0.2.RELEASE to 3.2.5
- Set source/target compatibility to 21
- Replace deprecated compile/testCompile with implementation/testImplementation
- Rename bootJar baseName/version to archiveBaseName/archiveVersion
- Bump Gradle wrapper from 4.6 to 8.7 (required for Java 21)

Co-Authored-By: Phil Bedford <phil.bedford@cognition.ai>
- Bump Spring Boot parent from 2.0.2.RELEASE to 3.2.5
- Bump java.version from 1.8 to 21
- Remove spring-boot-properties-migrator (only needed for 1.x→2.x)
- Bump Maven wrapper distribution from 3.3.9 to 3.9.6 (required for Java 21)

Co-Authored-By: Phil Bedford <phil.bedford@cognition.ai>
- Fix H2 2.x DROP TABLE syntax (DROP TABLE IF EXISTS customers)
- Update deprecated JdbcTemplate.query() to varargs overload
- Replace defunct gturnquist-quoters URL with jsonplaceholder placeholder

Co-Authored-By: Phil Bedford <phil.bedford@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 4 additional findings in Devin Review.

Open in Devin Review


RestTemplate restTemplate = new RestTemplate();
Quote quote = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
Quote quote = restTemplate.getForObject("https://jsonplaceholder.typicode.com/posts/1", Quote.class);
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.

🔴 New API endpoint response schema doesn't match Quote model, resulting in all-null deserialization

The API URL was changed from the old quoters service to https://jsonplaceholder.typicode.com/posts/1, but the Quote model class was not updated. The JSONPlaceholder endpoint returns {userId, id, title, body}, while Quote (src/main/java/hello/model/Quote.java:3-34) expects type (String) and value (Value), where Value (src/main/java/hello/model/Value.java:3-33) expects id (Long) and quote (String). Since Jackson's FAIL_ON_UNKNOWN_PROPERTIES defaults to false in Jackson 2.12+, the unknown fields are silently ignored and the Quote object is created with type=null and value=null. This affects both the manual RestTemplate call in main() (line 39) and the Spring-managed bean call in run() (lines 52-53), causing the application to log meaningless Quote{type='null', value=null} output instead of actual data.

Prompt for agents
The Quote and Value model classes need to be updated to match the JSONPlaceholder /posts/1 API response format. The API returns JSON like: {userId: 1, id: 1, title: "...", body: "..."}. Either: (1) create a new model class (e.g., Post) with fields userId (int), id (int), title (String), body (String), and update both getForObject calls in Application.java to use Post.class instead of Quote.class, or (2) find a different API that returns data matching the Quote/Value model structure. The affected locations are Application.java line 39 (in main()) and lines 52-53 (in the run() CommandLineRunner bean).
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.

Acknowledged — this is intentional and matches the original task spec, which permitted "a working placeholder or mock endpoint (e.g., https://jsonplaceholder.typicode.com/posts/1 or a local stub)" precisely because the original gturnquist-quoters.cfapps.io service is permanently dead. The bot's analysis is correct that Quote will deserialize with all null fields against the JSONPlaceholder response shape.

I deliberately did NOT modify the Quote / Value model classes because:

  1. The migration scope is "Java 8 → Java 21 / Spring Boot 2.0.2 → 3.2.5" — changing the domain model is out of scope.
  2. Quote is only used in two startup-time RestTemplate calls that just log the result; they are not part of any user-facing flow.
  3. Repointing the URL keeps the build green and the app reachable, which is the migration's actual goal. The "all-null Quote" log line is acceptable as a stub and is explicitly called out in the PR description's testing checklist (item 4).

If the team wants real data flowing through Quote again, the right follow-up is one of: (a) add a tiny local @RestController stub under src/main/java/hello/ returning a Quote-shaped JSON payload and point the RestTemplate at http://localhost:8080/..., or (b) introduce a new Post model and switch getForObject to use it. Either is a separate, non-migration change.

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