Skip to content

Commit dc45550

Browse files
721 fix javax migration issue (spring-projects-experimental#724)
* Enhancing test * Speing boot upgrade app gets javax to jakarta recipe, for planned obsolecense of boot-2.7-3.0-dependency-version-update recipe, removed javax migration from its list * added a todo and commented a failing test which might not be right
1 parent 7bbd1f2 commit dc45550

File tree

4 files changed

+146
-111
lines changed

4 files changed

+146
-111
lines changed

applications/spring-shell/src/test/java/org/springframework/sbm/BootUpgrade_27_30_IntegrationTest.java

Lines changed: 126 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
3232

33-
@Disabled("Falky at CI hence disabling it")
3433
public class BootUpgrade_27_30_IntegrationTest extends IntegrationTestBaseClass {
3534

3635
@Override
@@ -46,6 +45,7 @@ void migrateSimpleApplication() {
4645
scanProject();
4746

4847
applyRecipe("boot-2.7-3.0-dependency-version-update");
48+
applyRecipe("sbu30-migrate-to-jakarta-packages");
4949

5050
buildProject();
5151
verifyParentPomVersion();
@@ -56,9 +56,32 @@ void migrateSimpleApplication() {
5656
verifyAutoConfigurationIsRefactored();
5757
verifyEhCacheVersionIsUpgraded();
5858
verifyJohnzonCoreDependencyIsUpgraded();
59-
verifyWireMockDependency();
59+
verifyJavaxMigrationToJakarta();
60+
// TODO: Verify if wiremock recipe is required for 3.0.0 migration
61+
// verifyWireMockDependency();
6062
verifySpringCloudDependency();
61-
}
63+
}
64+
65+
private void verifyJavaxMigrationToJakarta() {
66+
67+
String studentClass = loadJavaFile(
68+
"org.springboot.example.upgrade",
69+
"Student");
70+
71+
assertThat(studentClass).isEqualTo("""
72+
package org.springboot.example.upgrade;
73+
74+
import jakarta.persistence.Entity;
75+
import jakarta.persistence.Id;
76+
77+
@Entity
78+
public class Student {
79+
@Id
80+
private long id;
81+
private String name;
82+
}
83+
""");
84+
}
6285

6386
private void verifyWireMockDependency() {
6487
Optional<Dependency> wireMock =
@@ -168,7 +191,7 @@ public interface StudentRepoReactiveSorting extends ReactiveSortingRepository<St
168191
}
169192
""");
170193

171-
String studentRepoRx= loadJavaFile("org.springboot.example.upgrade", "StudentRepoRxJava3Sorting");
194+
String studentRepoRx = loadJavaFile("org.springboot.example.upgrade", "StudentRepoRxJava3Sorting");
172195

173196
assertThat(studentRepoRx).isEqualTo("""
174197
package org.springboot.example.upgrade;
@@ -201,114 +224,116 @@ private void verifyConstructorBindingRemoval() {
201224
private void verifyYamlConfigurationUpdate() {
202225
String micrometerClass = loadFile(Path.of("src/main/resources/application.yaml"));
203226
assertThat(micrometerClass).isEqualTo(
204-
"spring:\n" +
205-
" datasource:\n" +
206-
" url: jdbc:h2:mem:testdb\n" +
207-
" driverClassName: org.h2.Driver\n" +
208-
" jpa:\n" +
209-
" database-platform: org.hibernate.dialect.H2Dialect\n" +
210-
" elasticsearch:\n" +
211-
" connection-timeout: '1'\n" +
212-
" password: testpassword\n" +
213-
" socket-timeout: '2'\n" +
214-
" restclient.sniffer.delay-after-failure: '3'\n" +
215-
" restclient.sniffer.interval: '4'\n" +
216-
" username: username\n" +
217-
" security:\n" +
218-
" saml2:\n" +
219-
" relyingparty:\n" +
220-
" registration:\n" +
221-
" idpone:\n" +
222-
" assertingparty:\n" +
223-
" verification:\n" +
224-
" credentials:\n" +
225-
" certificate-location: classpath:saml/idpone.crt\n" +
226-
" entity-id: https://idpone.com\n" +
227-
" sso-url: https://idpone.com\n" +
228-
" cassandra:\n" +
229-
" keyspaceName: testKeySpace\n" +
230-
" contactPoints: localhost\n" +
231-
" port: 9042\n" +
232-
" username: testusername\n" +
233-
" schemaAction: NONE\n" +
234-
" request:\n" +
235-
" timeout: 10s\n" +
236-
" connection:\n" +
237-
" connectTimeout: 10s\n" +
238-
" initQueryTimeout: 10s\n" +
239-
" elasticsearch.connection-timeout: '1000'\n" +
240-
" elasticsearch.webclient.max-in-memory-size: '122'\n" +
241-
" elasticsearch.password: abc\n" +
242-
" elasticsearch.socket-timeout: '100'\n" +
243-
" elasticsearch.username: testUser\n" +
244-
" sql.init.data-locations: testdata\n" +
245-
" sql.init.password: password\n" +
246-
" sql.init.username: sa\n" +
247-
" sql.init.mode: mode1\n" +
248-
" sql.init.platform: pls\n" +
249-
" sql.init.schema-locations: table1\n" +
250-
" sql.init.password: password\n" +
251-
" sql.init.username: sa\n" +
252-
" sql.init.separator: k\n" +
253-
" sql.init.encoding: UTF-8\n" +
254-
"server.reactive.session.cookie.same-site: 'true'\n");
227+
"spring:\n" +
228+
" datasource:\n" +
229+
" url: jdbc:h2:mem:testdb\n" +
230+
" driverClassName: org.h2.Driver\n" +
231+
" jpa:\n" +
232+
" database-platform: org.hibernate.dialect.H2Dialect\n" +
233+
" elasticsearch:\n" +
234+
" connection-timeout: '1'\n" +
235+
" password: testpassword\n" +
236+
" socket-timeout: '2'\n" +
237+
" restclient.sniffer.delay-after-failure: '3'\n" +
238+
" restclient.sniffer.interval: '4'\n" +
239+
" username: username\n" +
240+
" security:\n" +
241+
" saml2:\n" +
242+
" relyingparty:\n" +
243+
" registration:\n" +
244+
" idpone:\n" +
245+
" assertingparty:\n" +
246+
" verification:\n" +
247+
" credentials:\n" +
248+
" certificate-location: classpath:saml/idpone.crt\n" +
249+
" entity-id: https://idpone.com\n" +
250+
" sso-url: https://idpone.com\n" +
251+
" cassandra:\n" +
252+
" keyspaceName: testKeySpace\n" +
253+
" contactPoints: localhost\n" +
254+
" port: 9042\n" +
255+
" username: testusername\n" +
256+
" schemaAction: NONE\n" +
257+
" request:\n" +
258+
" timeout: 10s\n" +
259+
" connection:\n" +
260+
" connectTimeout: 10s\n" +
261+
" initQueryTimeout: 10s\n" +
262+
" elasticsearch.connection-timeout: '1000'\n" +
263+
" elasticsearch.webclient.max-in-memory-size: '122'\n" +
264+
" elasticsearch.password: abc\n" +
265+
" elasticsearch.socket-timeout: '100'\n" +
266+
" elasticsearch.username: testUser\n" +
267+
" sql.init.data-locations: testdata\n" +
268+
" sql.init.password: password\n" +
269+
" sql.init.username: sa\n" +
270+
" sql.init.mode: mode1\n" +
271+
" sql.init.platform: pls\n" +
272+
" sql.init.schema-locations: table1\n" +
273+
" sql.init.password: password\n" +
274+
" sql.init.username: sa\n" +
275+
" sql.init.separator: k\n" +
276+
" sql.init.encoding: UTF-8\n" +
277+
"server.reactive.session.cookie.same-site: 'true'\n");
255278
}
256279

257280

258281
private void verifyPropertyConfigurationUpdate() {
259282

260283
String applicationProperties = loadFile(Path.of("src/main/resources/application.properties"));
261284
assertThat(applicationProperties).isEqualTo(
262-
"spring.elasticsearch.connection-timeout=1000\n" +
263-
"spring.elasticsearch.webclient.max-in-memory-size=122\n" +
264-
"spring.elasticsearch.password=abc\n" +
265-
"spring.elasticsearch.socket-timeout=100\n" +
266-
"spring.elasticsearch.username=testUser\n" +
267-
"\n" +
268-
"spring.sql.init.data-locations=testdata\n" +
269-
"spring.sql.init.password=password\n" +
270-
"spring.sql.init.username=username\n" +
271-
"spring.sql.init.mode=mode1\n" +
272-
"spring.sql.init.platform=pls\n" +
273-
"spring.sql.init.schema-locations=table1\n" +
274-
"spring.sql.init.password=password2\n" +
275-
"spring.sql.init.username=username2\n" +
276-
"spring.sql.init.separator=k\n" +
277-
"spring.sql.init.encoding=UTF-8\n" +
278-
"\n" +
279-
"spring.elasticsearch.connection-timeout=1\n" +
280-
"spring.elasticsearch.password=testpassword\n" +
281-
"spring.elasticsearch.socket-timeout=2\n" +
282-
"spring.elasticsearch.restclient.sniffer.delay-after-failure=3\n" +
283-
"spring.elasticsearch.restclient.sniffer.interval=4\n" +
284-
"spring.elasticsearch.username=username\n" +
285-
"\n" +
286-
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.entity-id=https://idpone.com\n" +
287-
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.sso-url=https://idpone.com\n" +
288-
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.verification.credentials.certificate-location=classpath:saml/idpone.crt\n" +
289-
"\n" +
290-
"server.reactive.session.cookie.same-site=true\n" +
291-
"\n" +
292-
"spring.datasource.url=jdbc:h2:mem:testdb\n" +
293-
"spring.datasource.driverClassName=org.h2.Driver\n" +
294-
"spring.datasource.username=sa\n" +
295-
"spring.datasource.password=password\n" +
296-
"spring.jpa.database-platform=org.hibernate.dialect.H2Dialect\n" +
297-
"\n" +
298-
"spring.cassandra.keyspace-name=testKeySpace\n" +
299-
"spring.cassandra.port=9042\n" +
300-
"spring.cassandra.contact-points=localhost\n" +
301-
"spring.cassandra.username=testusername\n" +
302-
"spring.cassandra.schema-action=NONE\n" +
303-
"spring.cassandra.request.timeout=10s\n" +
304-
"spring.cassandra.connection.connect-timeout=10s\n" +
305-
"spring.cassandra.connection.init-query-timeout=10s\n");
285+
"spring.elasticsearch.connection-timeout=1000\n" +
286+
"spring.elasticsearch.webclient.max-in-memory-size=122\n" +
287+
"spring.elasticsearch.password=abc\n" +
288+
"spring.elasticsearch.socket-timeout=100\n" +
289+
"spring.elasticsearch.username=testUser\n" +
290+
"\n" +
291+
"spring.sql.init.data-locations=testdata\n" +
292+
"spring.sql.init.password=password\n" +
293+
"spring.sql.init.username=username\n" +
294+
"spring.sql.init.mode=mode1\n" +
295+
"spring.sql.init.platform=pls\n" +
296+
"spring.sql.init.schema-locations=table1\n" +
297+
"spring.sql.init.password=password2\n" +
298+
"spring.sql.init.username=username2\n" +
299+
"spring.sql.init.separator=k\n" +
300+
"spring.sql.init.encoding=UTF-8\n" +
301+
"\n" +
302+
"spring.elasticsearch.connection-timeout=1\n" +
303+
"spring.elasticsearch.password=testpassword\n" +
304+
"spring.elasticsearch.socket-timeout=2\n" +
305+
"spring.elasticsearch.restclient.sniffer.delay-after-failure=3\n" +
306+
"spring.elasticsearch.restclient.sniffer.interval=4\n" +
307+
"spring.elasticsearch.username=username\n" +
308+
"\n" +
309+
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.entity-id=https://idpone.com\n" +
310+
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.sso-url=https://idpone.com\n" +
311+
"spring.security.saml2.relyingparty.registration.idpone.assertingparty.verification.credentials.certificate-location=classpath:saml/idpone.crt\n" +
312+
"\n" +
313+
"server.reactive.session.cookie.same-site=true\n" +
314+
"\n" +
315+
"spring.datasource.url=jdbc:h2:mem:testdb\n" +
316+
"spring.datasource.driverClassName=org.h2.Driver\n" +
317+
"spring.datasource.username=sa\n" +
318+
"spring.datasource.password=password\n" +
319+
"spring.jpa.database-platform=org.hibernate.dialect.H2Dialect\n" +
320+
"\n" +
321+
"spring.cassandra.keyspace-name=testKeySpace\n" +
322+
"spring.cassandra.port=9042\n" +
323+
"spring.cassandra.contact-points=localhost\n" +
324+
"spring.cassandra.username=testusername\n" +
325+
"spring.cassandra.schema-action=NONE\n" +
326+
"spring.cassandra.request.timeout=10s\n" +
327+
"spring.cassandra.connection.connect-timeout=10s\n" +
328+
"spring.cassandra.connection.init-query-timeout=10s\n" +
329+
"logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS\n" +
330+
"management.endpoints.jmx.exposure.include=*\n");
306331
}
307332

308333
private void verifyParentPomVersion() {
309334
Xml.Document mavenAsXMLDocument = getRootBuildFile();
310335

311-
Xml.Tag parentTag =mavenAsXMLDocument
336+
Xml.Tag parentTag = mavenAsXMLDocument
312337
.getRoot()
313338
.getChildren("parent").get(0);
314339

@@ -317,7 +342,7 @@ private void verifyParentPomVersion() {
317342
String groupId = parentTag.getChildValue("groupId").get();
318343
String artifactId = parentTag.getChildValue("artifactId").get();
319344

320-
assertThat(version).isEqualTo("3.0.0-M3");
345+
assertThat(version).isEqualTo("3.0.0");
321346
assertThat(groupId).isEqualTo("org.springframework.boot");
322347
assertThat(artifactId).isEqualTo("spring-boot-starter-parent");
323348
}

components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/migration/sbu30-migrate-to-jakarta-packages.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
- name: sbu30-migrate-javax-to-jakarta
1+
- name: sbu30-migrate-to-jakarta-packages
22
description: Spring boot 3.0 Upgrade - Migrate javax packages to new jakarta packages
33
condition:
44
type: org.springframework.sbm.common.migration.conditions.TrueCondition
@@ -9,4 +9,4 @@
99
type: org.springframework.sbm.boot.common.conditions.IsSpringBootProject
1010
versionPattern: "3\\.0\\..*"
1111
description: Replace javax with new jakarta packages
12-
openRewriteRecipeName: org.openrewrite.java.migrate.JavaxMigrationToJakarta
12+
openRewriteRecipeName: org.openrewrite.java.migrate.JavaxMigrationToJakarta

components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@
132132
contributors:
133133
- "Fabian Krüger[@fabapp2]"
134134

135+
- title: Upgrade to Jakarta EE 10
136+
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.UpgradeSpringBootVersionHelper
137+
change: |-
138+
Jakarta EE Upgrade, usage of dependency coordinate changes from `javax.*` to `jakarta.*`
139+
affected: |-
140+
Upgrade application to support Jakarta EE upgrade
141+
remediation:
142+
description: |-
143+
Whenever Spring Boot depends on a Jakarta EE specification, Spring Boot 3.0 has upgraded to the version that is included in Jakarta EE 10. For example, Spring Boot 3.0 uses the Servlet 6.0 and JPA 3.1 specifications.
144+
If you are managing your own dependencies, and aren’t relying on our starter POMs, you should ensure that you have updated your Maven or Gradle file appropriately. You need to be especially careful that older Java EE dependencies are no longer directly or transitively used in your build. For example, if you should always be using jakarta.servlet:jakarta.servlet-api and not javax.servlet:javax.servlet-api.
145+
As well as dependency coordinate changes, Jakarta EE now uses jakarta packages rather than javax. Once you’ve update your dependencies you may find that import statements in your project need to be updated.
146+
recipe: sbu30-migrate-to-jakarta-packages
147+
githubIssue: 723
148+
contributors:
149+
- "Fabian Krüger[@fabapp2]"
150+
- "Sandeep Nagaraj[@sanagaraj-pivotal]"
135151

136152
- title: Actuator Endpoints Sanitization
137153
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ActuatorEndpointsSanitizationHelper
@@ -1678,4 +1694,4 @@
16781694
footer: |-
16791695
We want to say thank you to all Contributors:
16801696
1681-
Generated by Spring Boot Migrator (experimental)
1697+
Generated by Spring Boot Migrator (experimental)

components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,6 @@
160160
description: Remove redundant @ConstructorBinding annotations when applicable
161161
recipeList:
162162
- org.openrewrite.java.spring.boot3.RemoveConstructorBindingAnnotation
163-
- type: org.springframework.sbm.engine.recipe.OpenRewriteNamedRecipeAdapter
164-
condition:
165-
type: org.springframework.sbm.boot.common.conditions.IsSpringBootProject
166-
versionPattern: "3\\.0\\..*"
167-
description: Replace javax with new jakarta packages
168-
openRewriteRecipeName: org.openrewrite.java.migrate.JavaxMigrationToJakarta
169163
170164
- type: org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapter
171165
condition:
@@ -668,4 +662,4 @@
668662
- type: org.springframework.sbm.boot.upgrade_27_30.actions.Boot_27_30_JmxEndpointExposureAction
669663
description: "Sets JMX endpoint exposure include to *"
670664
condition:
671-
type: org.springframework.sbm.boot.upgrade_27_30.conditions.JmxEndpointExposureCondition
665+
type: org.springframework.sbm.boot.upgrade_27_30.conditions.JmxEndpointExposureCondition

0 commit comments

Comments
 (0)