{"id":"cmq4ni3d8005hpl01n1vmctra","docId":"cmq4nh0x6004ppl01inrkd195","version":1,"title":"Spring Boot 3 / Java 21 마이그레이션 플랜","content":"# Spring Boot 3 / Java 21 마이그레이션 플랜\n\n대상: `1472s_shred-system`  \n현재 기준: Spring Boot `2.5.2`, Java `8`, Gradle Wrapper `7.5`, `war` 배포  \n목표 기준: Spring Boot `3.3.x`, **Java `21` LTS 채택**.\n\n**Java 21 채택 이유** (2026-05-08 사용자 결정):\n- Spring Boot 3.3 LTS native 권장\n- virtual threads (Project Loom) — ERP I/O bound 워크로드에 유리 (Tomcat virtual thread executor)\n- 2028-09 LTS 지원, ZGC 안정, GraalVM native image 강화\n- pattern matching, record patterns, sealed classes 가독성\n- 자체 라이브러리 (wellsa-commons / irosafe-shred-commons) 신규 작성하므로 외부 jar 17 호환성 걱정 없음\n\n## 0. 기준 결정\n\n- Public Maven Central 기준 Spring Boot 3.3 라인의 최신 OSS 릴리스는 `3.3.13`이다.\n- Spring Enterprise/LTS 계약 저장소를 쓸 수 있으면 `3.3.16+` 라인을 별도 검토한다. Enterprise 문서 기준 Spring Boot 3.3.16은 Java 17 이상, Gradle 7.5+ 또는 8.x를 요구한다.\n- 이 프로젝트의 Gradle Wrapper는 이미 `7.5`라서 최소 요구사항은 맞지만, 실제 마이그레이션 브랜치에서는 Gradle `8.10+`로 올리는 편이 안전하다.\n- 로컬 현재 세션에는 JDK가 없어 `./gradlew` 빌드 실행은 아직 불가했다. `java_home`이 \"Unable to locate a Java Runtime\"를 반환했다.\n\n## 1. 현재 상태 스냅샷\n\n`1472s_shred-system/build.gradle` 주요 의존성:\n\n| 영역 | 현재 버전 |\n| --- | --- |\n| Spring Boot | `2.5.2` |\n| Java | `sourceCompatibility = 1.8` |\n| MyBatis Spring Boot Starter | `2.2.0` |\n| Spring Data Envers | Boot BOM 암묵 버전 |\n| Thymeleaf extras | `thymeleaf-extras-springsecurity5` |\n| Thymeleaf layout dialect | `2.4.1` |\n| lucy-xss-servlet | `2.0.0` |\n| JJWT | `0.11.2` |\n| JasperReports | `6.17.0` |\n| iText/lowagie | `2.1.7` |\n| ZXing | `3.4.1` |\n| Apache POI | `5.0.0` |\n| 외부 사내 jar (`libs/`) | 자체 라이브러리로 교체 예정 → `wellsa-commons` + `irosafe-shred-commons` 신규 |\n| Logback override | `1.2.3` |\n\n코드 스캔 결과:\n\n- `javax.*` import/참조: 106개 Java 파일, 483개 라인.\n- 주요 전환 대상: `javax.persistence` 285, `javax.validation` 46, `javax.servlet` 141, `javax.transaction` 10.\n- `javax.sql`, `javax.net.ssl`, `javax.imageio`는 Java SE 패키지이므로 `jakarta.*`로 바꾸면 안 된다.\n- `SecurityConfig`는 `WebSecurityConfigurerAdapter`, `authorizeRequests`, `antMatchers`, 체이닝식 `csrf()`/`headers()`를 사용한다.\n- Thymeleaf 3.1에서 제거된 `#request`, `#response`, `#session`, `#servletContext`, `th:include` 사용처는 현재 템플릿에서 0건이다.\n- 외부 사내 jar (`libs/`) 는 Java 8 bytecode + `javax.servlet`/`javax.persistence.criteria`/외부 XSS 필터 참조로 SB3 그대로 사용 불가. **자체 라이브러리 신규 작성으로 전면 교체** (사용자 결정 2026-05-08): `wellsa-commons` (전사 코어) + `irosafe-shred-commons` (도메인 특화) 2층 구조. SB3.3 + Java 21 + jakarta 기반 신규 작성.\n\n## 2. 의존성 호환 매트릭스\n\n| 의존성 | 현재 | SB3.3 / Java17 후보 | 판정 | 조치 |\n| --- | ---: | ---: | --- | --- |\n| Spring Boot Gradle Plugin | `2.5.2` | `3.3.13` OSS, 또는 Enterprise `3.3.16+` | High | 먼저 `2.7.18` 중간 경유 후 `3.3.x`로 올린다. `io.spring.dependency-management`는 `1.1.7` 이상 또는 Boot plugin BOM에 위임. |\n| Java | `1.8` | `21` | High | `java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }`로 고정. virtual threads + Loom 활용 (`spring.threads.virtual.enabled=true`). |\n| MyBatis Spring Boot Starter | `2.2.0` | `3.0.5` | High | MyBatis 공식 표에서 3.0 라인은 Spring Boot 3.2-3.5 + Java 17. `4.0.x`는 Boot 4 전용이므로 쓰지 않는다. |\n| Spring Data Envers | Boot 2.5 BOM | Boot 3.3 BOM-managed Spring Data `2024.0.x` | High | 명시 버전 없이 BOM에 맡긴다. 모든 entity/repository의 `javax.persistence`를 `jakarta.persistence`로 변환하고 Envers history workflow를 회귀 테스트한다. |\n| Thymeleaf | Boot 2.5 관리 `3.0.x` | Boot 3.3 BOM `3.1.3.RELEASE` | Medium | starter는 버전 제거. `thymeleaf-layout-dialect`는 Boot 3.3 BOM `3.3.0`. |\n| Thymeleaf Spring Security extras | `springsecurity5` | `thymeleaf-extras-springsecurity6` | Medium | artifact 교체. 템플릿의 `sec:*` 동작을 로그인/권한별로 확인. |\n| lucy-xss-servlet | `2.0.0` | 대체 필요 | High | 최신 `2.0.1`도 `javax.servlet:servlet-api:2.5` 기반. Boot 3/Tomcat 10의 `jakarta.servlet`와 호환되지 않는다. 제거 후 자체 `OncePerRequestFilter` 또는 OWASP Java HTML Sanitizer 기반 whitelist sanitizing으로 전환. |\n| JJWT | `0.11.2` | `0.12.7` 안정 후보, `0.13.0` 최신 | Low | 현재 실제 사용은 주석뿐이다. JWT 미사용이면 제거, 사용할 계획이면 `jjwt-api/impl/jackson` 조합으로 갱신하고 새 parser API로 테스트. |\n| JasperReports | `6.17.0` | `6.21.5` 저위험, `7.0.6` 최신 | High | 기존 `.jrxml`/`.jasper`가 있어 보고서 회귀가 핵심. 1차는 `6.21.5`로 PDF 유지 확인, 보안/장기 유지 기준이면 `7.0.6` + `jasperreports-pdf:7.0.6`로 별도 마이그레이션. |\n| iText / lowagie | `2.1.7` | 직접 의존 제거 | High | JasperReports 6.21.5는 `openpdf`를 사용한다. `com.lowagie:itext` 직접 의존은 제거하고 PDF export는 JasperReports가 끌고 오는 PDF 모듈로 검증. |\n| ZXing | `3.4.1` | `3.5.4` | Low | Java 17과 충돌 가능성 낮음. barcode 생성 샘플로 회귀 테스트. |\n| Apache POI | `5.0.0` | `5.5.1` | Medium | `poi`와 `poi-ooxml`을 같은 버전으로 올린다. Excel upload/download, 대용량 파일, 한글 파일명 response header 확인. |\n| MariaDB driver | BOM/runtime implicit | Boot 3.3 BOM `3.3.4` 또는 최신 `3.5.x` | Medium | 우선 BOM 버전 사용. DB timezone/characterEncoding URL과 Hibernate 6 dialect 자동 감지를 확인. |\n| Logback | `1.2.3` 명시 | Boot 3.3 BOM `1.5.x` | Medium | 명시 override 제거. Boot 3 / SLF4J 2와 맞춘다. |\n| sgis-common-frame.jar | flat jar | 재빌드 또는 소스 편입 | High | jar 내부가 `javax.*`와 Lucy XSS에 묶여 있으므로 Boot 3 compileClasspath로 재빌드해야 한다. |\n\n## 3. Breaking changes\n\n### 3.1 `javax.*` to `jakarta.*`\n\nSpring Boot 3는 Spring Framework 6 / Jakarta EE 9+ 기반이다. 아래는 일괄 전환 대상이다.\n\n- `javax.servlet.*` -> `jakarta.servlet.*`\n- `javax.persistence.*` -> `jakarta.persistence.*`\n- `javax.validation.*` -> `jakarta.validation.*`\n- `javax.transaction.*` -> `jakarta.transaction.*` 또는 Spring의 `org.springframework.transaction.annotation.Transactional`\n\n주의:\n\n- `javax.sql.DataSource`, `javax.net.ssl.*`, `javax.imageio.*`는 Java SE라 유지한다.\n- `sgis-common-frame.jar` 내부의 `javax.persistence.criteria.*`는 소스가 없으면 OpenRewrite 대상이 아니다. jar를 소스화하거나 새 모듈로 재빌드해야 한다.\n\n### 3.2 Spring Security 6\n\n현재 `SecurityConfig`는 제거된 `WebSecurityConfigurerAdapter` 기반이다.\n\n필수 전환:\n\n- `extends WebSecurityConfigurerAdapter` 제거.\n- `SecurityFilterChain` `@Bean`으로 전환.\n- 정적 리소스 ignore는 `WebSecurityCustomizer` 또는 `permitAll`로 분리.\n- `authorizeRequests()` -> `authorizeHttpRequests()`.\n- `antMatchers()` -> `requestMatchers()`.\n- `http.csrf()`, `http.headers()` 등은 lambda DSL로 전환.\n- `AuthenticationManagerBuilder` 직접 override 대신 `UserDetailsService`, `PasswordEncoder`, 필요 시 `AuthenticationProvider` bean으로 구성.\n\n### 3.3 Thymeleaf 3.1\n\nThymeleaf 3.1은 Spring 6용 `thymeleaf-spring6`와 Spring Security 6용 extras를 사용한다. 또한 `#request`, `#response`, `#session`, `#servletContext` expression utility object가 제거됐다.\n\n현재 템플릿 스캔에서는 제거 대상 expression 사용처가 없었다. 그래도 로그인/권한별 화면 렌더링에서 `sec:*`, layout dialect, fragment include 동작을 확인해야 한다.\n\n### 3.4 Hibernate 6 / JPA\n\nBoot 3.3 BOM은 Hibernate 6.5 계열이다. 이 프로젝트는 entity import 전환 외에도 아래가 위험하다.\n\n- `spring.jpa.hibernate.naming-strategy: org.hibernate.cfg.EJB3NamingStrategy`는 제거 대상이다. 현재 이미 `physical-strategy`, `implicit-strategy`가 있으므로 legacy key 제거 후 테이블/컬럼 매핑을 검증한다.\n- Envers audit suffix, revision repository, `*_HISTORY` 테이블 생성/조회가 Hibernate 6에서 그대로 동작하는지 별도 테스트한다.\n- `ddl-auto: update`는 마이그레이션 검증 중에는 위험하므로 staging DB snapshot에서만 사용하고 운영 전에는 DDL diff를 고정한다.\n\n## 4. lucy-xss-servlet 대체안\n\nLucy XSS Servlet Filter는 `javax.servlet` 2.5 기반이고 Maven Central 최신도 2019년 `2.0.1`에 머물러 있다. Boot 3에서는 다음 중 하나로 대체한다.\n\n| 대안 | 권장도 | 설명 |\n| --- | --- | --- |\n| 출력 escaping 유지 + 입력 whitelist sanitizing | 높음 | Thymeleaf 기본 escaping을 유지하고, rich text/메모/주소 등 HTML 허용 필드만 OWASP Java HTML Sanitizer 같은 whitelist sanitizing 적용. |\n| 자체 `OncePerRequestFilter` + `HttpServletRequestWrapper` | 중간 | 기존 Lucy처럼 전역 request parameter를 감싸려면 `jakarta.servlet` 기반 wrapper를 직접 구현. 단 모든 입력을 HTML escape하면 검색/비밀번호/JSON payload가 깨질 수 있다. |\n| Lucy fork 후 jakarta 변환 | 낮음 | 단기 호환은 가능하지만 유지보수 책임이 생긴다. `sgis-common-frame.jar` 내부 `XssConfig`도 같이 제거/재빌드해야 한다. |\n\n최소 구현 방향:\n\n- `com.navercorp.lucy:lucy-xss-servlet` 제거.\n- `src/main/resources/lucy-xss-servlet-filter-rule.xml`, `luxy-xss-sax.xml`는 archive 처리.\n- `OncePerRequestFilter`는 `POST form-urlencoded`/`multipart form field`에만 제한 적용.\n- HTML 허용 필드와 plain text 필드를 분리한다.\n- W1/W2/W3에서 `<script>`, event handler, encoded payload, 정상 한글/특수문자 입력을 함께 테스트한다.\n\n## 5. `sgis-common-frame.jar` 호환 검증 절차\n\n현재 jar는 `src/main/resources/libs/sgis-common-frame.jar` 하나뿐이고 소스가 없다. 내부 클래스는 전부 Java 8 bytecode지만 다음 참조가 확인됐다.\n\n- `javax.servlet.Filter`, `javax.servlet.http.HttpServletRequest/Response`\n- `javax.persistence.criteria.*`\n- `com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter`\n- Spring Boot 2 era `FilterRegistrationBean` 설정\n\n검증/전환 순서:\n\n1. jar inventory 고정\n   ```bash\n   unzip -l src/main/resources/libs/sgis-common-frame.jar\n   unzip -p src/main/resources/libs/sgis-common-frame.jar '*.class' | strings | rg 'javax/|com/navercorp/lucy|org/springframework'\n   ```\n\n2. JDK 17 설치 후 의존성 분석\n   ```bash\n   jdeps --multi-release 17 --ignore-missing-deps --recursive src/main/resources/libs/sgis-common-frame.jar\n   ```\n\n3. 소스 확보 또는 decompile 후 별도 모듈화\n   - `com.sgisframe.global.utils.specification.SearchSpecs`는 `jakarta.persistence.criteria.*`로 전환.\n   - `XssConfig`는 제거하거나 새 XSS filter로 재작성.\n   - `FileMgmtUtil`, `BarcodeMgmtUtil`, datasource/config 클래스는 Boot 3 compileClasspath에서 재컴파일.\n\n4. flatDir 제거\n   - `flatDir` + `implementation name: 'sgis-common-frame'` 대신 `buildSrc`, `includedBuild`, 또는 내부 Maven artifact로 관리.\n\n5. compile 검증\n   ```bash\n   ./gradlew clean compileJava --stacktrace\n   ./gradlew dependencyInsight --dependency sgis-common-frame\n   ```\n\n## 6. OpenRewrite recipe 목록\n\n권장 실행은 `feature/sb3-java17-migration` 같은 전용 브랜치에서 datatable export를 켠 뒤 단계별 commit으로 나눈다.\n\n1. Java 17 준비\n   - `org.openrewrite.java.migrate.UpgradeToJava17`\n\n2. Spring Boot 2.5 -> 2.7 중간 경유\n   - `org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7`\n\n3. Spring Boot 3 기본 전환\n   - `org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0`\n   - `org.openrewrite.java.spring.boot3.SpringBootProperties_3_0`\n\n4. Jakarta namespace\n   - `org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta`\n\n5. Spring Security 6\n   - `org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_0`\n\n6. 수동 후속\n   - `SecurityConfig` lambda DSL 정리.\n   - `sgis-common-frame.jar` 소스화/재빌드.\n   - Lucy XSS 제거 및 대체 filter 추가.\n   - JasperReports `.jrxml` 재컴파일.\n   - BootWar `archiveName` -> `archiveFileName` 정리.\n\n예시 Gradle init-script 방식:\n\n```groovy\ninitscript {\n    repositories { maven { url \"https://plugins.gradle.org/m2\" } }\n    dependencies { classpath(\"org.openrewrite:plugin:7.32.1\") }\n}\nrootProject {\n    plugins.apply(org.openrewrite.gradle.RewritePlugin)\n    repositories { mavenCentral() }\n    dependencies {\n        rewrite(\"org.openrewrite.recipe:rewrite-spring:6.30.3\")\n        rewrite(\"org.openrewrite.recipe:rewrite-migrate-java:latest.release\")\n    }\n    rewrite {\n        activeRecipe(\"org.openrewrite.java.migrate.UpgradeToJava17\")\n        activeRecipe(\"org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7\")\n        activeRecipe(\"org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0\")\n        activeRecipe(\"org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta\")\n        activeRecipe(\"org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_0\")\n        setExportDatatables(true)\n    }\n}\n```\n\n## 7. 회귀 테스트 핵심 워크플로\n\n### W1. 인증/세션/권한\n\n목표: Spring Security 6 전환 후 기존 운영 화면 접근 정책 유지.\n\n- `/login/loginForm` 렌더링.\n- `/login/doLogin` 성공/실패 handler 확인.\n- `SUPER`, `ADMIN`, `USER` 역할별 `/adm/**`, `/common/admMain`, `/common/frnMain`, `/frn/**` 접근.\n- 중복 로그인, session timeout, invalid session, logout cookie 삭제.\n- CSRF token cookie와 form submit 확인.\n\n### W2. 파쇄 운영 핵심 CRUD\n\n목표: JPA/Hibernate 6, Envers, MyBatis, DB schema 영향 검증.\n\n- 고객/지점/계약 등록 및 수정.\n- 파쇄 신청/작업 등록, console matching, schedule 변경.\n- Envers `RevisionRepository` 조회 및 `*_HISTORY` 테이블 기록.\n- MyBatis mapper SQL 3종(`SCHEDULE_SQL.xml`, `SAMPLE_SQL.xml`, `STATISTICS_SQL.xml`) 조회.\n- MariaDB timezone, 한글 검색, pagination, `Specification` join 조건 확인.\n\n### W3. 파일/리포트/외부 연동\n\n목표: POI/Jasper/ZXing/파일 다운로드/알림톡 회귀 확인.\n\n- Excel upload/download: `.xls`, `.xlsx`, 한글 파일명, 대용량 row.\n- Jasper PDF: `src/main/resources/ireport/*.jrxml` 컴파일, 기존 `.jasper` 재생성, PDF layout diff.\n- Barcode 생성/인쇄 화면: ZXing output 확인.\n- 파일 upload/download/zip, 이미지 preview.\n- Kakao 알림톡 token/send/result polling은 sandbox key 또는 mock server로 분리 테스트.\n- XSS payload 입력 후 저장/조회/다운로드 화면에서 escaping 확인.\n\n## 8. 단계별 실행 순서와 위험도\n\n| 단계 | 작업 | 위험도 | 완료 기준 |\n| --- | --- | --- | --- |\n| 0 | JDK 17 설치, baseline `./gradlew clean test` 확보 | Medium | 현재 Boot 2.5 상태에서 빌드/테스트 실패 목록 고정 |\n| 1 | Spring Boot `2.7.18` + Java 17 중간 경유 | High | `javax.*` 상태로 Java 17 compile/runtime 이슈 선제 제거 |\n| 2 | OpenRewrite Java/Jakarta/SB3 recipe 실행 | High | 자동 diff를 compile 단위로 분리 commit |\n| 3 | Gradle/Boot build 정리 | Medium | Boot `3.3.x`, Gradle plugin, `archiveFileName`, BOM 의존성 정리 |\n| 4 | `sgis-common-frame.jar` 소스화/재빌드 | High | jar 내부 `javax.*` 제거, Boot 3 compile 성공 |\n| 5 | Security 6 수동 마이그레이션 | High | W1 통과 |\n| 6 | Lucy XSS 제거 및 대체 filter 적용 | High | 정상 입력 보존 + XSS payload 차단/escaping 검증 |\n| 7 | Jasper/POI/ZXing 업그레이드 | Medium | W3 PDF/Excel/barcode 결과물 diff 승인 |\n| 8 | Hibernate 6/Envers/DB 검증 | High | W2 통과, DDL diff 승인 |\n| 9 | staging WAR 배포 smoke | High | W1/W2/W3 staging 통과, rollback artifact 준비 |\n\n## 9. 1차 build.gradle 목표안\n\n실제 적용 전용 브랜치에서 아래 방향으로 정리한다.\n\n```groovy\nplugins {\n    id 'org.springframework.boot' version '3.3.13'\n    id 'io.spring.dependency-management' version '1.1.7'\n    id 'java'\n    id 'war'\n}\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(17)\n    }\n}\n\nbootWar {\n    archiveFileName = \"1472SHRED_DEPLOY.war\"\n}\n\ndependencies {\n    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'\n    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.5'\n    implementation 'org.springframework.data:spring-data-envers'\n    implementation 'org.springframework.boot:spring-boot-starter-jdbc'\n    implementation 'org.springframework.boot:spring-boot-starter-quartz'\n    implementation 'org.springframework.boot:spring-boot-starter-security'\n    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'\n    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'\n    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'\n    implementation 'org.springframework.boot:spring-boot-starter-web'\n    implementation 'org.springframework.boot:spring-boot-starter-validation'\n\n    implementation 'org.apache.poi:poi:5.5.1'\n    implementation 'org.apache.poi:poi-ooxml:5.5.1'\n    implementation 'net.sf.jasperreports:jasperreports:6.21.5'\n    implementation 'com.google.zxing:core:3.5.4'\n    implementation 'com.google.zxing:javase:3.5.4'\n\n    implementation 'org.modelmapper:modelmapper:3.2.6'\n    implementation 'org.apache.httpcomponents.client5:httpclient5'\n    implementation 'org.json:json:20250517'\n\n    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'\n    compileOnly 'org.projectlombok:lombok'\n    annotationProcessor 'org.projectlombok:lombok'\n    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'\n    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'\n    testImplementation 'org.springframework.boot:spring-boot-starter-test'\n    testImplementation 'org.springframework.security:spring-security-test'\n}\n```\n\n보류/삭제 후보:\n\n- `com.navercorp.lucy:lucy-xss-servlet`: 삭제.\n- `com.lowagie:itext`: 삭제.\n- `ch.qos.logback:*`: 명시 버전 삭제 후 Boot BOM 사용.\n- `flatDir` + `sgis-common-frame.jar`: 소스화/내부 artifact 전환 후 삭제.\n- `io.jsonwebtoken:*`: 현재 미사용이면 삭제, JWT 도입 시 별도 security task로 갱신.\n\n## 10. 출처\n\n- Spring Boot 3.3 system requirements: https://docs.enterprise.spring.io/spring-boot/system-requirements.html\n- Spring Boot Maven Central metadata: https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-dependencies/maven-metadata.xml\n- Spring Boot 3.3.13 dependency BOM: https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-dependencies/3.3.13/spring-boot-dependencies-3.3.13.pom\n- MyBatis Spring Boot Starter requirements: https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/\n- Thymeleaf 3.1 migration notes: https://www.thymeleaf.org/doc/articles/thymeleaf31whatsnew.html\n- Spring Security migration note for `SecurityFilterChain`: https://docs.enterprise.spring.io/spring-security/reference/5.8-SNAPSHOT/migration/servlet/config.html\n- OpenRewrite Spring Boot 3 recipe: https://docs.openrewrite.org/recipes/java/spring/boot3/upgradespringboot_3_0\n- OpenRewrite Spring Boot properties recipe: https://docs.openrewrite.org/recipes/java/spring/boot3/springbootproperties_3_0\n- OpenRewrite Spring Security 6 recipe: https://docs.openrewrite.org/recipes/java/spring/security6/upgradespringsecurity_6_0\n- OpenRewrite Jakarta recipe catalog: https://docs.openrewrite.org/reference/recipes-by-tag\n- Maven Central metadata: JJWT, JasperReports, JasperReports PDF, Apache POI, ZXing, Lucy XSS Servlet.\n- JasperReports 7.0.0 release notes / module split: https://sourceforge.net/projects/jasperreports/files/jasperreports/JasperReports%207.0.0/\n","sourceHash":"ef960c973552b738810f03f1f331a194","archivedAt":"2026-06-08T12:28:10+09:00","archivedBy":"sync"}