Skip to content

Commit c969e42

Browse files
wapkchchao.wang
and
chao.wang
authored
Add Recipe to migrate org.springframework.web.reactive.HandlerResult.setExceptionHandler method (#690)
* Add migration recipe for HandlerResult setExceptionHandler method * Add spring-web-6.1.8.jar to test classpath * Refactor migration for HandlerResult setExceptionHandler method to support inline and non-inline lambda functions * Refactor visitMethodInvocation to use context parameter for improved readability --------- Co-authored-by: chao.wang <[email protected]>
1 parent ace3ff3 commit c969e42

File tree

5 files changed

+229
-0
lines changed

5 files changed

+229
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Moderne Source Available License (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+
* <p>
8+
* https://docs.moderne.io/licensing/moderne-source-available-license
9+
* <p>
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.openrewrite.java.spring.framework;
17+
18+
import org.openrewrite.ExecutionContext;
19+
import org.openrewrite.Preconditions;
20+
import org.openrewrite.Recipe;
21+
import org.openrewrite.TreeVisitor;
22+
import org.openrewrite.java.JavaIsoVisitor;
23+
import org.openrewrite.java.JavaTemplate;
24+
import org.openrewrite.java.MethodMatcher;
25+
import org.openrewrite.java.search.UsesType;
26+
import org.openrewrite.java.tree.J;
27+
28+
public class MigrateHandlerResultSetExceptionHandlerMethod extends Recipe {
29+
30+
private static final String HandlerResult = "org.springframework.web.reactive.HandlerResult";
31+
32+
private static final MethodMatcher METHOD_MATCHER = new MethodMatcher(HandlerResult + " setExceptionHandler(java.util.function.Function)");
33+
34+
@Override
35+
public String getDisplayName() {
36+
return "Migrate `org.springframework.web.reactive.HandlerResult.setExceptionHandler` method";
37+
}
38+
39+
@Override
40+
public String getDescription() {
41+
return "`org.springframework.web.reactive.HandlerResult.setExceptionHandler(Function<Throwable, Mono<HandlerResult>>)` was deprecated, in favor of `setExceptionHandler(DispatchExceptionHandler)`.";
42+
}
43+
44+
@Override
45+
public TreeVisitor<?, ExecutionContext> getVisitor() {
46+
return Preconditions.check(new UsesType<>(HandlerResult, false), new JavaIsoVisitor<ExecutionContext>() {
47+
48+
@Override
49+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
50+
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
51+
if (METHOD_MATCHER.matches(m)) {
52+
if (m.getArguments().get(0) instanceof J.Identifier) {
53+
return JavaTemplate.builder("(exchange, ex) -> #{any()}.apply(ex)")
54+
.build()
55+
.apply(getCursor(), m.getCoordinates().replaceArguments(), m.getArguments().get(0));
56+
} else if (m.getArguments().get(0) instanceof J.Lambda) {
57+
return JavaTemplate.builder("(exchange, ex) -> #{any()}")
58+
.build()
59+
.apply(getCursor(), m.getCoordinates().replaceArguments(), ((J.Lambda) m.getArguments().get(0)).getBody());
60+
}
61+
}
62+
return m;
63+
}
64+
});
65+
}
66+
67+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Moderne Source Available License (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+
* <p>
8+
* https://docs.moderne.io/licensing/moderne-source-available-license
9+
* <p>
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.openrewrite.java.spring.framework;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.InMemoryExecutionContext;
21+
import org.openrewrite.java.JavaParser;
22+
import org.openrewrite.test.RecipeSpec;
23+
import org.openrewrite.test.RewriteTest;
24+
import org.openrewrite.test.TypeValidation;
25+
26+
import static org.openrewrite.java.Assertions.java;
27+
28+
class MigrateHandlerResultSetExceptionHandlerMethodTest implements RewriteTest {
29+
30+
@Override
31+
public void defaults(RecipeSpec spec) {
32+
spec
33+
.typeValidationOptions(TypeValidation.none())
34+
.recipe(new MigrateHandlerResultSetExceptionHandlerMethod())
35+
.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(),
36+
"reactor-core-3.6.+", "spring-webflux-6.1.+"));
37+
}
38+
39+
@DocumentExample
40+
@Test
41+
void migrateHandlerResultSetExceptionHandlerMethodParameterIsInlineLambdaFunction() {
42+
rewriteRun(
43+
// language=java
44+
java(
45+
"""
46+
import org.springframework.web.reactive.HandlerResult;
47+
import reactor.core.publisher.Mono;
48+
49+
class MyHandler {
50+
void configureHandler(HandlerResult result) {
51+
result.setExceptionHandler(ex -> Mono.empty());
52+
}
53+
}
54+
""",
55+
"""
56+
import org.springframework.web.reactive.HandlerResult;
57+
import reactor.core.publisher.Mono;
58+
59+
class MyHandler {
60+
void configureHandler(HandlerResult result) {
61+
result.setExceptionHandler((exchange, ex) -> Mono.empty());
62+
}
63+
}
64+
"""
65+
)
66+
);
67+
}
68+
69+
@Test
70+
void migrateHandlerResultSetExceptionHandlerMethodParameterIsNonInlineLambdaFunction() {
71+
rewriteRun(
72+
// language=java
73+
java(
74+
"""
75+
import org.springframework.web.reactive.HandlerResult;
76+
import reactor.core.publisher.Mono;
77+
78+
class MyHandler {
79+
void configureHandler(HandlerResult result) {
80+
result.setExceptionHandler(ex -> {
81+
// do something
82+
return Mono.empty();
83+
});
84+
}
85+
}
86+
""",
87+
"""
88+
import org.springframework.web.reactive.HandlerResult;
89+
import reactor.core.publisher.Mono;
90+
91+
class MyHandler {
92+
void configureHandler(HandlerResult result) {
93+
result.setExceptionHandler((exchange, ex) -> {
94+
// do something
95+
return Mono.empty();
96+
});
97+
}
98+
}
99+
"""
100+
)
101+
);
102+
}
103+
104+
@Test
105+
void migrateHandlerResultSetExceptionHandlerMethodParameterIsIdentifier() {
106+
rewriteRun(
107+
// language=java
108+
java(
109+
"""
110+
import org.springframework.web.reactive.HandlerResult;
111+
import reactor.core.publisher.Mono;
112+
113+
import java.util.function.Function;
114+
115+
class MyHandler {
116+
void configureHandler(HandlerResult result) {
117+
Function<Throwable, Mono<HandlerResult>> func = (ex -> Mono.empty());
118+
result.setExceptionHandler(func);
119+
}
120+
}
121+
""",
122+
"""
123+
import org.springframework.web.reactive.HandlerResult;
124+
import reactor.core.publisher.Mono;
125+
126+
import java.util.function.Function;
127+
128+
class MyHandler {
129+
void configureHandler(HandlerResult result) {
130+
Function<Throwable, Mono<HandlerResult>> func = (ex -> Mono.empty());
131+
result.setExceptionHandler((exchange, ex) -> func.apply(ex));
132+
}
133+
}
134+
"""
135+
)
136+
);
137+
}
138+
139+
@Test
140+
void migrateHandlerResultSetExceptionHandlerMethodParameterIsDispatchExceptionHandler() {
141+
rewriteRun(
142+
// language=java
143+
java(
144+
"""
145+
import org.springframework.web.reactive.HandlerResult;
146+
import reactor.core.publisher.Mono;
147+
148+
import java.util.function.Function;
149+
150+
class MyHandler {
151+
void configureHandler(HandlerResult result) {
152+
result.setExceptionHandler((exchange, ex) -> {
153+
// do something
154+
return Mono.empty();
155+
});
156+
}
157+
}
158+
"""
159+
)
160+
);
161+
}
162+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)