Skip to content

Commit f041383

Browse files
authored
Fix MockWebServer Dispatcher return type and RecordedRequest renames (#972)
* Fix MockWebServer Dispatcher return type and RecordedRequest renames Restore the `MockResponse` return type on `Dispatcher.dispatch()` overrides after the blanket `MockResponse` → `MockResponse.Builder` rename, wrapping return expressions with `.build()`. Also rename `RecordedRequest.getPath()` → `getTarget()` and `getRequestUrl()` → `getUrl()` to match mockwebserver3 5.x. * Prevent Dispatcher.dispatch() misconversion instead of correcting after Retarget UpdateMockWebServerDispatcher to match OLD (okhttp3.mockwebserver.*) types and run it before the blanket ChangeType, so dispatch() is pinned to mockwebserver3.MockResponse up front rather than reverted post-hoc. * Use JavaTemplate to replace dispatch() return type Drop the manual J.Identifier construction in favor of a JavaTemplate replace, which delegates type attribution to the parser and removes the Tree/Collections imports. * Regenerate recipes.csv for UpdateMockWebServerDispatcher * Use MethodMatcher for dispatch() override detection
1 parent 13f0a17 commit f041383

4 files changed

Lines changed: 204 additions & 10 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright 2026 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.testing.junit5;
17+
18+
import lombok.Getter;
19+
import org.openrewrite.Cursor;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.Preconditions;
22+
import org.openrewrite.Recipe;
23+
import org.openrewrite.TreeVisitor;
24+
import org.openrewrite.java.JavaIsoVisitor;
25+
import org.openrewrite.java.JavaParser;
26+
import org.openrewrite.java.JavaTemplate;
27+
import org.openrewrite.java.MethodMatcher;
28+
import org.openrewrite.java.search.UsesType;
29+
import org.openrewrite.java.tree.Expression;
30+
import org.openrewrite.java.tree.Flag;
31+
import org.openrewrite.java.tree.J;
32+
import org.openrewrite.java.tree.JavaType;
33+
import org.openrewrite.java.tree.TypeTree;
34+
import org.openrewrite.java.tree.TypeUtils;
35+
36+
import java.util.List;
37+
38+
public class UpdateMockWebServerDispatcher extends Recipe {
39+
private static final String OLD_DISPATCHER_FQN = "okhttp3.mockwebserver.Dispatcher";
40+
private static final String OLD_RECORDED_REQUEST_FQN = "okhttp3.mockwebserver.RecordedRequest";
41+
private static final String OLD_MOCK_RESPONSE_FQN = "okhttp3.mockwebserver.MockResponse";
42+
private static final String NEW_MOCK_RESPONSE_FQN = "mockwebserver3.MockResponse";
43+
private static final String NEW_MOCK_RESPONSE_BUILDER_FQN = "mockwebserver3.MockResponse$Builder";
44+
private static final MethodMatcher DISPATCH_MATCHER = new MethodMatcher(
45+
OLD_DISPATCHER_FQN + " dispatch(" + OLD_RECORDED_REQUEST_FQN + ")", true);
46+
47+
@Getter
48+
final String displayName = "Preserve `MockResponse` return type for `Dispatcher.dispatch()` overrides";
49+
50+
@Getter
51+
final String description = "In mockwebserver3 5.x, `Dispatcher.dispatch()` returns `MockResponse`, not `MockResponse.Builder`. " +
52+
"Pre-pin the return type to `mockwebserver3.MockResponse` and wrap return expressions with `.build()`, so the subsequent blanket `MockResponse` → `Builder` type change leaves `dispatch()` alone.";
53+
54+
@Override
55+
public TreeVisitor<?, ExecutionContext> getVisitor() {
56+
return Preconditions.check(new UsesType<>(OLD_DISPATCHER_FQN, false), new JavaIsoVisitor<ExecutionContext>() {
57+
@Override
58+
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
59+
J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx);
60+
if (!DISPATCH_MATCHER.matches(m.getMethodType())) {
61+
return m;
62+
}
63+
TypeTree rte = m.getReturnTypeExpression();
64+
if (rte == null) {
65+
return m;
66+
}
67+
if (!TypeUtils.isOfClassType(rte.getType(), OLD_MOCK_RESPONSE_FQN)) {
68+
return m;
69+
}
70+
71+
JavaType.Class mockResponseType = JavaType.ShallowClass.build(NEW_MOCK_RESPONSE_FQN);
72+
JavaType.Method buildMethodType = new JavaType.Method(
73+
null,
74+
Flag.Public.getBitMask() | Flag.Final.getBitMask(),
75+
JavaType.ShallowClass.build(NEW_MOCK_RESPONSE_BUILDER_FQN),
76+
"build",
77+
mockResponseType,
78+
(List<String>) null,
79+
null,
80+
null,
81+
null,
82+
null,
83+
null
84+
);
85+
86+
// Wrap return expressions with .build(). The outer check already guarantees
87+
// this is a dispatch override declared to return old MockResponse — every return
88+
// must become a built MockResponse in v5. Expression types may already be partially
89+
// retyped to Builder by prior ChangeMethodInvocationReturnType sub-recipes, so we
90+
// don't gate on the expression's current type.
91+
m = (J.MethodDeclaration) new JavaIsoVisitor<ExecutionContext>() {
92+
@Override
93+
public J.Return visitReturn(J.Return aReturn, ExecutionContext c) {
94+
J.Return r = super.visitReturn(aReturn, c);
95+
Expression expr = r.getExpression();
96+
if (expr == null) {
97+
return r;
98+
}
99+
J.MethodInvocation wrapped = JavaTemplate
100+
.builder("#{any(" + OLD_MOCK_RESPONSE_FQN + ")}.build()")
101+
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(c, "mockwebserver-4.10", "okhttp-4.10"))
102+
.build()
103+
.apply(new Cursor(getCursor(), expr), expr.getCoordinates().replace(), expr);
104+
wrapped = wrapped.withMethodType(buildMethodType)
105+
.withName(wrapped.getName().withType(buildMethodType));
106+
return r.withExpression(wrapped);
107+
}
108+
}.visitNonNull(m, ctx, getCursor().getParentTreeCursor());
109+
110+
// Pre-pin the return type to mockwebserver3.MockResponse so the blanket
111+
// ChangeType(MockResponse -> Builder) that runs next won't match it.
112+
m = JavaTemplate.builder("MockResponse")
113+
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockwebserver3"))
114+
.imports(NEW_MOCK_RESPONSE_FQN)
115+
.build()
116+
.apply(new Cursor(getCursor().getParentOrThrow(), m),
117+
((Expression) m.getReturnTypeExpression()).getCoordinates().replace());
118+
JavaType.Method methodType = m.getMethodType();
119+
if (methodType != null) {
120+
JavaType.Method updatedMethodType = methodType.withReturnType(mockResponseType);
121+
m = m.withMethodType(updatedMethodType)
122+
.withName(m.getName().withType(updatedMethodType));
123+
}
124+
maybeAddImport(NEW_MOCK_RESPONSE_FQN);
125+
return m;
126+
}
127+
128+
});
129+
}
130+
}

src/main/java/org/openrewrite/java/testing/junit5/UpdateMockWebServerMockResponse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ public List<Recipe> getRecipeList() {
103103
recipes.add(new ChangeMethodInvocationReturnType(methodPattern, NEW_MOCKRESPONSE_FQN_BUILDER.replace("$", ".")));
104104
recipes.add(new ChangeMethodName(methodPattern, rep.getValue(), true, false));
105105
}
106+
recipes.add(new ChangeMethodName("okhttp3.mockwebserver.RecordedRequest getPath()", "getTarget", true, false));
107+
recipes.add(new ChangeMethodName("okhttp3.mockwebserver.RecordedRequest getRequestUrl()", "getUrl", true, false));
108+
// Pin Dispatcher.dispatch() return type before the blanket ChangeType below would misconvert it to Builder.
109+
recipes.add(new UpdateMockWebServerDispatcher());
106110
recipes.add(new ChangeType(OLD_MOCKRESPONSE_FQN, NEW_MOCKRESPONSE_FQN_BUILDER, true));
107111
recipes.add(new ChangePackage("okhttp3.mockwebserver", "mockwebserver3", false));
108112
return recipes;

0 commit comments

Comments
 (0)