Skip to content

Commit 38f5ae7

Browse files
authored
120 fix demo for spring boot 24 25 upgrade (#122)
Provides demo for Spring Boot 2.4 to 2.5 upgrade Fixes some bugs in Spring Boot 2.4 to 2.5 upgrade
1 parent 8767c83 commit 38f5ae7

File tree

37 files changed

+442
-838
lines changed

37 files changed

+442
-838
lines changed

applications/spring-shell/pom.xml

+10-3
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,19 @@
160160
<version>${spring-boot.version}</version>
161161
<executions>
162162
<execution>
163-
<configuration>
164-
<mainClass>org.springframework.sbm.SpringShellApplication</mainClass>
165-
</configuration>
163+
<id>repackage</id>
166164
<goals>
167165
<goal>repackage</goal>
168166
</goals>
167+
<configuration>
168+
<requiresUnpack>
169+
<dependency>
170+
<groupId>org.asciidoctor</groupId>
171+
<artifactId>asciidoctorj</artifactId>
172+
</dependency>
173+
</requiresUnpack>
174+
<mainClass>org.springframework.sbm.SpringShellApplication</mainClass>
175+
</configuration>
169176
</execution>
170177
</executions>
171178
</plugin>

changelog.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1-
## [0.11.0](https://github.com/spring-projects-experimental/spring-boot-migrator/releases/tag/0.10.0) -
1+
## [0.11.0](https://github.com/spring-projects-experimental/spring-boot-migrator/releases/tag/0.11.0) -
22

33
### Adds
44
- Unmarshalling ejb-jar.xml for EJB 2.1 (#62)
55
- Demo for Mule to Boot migration (#80)
6+
- Demo for Spring Boot 2.4 to 2.5 upgrade (#120)
7+
- New Mule 3.9 components and schemas (#110, #95, #87)
8+
- Bumped some dependency versions
69

710
### Fixes
811
- Paths and CLI rendering under Windows (#58)
912
- Fix SBM when using Windows (#58)
1013
- Bump some dependency versions, removes CVEs
14+
- SBM generates Asciidoc report when started as jar
15+
- 2.4 to 2.5 upgrade does not randomly fail anymore
16+
- Full Windows support (#91)
17+
- Builds on Mac M1 (#114)
1118

1219
## [0.10.0](https://github.com/spring-projects-experimental/spring-boot-migrator/releases/tag/0.10.0) - 2022-03-28
1320

components/sbm-core/src/main/java/org/springframework/sbm/engine/recipe/Action.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ default void applyWithStatusEvent(ProjectContext context) {
3636
try {
3737
apply(context);
3838
} catch(Exception e) {
39-
throw new ActionFailedException("'"+this.getDescription()+"' failed: " + e.getMessage(), e);
39+
throw new ActionFailedException("Action ["+ getClass().getName()+"] with description '"+this.getDescription()+"' failed: " + e.getMessage(), e);
4040
}
4141
if (eventPublisher != null) {
4242
eventPublisher.publishEvent(new ActionFinishedEvent(getDescription()));

components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteType.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
*/
1616
package org.springframework.sbm.java.impl;
1717

18+
import org.openrewrite.java.tree.JavaSourceFile;
19+
import org.openrewrite.marker.SearchResult;
1820
import org.springframework.sbm.java.api.*;
1921
import org.springframework.sbm.java.migration.visitor.RemoveImplementsVisitor;
2022
import org.springframework.sbm.java.refactoring.JavaRefactoring;
23+
import org.springframework.sbm.openrewrite.RewriteExecutionContext;
2124
import org.springframework.sbm.project.resource.RewriteSourceFileHolder;
2225
import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe;
2326
import org.springframework.sbm.support.openrewrite.java.AddAnnotationVisitor;
@@ -278,9 +281,13 @@ public boolean hasMethod(String methodPattern) {
278281
// TODO: parse and validate methodPattern
279282
methodPattern = this.getFullyQualifiedName() + " " + methodPattern;
280283
DeclaresMethod<ExecutionContext> declaresMethod = new DeclaresMethod(new MethodMatcher(methodPattern, true));
281-
List<RewriteSourceFileHolder<J.CompilationUnit>> matches = refactoring.find(rewriteSourceFileHolder, new GenericOpenRewriteRecipe<>(() -> declaresMethod));
284+
JavaSourceFile javaSourceFile = declaresMethod.visitJavaSourceFile(rewriteSourceFileHolder.getSourceFile(), new RewriteExecutionContext());
285+
Optional<SearchResult> match = javaSourceFile.getMarkers().findFirst(SearchResult.class);
286+
return match.isPresent() ? true : false;
287+
// this.getClassDeclaration()
288+
// List<RewriteSourceFileHolder<J.CompilationUnit>> matches = refactoring.find(rewriteSourceFileHolder, new GenericOpenRewriteRecipe<>(() -> declaresMethod));
282289
// TODO: searches in all classes, either filter result list or provide findInCurrent() or similar
283-
return !matches.isEmpty();
290+
// return !matches.isEmpty();
284291
}
285292

286293
@Override

components/sbm-core/src/main/java/org/springframework/sbm/java/impl/ProjectJavaSourcesImpl.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.sbm.java.impl;
1717

18+
import org.openrewrite.java.tree.TypeTree;
1819
import org.springframework.sbm.java.api.MethodCall;
1920
import org.springframework.sbm.java.api.JavaSource;
2021
import org.springframework.sbm.java.api.JavaSourceAndType;
@@ -91,6 +92,11 @@ public Optional<? extends JavaSource> findJavaSourceDeclaringType(String fqName)
9192
.findFirst();
9293
}
9394

95+
/**
96+
* Find method calls matching given {@code methodPattern}.
97+
*
98+
* @param methodPattern the pattern for the method like {@code com.example.TheType theMethod(com.example.Arg1, com.example.Arg2)}
99+
*/
94100
@Override
95101
public List<MethodCall> findMethodCalls(String methodPattern) {
96102
List<MethodCall> matches = new ArrayList<>();
@@ -120,15 +126,17 @@ public List<JavaSourceAndType> findTypesImplementing(String type) {
120126

121127
private boolean hasTypeImplementing(J.ClassDeclaration c, String type) {
122128
try {
123-
return c.getImplements() != null &&
124-
c.getImplements()
129+
List<TypeTree> implmeneting = c.getImplements();
130+
return implmeneting != null &&
131+
implmeneting
125132
.stream()
126133
.anyMatch(intaface -> {
127134
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(
128135
intaface.getType()
129136
);
130137
if(fullyQualified == null) {
131-
log.error("Could not resolve implemented type '" + ((J.Identifier)intaface).getSimpleName() + "'");
138+
String simpleName = ((J.Identifier) ((J.ParameterizedType) intaface).getClazz()).getSimpleName();
139+
log.error("Could not resolve implemented type '" + simpleName + "'");
132140
return false;
133141
}
134142
return fullyQualified

components/sbm-core/src/main/java/org/springframework/sbm/project/parser/DependencyHelper.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import lombok.extern.slf4j.Slf4j;
1919
import org.openrewrite.maven.cache.LocalMavenArtifactCache;
2020
import org.openrewrite.maven.cache.ReadOnlyLocalMavenArtifactCache;
21+
import org.openrewrite.maven.internal.MavenDownloadingException;
2122
import org.openrewrite.maven.internal.MavenParsingException;
2223
import org.openrewrite.maven.tree.MavenRepository;
2324
import org.openrewrite.maven.tree.Pom;
@@ -55,10 +56,10 @@ public List<Path> downloadArtifacts(Set<Pom.Dependency> dependencies) {
5556

5657
private static Consumer<Throwable> createErrorHandler() {
5758
Consumer<Throwable> errorConsumer = (t) -> {
58-
if (t instanceof MavenParsingException) {
59+
if (MavenParsingException.class.isInstance(t) || MavenDownloadingException.class.isInstance(t)) {
5960
log.error(t.getMessage());
6061
} else {
61-
t.printStackTrace();
62+
throw new RuntimeException(t);
6263
}
6364
};
6465
return errorConsumer;

components/sbm-core/src/test/java/org/springframework/sbm/build/api/ApplicationModuleTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ void testGetModuleResources() {
7878
.addProjectResource("pom.xml", parentPom)
7979
.addProjectResource("module1/pom.xml", pom1)
8080
.addProjectResource("module2/pom.xml", pom2)
81-
.addJavaSource("module1/src/main/java", javaSource2)
82-
.addJavaSource("module2/src/main/java", javaSource3)
81+
.withJavaSource("module1/src/main/java", javaSource2)
82+
.withJavaSource("module2/src/main/java", javaSource3)
8383
.build();
8484

8585
ApplicationModule parentModule = context.getApplicationModules().getModule(Path.of(""));

components/sbm-core/src/test/java/org/springframework/sbm/project/openrewrite/RewriteSourceFileHolderTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class RewriteSourceFileHolderTest {
3131
public static final String SOURCE_CODE = "package com.foo.bar; class Foo{}";
3232

3333
private ProjectContext projectContext = TestProjectContext.buildProjectContext()
34-
.addJavaSource("src/main/java", SOURCE_CODE)
34+
.withJavaSource("src/main/java", SOURCE_CODE)
3535
.build();
3636

3737
private RewriteSourceFileHolder<J.CompilationUnit> sut = projectContext
@@ -43,7 +43,7 @@ class RewriteSourceFileHolderTest {
4343
@Test
4444
void replaceWithShouldMarkAsChanged_whenContentDiffers() {
4545
J.CompilationUnit newSourceFile = TestProjectContext.buildProjectContext()
46-
.addJavaSource("src/main/java", "package com.foo.bar; class Bar{}")
46+
.withJavaSource("src/main/java", "package com.foo.bar; class Bar{}")
4747
.build()
4848
.getProjectJavaSources()
4949
.list()
@@ -61,7 +61,7 @@ void replaceWithShouldMarkAsChanged_whenContentDiffers() {
6161
void replaceWithShouldNotMarkAsChanged_WhenContentEquals() {
6262
String sourceCode = "class Foo{}";
6363
J.CompilationUnit newSourceFile = TestProjectContext.buildProjectContext()
64-
.addJavaSource("src/main/java", SOURCE_CODE)
64+
.withJavaSource("src/main/java", SOURCE_CODE)
6565
.build()
6666
.getProjectJavaSources()
6767
.list()

components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ public Builder addRegistrar(ProjectResourceWrapper projectResourceWrapper) {
289289
* The source Path is ' src/main/java' in the root module and the path inside is calculated from package declaration if exists.
290290
*/
291291
@Deprecated
292-
public Builder addJavaSource(String sourceCode) {
292+
public Builder withJavaSource(String sourceCode) {
293293
return withJavaSources(sourceCode);
294294
}
295295

296296

297-
public Builder addJavaSource(Path sourcePathDir, String sourceCode) {
297+
public Builder withJavaSource(Path sourcePathDir, String sourceCode) {
298298
if (sourcePathDir.isAbsolute()) {
299299
throw new IllegalArgumentException("Source path must be relative to project root dir.");
300300
}
@@ -304,8 +304,8 @@ public Builder addJavaSource(Path sourcePathDir, String sourceCode) {
304304
return this;
305305
}
306306

307-
public Builder addJavaSource(String sourcePath, String sourceCode) {
308-
return addJavaSource(Path.of(sourcePath), sourceCode);
307+
public Builder withJavaSource(String sourcePath, String sourceCode) {
308+
return withJavaSource(Path.of(sourcePath), sourceCode);
309309
}
310310

311311
public Builder addJavaSourceToModule(String modulePath, String sourceCode) {

components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/filter/SpringDataJpaAnalyzer.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ public List<MethodCall> findCallsToGetOneMethod(ProjectContext context) {
3131

3232
public List<MatchingMethod> getJpaRepositoriesWithGetByIdMethod(ProjectContext context) {
3333
String jpaRepositoryInterface = "org.springframework.data.jpa.repository.JpaRepository";
34-
return getJpaRepositoriesWithGetByIdMethod(context, jpaRepositoryInterface);
35-
}
36-
37-
private List<MatchingMethod> getJpaRepositoriesWithGetByIdMethod(ProjectContext context, String jpaRepositoryInterface) {
3834
List<JavaSourceAndType> jpaRepositories = context.getProjectJavaSources().findTypesImplementing(jpaRepositoryInterface);
3935
// FIXME: type of PK must be retrieved, moves to rewrite when these migrations are provided as OpenRewrite recipes
4036
String methodPattern = "getById(java.lang.Long)";
41-
return findRepositoriesDeclaring(jpaRepositories, methodPattern);
37+
return jpaRepositories.stream()
38+
.filter(jat -> jat.getType().hasMethod(methodPattern))
39+
.map(jat -> {
40+
return new MatchingMethod(jat, methodPattern, jat.getType().getMethod(methodPattern));
41+
})
42+
.collect(Collectors.toList());
43+
//return findRepositoriesDeclaring(jpaRepositories, methodPattern);
4244
}
4345

4446
private List<MatchingMethod> findRepositoriesDeclaring(List<JavaSourceAndType> jpaRepositories, String methodPattern) {

components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_Introduction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import java.nio.file.Path;
2525
import java.util.Date;
26+
import java.util.Optional;
2627

2728
public class Boot_24_25_Introduction implements UpgradeSectionBuilder {
2829
@Override
@@ -39,7 +40,11 @@ public Section build(ProjectContext projectContext) {
3940
String groupId = buildFile.getGroupId();
4041
String artifactId = buildFile.getArtifactId();
4142
String version = buildFile.getVersion();
42-
String bootVersion = buildFile.getDeclaredDependencies().stream().filter(d -> d.getGroupId().equals("org.springframework.boot")).map(d -> d.getVersion()).findFirst().get();
43+
Optional<String> foundSpringVersion = buildFile.getDeclaredDependencies().stream().filter(d -> d.getGroupId().equals("org.springframework.boot")).map(d -> d.getVersion()).findFirst();
44+
if(foundSpringVersion.isEmpty()) {
45+
throw new RuntimeException(String.format("Could not retrieve Spring version from declared dependencies in %s", buildFile.getAbsolutePath()));
46+
}
47+
String bootVersion = foundSpringVersion.get();
4348

4449
IntroductionSection introductionSection = IntroductionSection.builder()
4550
.projectName(applicationName)

components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_24_25/report/Boot_24_25_SqlScriptDataSourceInitialization.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.sbm.boot.properties.api.SpringBootApplicationProperties;
2626
import org.springframework.sbm.boot.properties.search.SpringBootApplicationPropertiesResourceListFilter;
2727

28+
import java.util.Comparator;
2829
import java.util.List;
2930

3031
public class Boot_24_25_SqlScriptDataSourceInitialization implements UpgradeSectionBuilder {
@@ -45,7 +46,7 @@ public Section build(ProjectContext projectContext) {
4546

4647
Table.Builder tableBuilder = Table.builder();
4748
tableBuilder.headerCols("File", "Old (2.4)", "New (2.5)");
48-
49+
deprecatedProperties.sort(Comparator.comparing(SqlScriptDataSourceInitializationPropertiesAnalyzer.DeperecatedPropertyMatch::getDeprecatedPropery));
4950
for (SqlScriptDataSourceInitializationPropertiesAnalyzer.DeperecatedPropertyMatch match : deprecatedProperties) {
5051
tableBuilder.row("`" + match.getPath() + "`", "`" + match.getDeprecatedPropery() + "`", "`" + match.getNewProperty() + "`");
5152
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2021 - 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.sbm.boot.upgrade_24_25.filter;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.springframework.sbm.engine.context.ProjectContext;
20+
import org.springframework.sbm.java.api.MethodCall;
21+
import org.springframework.sbm.java.api.ProjectJavaSources;
22+
import org.springframework.sbm.project.resource.TestProjectContext;
23+
24+
import java.util.List;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.mockito.Mockito.*;
28+
29+
class SpringDataJpaAnalyzerTest {
30+
@Test
31+
void testFindCallsToGetOneMethod() {
32+
List<MethodCall> foundCalls = List.of();
33+
ProjectContext context = mock(ProjectContext.class);
34+
ProjectJavaSources projectJavaSources = mock(ProjectJavaSources.class);
35+
when(context.getProjectJavaSources()).thenReturn(projectJavaSources);
36+
when(projectJavaSources.findMethodCalls("org.springframework.data.jpa.repository.JpaRepository getOne(java.lang.Long)")).thenReturn(foundCalls);
37+
38+
SpringDataJpaAnalyzer sut = new SpringDataJpaAnalyzer();
39+
List<MethodCall> callsToGetOneMethod = sut.findCallsToGetOneMethod(context);
40+
assertThat(callsToGetOneMethod).isSameAs(foundCalls);
41+
}
42+
43+
@Test
44+
void testGetJpaRepositoriesWithGetByIdMethod() {
45+
String tag =
46+
"package com.example.springboot24to25example;\n" +
47+
"\n" +
48+
"import com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n" +
49+
"import lombok.Getter;\n" +
50+
"import lombok.Setter;\n" +
51+
"\n" +
52+
"import javax.persistence.Entity;\n" +
53+
"import javax.persistence.GeneratedValue;\n" +
54+
"import javax.persistence.Id;\n" +
55+
"\n" +
56+
"@Entity\n" +
57+
"@Getter\n" +
58+
"@Setter\n" +
59+
"@JsonIgnoreProperties({\"hibernateLazyInitializer\", \"handler\"})\n" +
60+
"public class Tag {\n" +
61+
" @Id\n" +
62+
" @GeneratedValue\n" +
63+
" private Long id;\n" +
64+
"\n" +
65+
" private String tag;\n" +
66+
"}";
67+
68+
String tagRepository =
69+
"package com.example.springboot24to25example;\n" +
70+
"\n" +
71+
"import org.springframework.data.jpa.repository.JpaRepository;\n" +
72+
"\n" +
73+
"public interface TagRepository extends JpaRepository<Tag, Long> {\n" +
74+
" public Tag getOne(Long id);\n" +
75+
"}";
76+
77+
String task =
78+
"package com.example.springboot24to25example;\n" +
79+
"\n" +
80+
"import lombok.Getter;\n" +
81+
"import lombok.Setter;\n" +
82+
"\n" +
83+
"import javax.persistence.Entity;\n" +
84+
"import javax.persistence.GeneratedValue;\n" +
85+
"import javax.persistence.Id;\n" +
86+
"\n" +
87+
"@Entity\n" +
88+
"@Getter\n" +
89+
"@Setter\n" +
90+
"public class Task {\n" +
91+
"\n" +
92+
" @Id\n" +
93+
" @GeneratedValue\n" +
94+
" private Long id;\n" +
95+
"\n" +
96+
" private String name;\n" +
97+
"\n" +
98+
" private boolean done;\n" +
99+
"}";
100+
101+
String taskRepository =
102+
"import org.springframework.data.jpa.repository.JpaRepository;\n" +
103+
"import org.springframework.data.jpa.repository.Query;\n" +
104+
"import org.springframework.data.repository.query.Param;\n" +
105+
"\n" +
106+
"public interface TaskRepository extends JpaRepository<Task, Long> {\n" +
107+
"\n" +
108+
" @Query(\"from Task t where t.id=:id\")\n" +
109+
" Task getById(@Param(\"id\") Long id);\n" +
110+
"\n" +
111+
"}";
112+
113+
ProjectContext context = TestProjectContext.buildProjectContext()
114+
.withJavaSource("src/main/java", tag)
115+
.withJavaSource("src/main/java", tagRepository)
116+
.withJavaSource("src/main/java", task)
117+
.withJavaSource("src/main/java", taskRepository)
118+
.withBuildFileHavingDependencies("org.springframework.boot:spring-boot-starter-data-jpa:2.4.12")
119+
.build();
120+
121+
SpringDataJpaAnalyzer sut = new SpringDataJpaAnalyzer();
122+
List<SpringDataJpaAnalyzer.MatchingMethod> match = sut.getJpaRepositoriesWithGetByIdMethod(context);
123+
assertThat(match).hasSize(1);
124+
}
125+
}

0 commit comments

Comments
 (0)