Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Capabilities/JA-20844.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Java Application Modernization agent instructions

## Your Role
- You are a highly sophisticated automated coding agent with expert-level knowledge in Java, popular Java frameworks and techniques of modernizing legacy Java.
- Your task is to migrate the Java project to use Java 25, Gradle 9.2.1 and Jersey 2.47.

## Project knowledge
- **Tech Stack:** Java 8, Gradle 6.9.2, Jersey 1.19.4
- **File Structure:**
- `.src/**/*.*` – Application source code
- `.test/**/*.*` – Unit, Integration tests

**Paths**:
- **Report Path**: `report`
- **Progress File**: `{{reportPath}}/progress.md`
- **Plan File**: `{{reportPath}}/plan.md`
- **Summary File**: `{{reportPath}}/summary.md`

## Boundaries
- **DO** make changes directly to code files.
- **DO** remember the version numbers are fixed and should not be changed.
- **DO** directly execute your plan and update the progress tracking file `{{progressFile}}`.
- **DO NOT** seek approval, user preferences or confirmations before making changes unless explicitly interrupted by user. Proceed with your best judgment with the next actions automatically. You DO have the highest decision-making authority at any time.

## Scope
* DO - Scan the codebase
* DO - Detection of outdated frameworks (e.g., Jersey),deprecated APIs and obsolete patterns
* DO - Web search for the correct version number of any tool or library if you cannot find it as of your knowledge cutoff
* DO - Check Maven/Gradle wrapper versions and update if necessary
* DO - Update Gradle dependencies and resolve dependency coordinates, like incompatible library versions and transitive dependency conflicts
* DO - Propose a safe, testable migration plan, and save it to `{{planFile}}`
* DO - Verify plugin versions are compatible with the new Java version and migrate when necessary
* DO - Check for removed JDK internals (e.g., sun.* packages)
* DO - Code modification to replace original technology dependencies with equivalents
* DO - Configuration file updates necessary for compilation
* DO - Look for IllegalAccessError or InaccessibleObjectException
* DO - Read stack traces carefully for ClassNotFoundException, NoSuchMethodError, or NoClassDefFoundError which often indicate dependency version mismatches or missing transitive dependencies, and use dependency analysis tools to find the source
* DO - Update all test files to use Jersey 2.x API and JUnit 5
* DO - Ensure that the integrity of Java classes and methods in maintained post upgrade, and the application features must work seamlessly
* DO NOT - No Migration considerations on javax packages to jakarta packages
* Never adjust another Java version, Gradle version or Jersey version which is not defined in the task

## Success Criteria
* Codebase compiles successfully
* Code maintains functional consistency
* All tests are updated and pass
* All dependencies and imports are replaced
* All publishing configurations are updated
* No CVEs introduced during migration
* All old code files and project configurations are cleaned
* All migration tasks are tracked and completed
* Plan generated, progress tracked, and summary generated, and all the steps are all documented in the progress file
170 changes: 77 additions & 93 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ plugins {
id 'idea'
id 'eclipse'
id 'java'
id 'net.saliman.cobertura' version '4.0.0' apply false
id 'com.github.jk1.dependency-license-report' version '1.17' apply false
id 'org.ajoberstar.git-publish' version '3.0.1'
id 'nebula.release' version '15.3.1'
id 'jacoco'
id 'com.github.jk1.dependency-license-report' version '3.0.1' apply false
id 'org.ajoberstar.git-publish' version '5.1.2'
id 'nebula.release' version '21.0.0'
}

// name of the github project repository
Expand All @@ -39,11 +39,11 @@ ext.licenseUrl = 'https://www.apache.org/licenses/'

subprojects {
apply plugin: 'java-library'
apply plugin: 'net.saliman.cobertura'
apply plugin: 'jacoco'
apply plugin: 'com.github.jk1.dependency-license-report'
apply plugin: 'distribution'
apply plugin: 'signing'
apply plugin: 'maven'
apply plugin: 'maven-publish'

group 'com.emc.ecs'

Expand All @@ -54,61 +54,11 @@ subprojects {
mavenLocal()
}

configurations {
jars.extendsFrom(signatures)
}

[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

sourceCompatibility = 1.8

def projectPom = {
project {
name project.name
description project.description
url githubProjectUrl

scm {
url githubProjectUrl
connection githubScmUrl
developerConnection githubScmUrl
}

licenses {
license {
name licenseName
url licenseUrl
distribution 'repo'
}
}

developers {
developer {
id 'EMCECS'
name 'Dell EMC ECS'
}
}
}
}

task writePom {
ext.pomFile = file("$buildDir/pom.xml")
outputs.file pomFile
doLast {
pom(projectPom).writeTo pomFile
}
}

jar {
doFirst {
manifest {
attributes 'Implementation-Version': project.version,
'Class-Path': configurations.runtime.collect { it.getName() }.join(' ')
}
}
into("META-INF/maven/$project.group/$project.name") {
from writePom
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
}

javadoc {
Expand All @@ -117,7 +67,7 @@ subprojects {

task javadocJar(type: Jar) {
archiveClassifier = 'javadoc'
from "${docsDir}/javadoc"
from javadoc.destinationDir
}
tasks.javadocJar.dependsOn javadoc

Expand All @@ -126,14 +76,67 @@ subprojects {
from sourceSets.main.allSource
}

artifacts {
jars jar
jars javadocJar
jars sourcesJar
jar {
doFirst {
manifest {
attributes 'Implementation-Version': project.version,
'Class-Path': configurations.runtimeClasspath.collect { it.getName() }.join(' ')
}
}
}

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar

pom {
name = project.name
description = project.description
url = githubProjectUrl

scm {
url = githubProjectUrl
connection = githubScmUrl
developerConnection = githubScmUrl
}

licenses {
license {
name = licenseName
url = licenseUrl
distribution = 'repo'
}
}

developers {
developer {
id = 'EMCECS'
name = 'Dell EMC ECS'
}
}
}
}
}

repositories {
maven {
name = 'sonatype'
url = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
credentials {
username = findProperty('sonatypeUser') ?: ''
password = findProperty('sonatypePass') ?: ''
}
}
}
}

// remove zips and tars from "install" task
configurations.archives.artifacts.removeAll {it.file =~ /(zip|tar)$/}
signing {
required { gradle.taskGraph.hasTask('publish') }
sign publishing.publications.mavenJava
}

licenseReport {
renderers = [new InventoryHtmlReportRenderer()]
Expand All @@ -142,7 +145,9 @@ subprojects {
distributions {
main {
contents {
from configurations.jars.artifacts.files
from jar
from javadocJar
from sourcesJar
from('.') {
include '*.txt'
}
Expand All @@ -156,31 +161,12 @@ subprojects {
}
}

signing {
required { gradle.taskGraph.hasTask(uploadJars) }
sign configurations.jars
}

uploadJars {
repositories {
mavenDeployer {
beforeDeployment { deployment -> signing.signPom(deployment) }

repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') {
authentication(userName: '', password: '')
}

pom projectPom
}
}
}

// allow typing in credentials
// note: this only works when run without the Gradle daemon (--no-daemon).
// if that's not possible, it's best to read passwords into env. variables and set these properties on the gradle
// command line ( -PsigningPass="${SIGNING_PASS}" -PsonatypePass="${SONATYPE_PASS}" )
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(uploadJars)) {
if (taskGraph.hasTask('publish')) {
if (!rootProject.hasProperty('signingSecretKeyRingFile'))
rootProject.ext.signingSecretKeyRingFile = new String(System.console().readLine('\nSecret key ring file: '))
if (!rootProject.hasProperty('signingKeyId'))
Expand All @@ -194,26 +180,24 @@ subprojects {
ext.'signing.keyId' = rootProject.ext.signingKeyId
ext.'signing.secretKeyRingFile' = rootProject.ext.signingSecretKeyRingFile
ext.'signing.password' = rootProject.ext.signingPass
uploadJars.repositories.mavenDeployer.repository.authentication.userName = rootProject.ext.sonatypeUser
uploadJars.repositories.mavenDeployer.repository.authentication.password = rootProject.ext.sonatypePass
}
}
}

ext.aggregatedDocsDir = "$buildDir/aggregatedDocs"
ext.aggregatedDocsDir = "${layout.buildDirectory.get().asFile}/aggregatedDocs"
task aggregateDocs {
doLast {
if (project.hasProperty('release.stage') && project.ext['release.stage'] == 'final') {
subprojects.each { sp ->
copy {
from sp.docsDir
from sp.javadoc.destinationDir
into "${aggregatedDocsDir}/${sp.name}/latest"
}
}
}
subprojects.each {sp ->
copy {
from sp.docsDir
from sp.javadoc.destinationDir
into "${aggregatedDocsDir}/${sp.name}/${sp.version}"
}
}
Expand All @@ -231,7 +215,7 @@ gitPublish {
}
tasks.gitPublishPush.dependsOn aggregateDocs

tasks.release.dependsOn subprojects.test, subprojects.uploadJars, gitPublishPush, subprojects.distZip
tasks.release.dependsOn subprojects.test, gitPublishPush, subprojects.distZip

clean {
delete aggregatedDocsDir
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
58 changes: 58 additions & 0 deletions report/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Migration Plan: Java 25, Gradle 9.2.1, Jersey 2.47

## Phase 1: Build System
1. Update Gradle wrapper from 6.9.2 → 9.2.1
2. Update root `build.gradle`:
- Java `sourceCompatibility` 1.8 → 25
- Replace `maven` plugin with `maven-publish`
- Replace `net.saliman.cobertura` with `jacoco`
- Update `com.github.jk1.dependency-license-report` 1.17 → 3.0.1
- Update `org.ajoberstar.git-publish` 3.0.1 → 5.1.2
- Update `nebula.release` 15.3.1 → 21.0.0
- Replace `uploadJars`/`mavenDeployer` with `maven-publish` publishing
- Fix deprecated Gradle APIs (`configurations.runtime`, `pom()`, etc.)
3. Update subproject `build.gradle` files:
- Jersey 1.19.4 → Jersey 2.47 (`org.glassfish.jersey.*`)
- JUnit 4.13.2 → JUnit 5.11.0
- Log4j 1.2.17 → Logback 1.5.12 (test logging)
- SLF4J 1.7.36 → 2.0.16
- Jackson 2.12.7 → 2.17.2
- Apache HttpClient 4.5.13 → 4.5.14
- Add JAXB runtime (removed from JDK since Java 11)
- Add `jersey-hk2` for DI

## Phase 2: Source Code Migration
4. Migrate `smart-client-jersey` main sources:
- `SmartFilter`: Rewrite from `ClientFilter` to Jersey 2 `Connector` wrapper
- `SmartClientFactory`: Rewrite for Jersey 2 client creation API
- `SizeOverrideWriter`: Remove Jersey 1 internal provider deps, use standalone impls
- `SizedInputStreamWriter`: Update `ReaderWriter` import
- `OctetStreamXmlProvider`: Remove Jersey 1 deps, use JAXB directly
5. Migrate `smart-client-ecs` main sources:
- `EcsHostListProvider`: Update Jersey client API (`Client`, `WebResource` → `WebTarget`)

## Phase 3: Test Migration
6. Migrate all tests to JUnit 5:
- `org.junit.Test` → `org.junit.jupiter.api.Test`
- `org.junit.Assert` → `org.junit.jupiter.api.Assertions` (note: arg order changes)
- `org.junit.Assume` → `org.junit.jupiter.api.Assumptions`
- `@Before/@After` → `@BeforeEach/@AfterEach`
7. Migrate test Jersey API usage to Jersey 2
8. Replace log4j 1.x usage in tests with SLF4J + Logback

## Phase 4: Verification
9. Build the project: `./gradlew build`
10. Fix any compilation errors
11. Run tests: `./gradlew test`
12. Generate summary report

## Dependency Mapping
| Old | New |
|-----|-----|
| `com.sun.jersey:jersey-client:1.19.4` | `org.glassfish.jersey.core:jersey-client:2.47` |
| `com.sun.jersey.contribs:jersey-apache-client4:1.19.4` | `org.glassfish.jersey.connectors:jersey-apache-connector:2.47` |
| `com.sun.jersey:jersey-json:1.19.4` | Removed (Jackson handles JSON) |
| `junit:junit:4.13.2` | `org.junit.jupiter:junit-jupiter:5.11.0` |
| `log4j:log4j:1.2.17` | `ch.qos.logback:logback-classic:1.5.12` |
| `org.slf4j:slf4j-api:1.7.36` | `org.slf4j:slf4j-api:2.0.16` |
| `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.12.7` | `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.17.2` |
Loading