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
214 changes: 83 additions & 131 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@ import com.github.jk1.license.render.InventoryHtmlReportRenderer
plugins {
id 'idea'
id 'eclipse'
id 'java'
id 'net.saliman.cobertura' version '4.0.0'
id 'com.github.jk1.dependency-license-report' version '1.17'
id 'java-library'
id 'com.github.jk1.dependency-license-report' version '2.9'
id 'distribution'
id 'signing'
id 'maven'
id 'org.ajoberstar.git-publish' version '3.0.1'
id 'nebula.release' version '15.3.1'
id 'maven-publish'
}

group 'com.emc.ecs'
Expand All @@ -63,16 +60,15 @@ repositories {

dependencies {
implementation 'com.emc.ecs:smart-client-ecs:3.0.6'
implementation 'com.sun.jersey.contribs:jersey-apache-client4:1.19.4'
// NOTE: Jackson 2.13 dropped support for JAX-RS 1.x, and we use Jersey client 1.x, so we are stuck on Jackson 1.12.x
// ref: https://github.com/FasterXML/jackson-jaxrs-providers/issues/90#issuecomment-1081368194
implementation 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.12.7'
implementation 'com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.12.7'
implementation 'org.glassfish.jersey.connectors:jersey-apache-connector:2.47'
implementation 'org.glassfish.jersey.inject:jersey-hk2:2.47'
implementation 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.18.3'
implementation 'com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.18.3'
implementation('com.emc.ecs:object-transform:1.1.0') {
exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}
implementation 'commons-codec:commons-codec:1.15'
implementation('org.dom4j:dom4j:2.1.3') {
implementation 'commons-codec:commons-codec:1.17.1'
implementation('org.dom4j:dom4j:2.1.4') {
// workaround for jdom2 bug (https://github.com/dom4j/dom4j/issues/99)
// NOTE: a component metadata rule will not solve the problem for library consumers - this is the only way
exclude module: 'pull-parser'
Expand All @@ -82,11 +78,14 @@ dependencies {
exclude module: 'stax-api'
exclude module: 'jaxb-api'
}
implementation 'org.slf4j:slf4j-api:1.7.36'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.apache.httpcomponents:httpclient:4.5.13'
testRuntimeOnly 'org.slf4j:jcl-over-slf4j:1.7.36'
testRuntimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.19.0'
implementation 'org.slf4j:slf4j-api:2.0.16'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.9'
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.4'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
testRuntimeOnly 'org.slf4j:jcl-over-slf4j:2.0.16'
testRuntimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3'
}

allprojects {
Expand All @@ -95,92 +94,49 @@ allprojects {
}
}

configurations {
jars.extendsFrom(signatures)
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}

[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
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
}

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

javadoc {
options.addStringOption('Xdoclint:none', '-quiet')
}

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

task sourcesJar(type: Jar) {
tasks.register('sourcesJar', Jar) {
archiveClassifier = 'sources'
from sourceSets.main.allSource
}

artifacts {
jars jar
jars javadocJar
jars sourcesJar
}

licenseReport {
renderers = [new InventoryHtmlReportRenderer()]
}

distributions {
main {
contents {
from configurations.jars.artifacts.files
from jar
from tasks.named('javadocJar')
from tasks.named('sourcesJar')
into('tools') {
from { allprojects.configurations.tools.artifacts.files }
}
Expand All @@ -197,84 +153,80 @@ distributions {
}
}

signing {
required { gradle.taskGraph.hasTask(':uploadJars') }
sign configurations.jars
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact tasks.named('sourcesJar')
artifact tasks.named('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'
}
}
}
}
}

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

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

pom projectPom
}
}
}

ext.aggregatedDocsDir = "$buildDir/aggregatedDocs"
task aggregateDocs {
signing {
required { gradle.taskGraph.hasTask(':publishMavenJavaPublicationToSonatypeRepository') }
sign publishing.publications.mavenJava
}

ext.aggregatedDocsDir = "${layout.buildDirectory.get().asFile}/aggregatedDocs"
tasks.register('aggregateDocs') {
dependsOn javadoc
doLast {
if (project.hasProperty('release.stage') && project.ext['release.stage'] == 'final') {
copy {
from docsDir
from javadoc.destinationDir
into "${aggregatedDocsDir}/latest"
}
}
copy {
from docsDir
from javadoc.destinationDir
into "${aggregatedDocsDir}/${project.version}"
}
}
}
tasks.aggregateDocs.dependsOn javadoc

gitPublish {
repoUri = githubRemoteUrl
branch = 'gh-pages'
contents {
from aggregatedDocsDir
}
preserve { include '**/*' }
}
tasks.gitPublishPush.dependsOn aggregateDocs

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

clean {
delete aggregatedDocsDir
}

// allow typing in credentials
// note: this only works when run without the Gradle daemon (--no-daemon)
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(':uploadJars')) {
if (!rootProject.hasProperty('signingSecretKeyRingFile'))
rootProject.ext.signingSecretKeyRingFile = new String(System.console().readLine('\nSecret key ring file: '))
if (!rootProject.hasProperty('signingKeyId'))
rootProject.ext.signingKeyId = new String(System.console().readLine('\nSigning key id: '))
if (!rootProject.hasProperty('signingPass'))
rootProject.ext.signingPass = new String(System.console().readPassword('\nSigning key passphrase: '))
if (!rootProject.hasProperty('sonatypeUser'))
rootProject.ext.sonatypeUser = new String(System.console().readLine('\nSonatype username: '))
if (!rootProject.hasProperty('sonatypePass'))
rootProject.ext.sonatypePass = new String(System.console().readPassword('\nSonatype password: '))
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
}
if (taskGraph.hasTask(':gitPublishPush') || taskGraph.hasTask(':release')) {
if (!rootProject.hasProperty('gitUsername'))
rootProject.ext.gitUsername = new String(System.console().readLine('\nGit username: '))
if (!rootProject.hasProperty('gitPassword'))
rootProject.ext.gitPassword = new String(System.console().readPassword('\nGit password: '))
System.setProperty('org.ajoberstar.grgit.auth.username', rootProject.ext.gitUsername)
System.setProperty('org.ajoberstar.grgit.auth.password', rootProject.ext.gitPassword)
}
test {
useJUnitPlatform()
}
53 changes: 53 additions & 0 deletions capabilities/JA-20844.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 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
- `../smart-client-java` - smart client repository as a dependency, which has been migrated

**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
Loading