Skip to content

Commit 630c51b

Browse files
Reapplying paddings from arguments as they were prior to chaining .build(), and backpatching the parameter types onto the various method invocations. Feels like there could be a lot of improvement still with how this done, as it feels pretty hacky right now.
1 parent 94fd580 commit 630c51b

File tree

2 files changed

+150
-103
lines changed

2 files changed

+150
-103
lines changed

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

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,41 @@
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+
*/
116
package org.openrewrite.java.testing.junit5;
217

318
import org.jspecify.annotations.Nullable;
419
import org.openrewrite.*;
20+
import org.openrewrite.internal.ListUtils;
521
import org.openrewrite.java.*;
622
import org.openrewrite.java.format.AutoFormatVisitor;
723
import org.openrewrite.java.search.UsesType;
8-
import org.openrewrite.java.tree.J;
9-
import org.openrewrite.java.tree.TypeUtils;
24+
import org.openrewrite.java.style.IntelliJ;
25+
import org.openrewrite.java.style.WrappingAndBracesStyle;
26+
import org.openrewrite.java.tree.*;
27+
import org.openrewrite.style.LineWrapSetting;
28+
import org.openrewrite.style.NamedStyles;
29+
import org.openrewrite.style.Style;
1030

11-
import java.util.HashMap;
12-
import java.util.List;
13-
import java.util.Map;
14-
import java.util.UUID;
31+
import java.util.*;
1532
import java.util.stream.IntStream;
33+
import java.util.stream.Stream;
1634

1735
import static java.util.Collections.emptyList;
36+
import static java.util.Collections.emptySet;
1837
import static java.util.stream.Collectors.toList;
38+
import static org.openrewrite.java.tree.JavaType.ShallowClass.build;
1939

2040
public class UpdateMockWebServerMockResponse extends Recipe {
2141
private static final String OLD_MOCKRESPONSE_FQN = "okhttp3.mockwebserver.MockResponse";
@@ -25,6 +45,8 @@ public class UpdateMockWebServerMockResponse extends Recipe {
2545
private static final String OLD_MOCKRESPONSE_SETHEADERS = OLD_MOCKRESPONSE_FQN + " setHeaders(okhttp3.Headers)";
2646
private static final String NEW_MOCKRESPONSE_FQN = "mockwebserver3.MockResponse";
2747
private static final String NEW_MOCKRESPONSE_BUILDER_FQN = NEW_MOCKRESPONSE_FQN + "$Builder";
48+
private static final String OLD_MOCKWEBSERVER_FQN = "okhttp3.mockwebserver.MockWebServer";
49+
private static final String NEW_MOCKWEBSERVER_FQN = "mockwebserver3.MockWebServer";
2850

2951
@Override
3052
public String getDisplayName() {
@@ -40,7 +62,6 @@ public String getDescription() {
4062
public TreeVisitor<?, ExecutionContext> getVisitor() {
4163
return Preconditions.check(new UsesType<>(OLD_MOCKRESPONSE_FQN, false), new JavaIsoVisitor<ExecutionContext>() {
4264
private final Map<UUID, List<Integer>> methodInvocationsToAdjust = new HashMap<>();
43-
4465
@Override
4566
public @Nullable J visit(@Nullable Tree tree, ExecutionContext ctx) {
4667
J j = (J) tree;
@@ -51,8 +72,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInv, Ex
5172
List<Integer> indexes = IntStream.range(0, mi.getArguments().size())
5273
.filter(x -> TypeUtils.isAssignableTo(OLD_MOCKRESPONSE_FQN, mi.getArguments().get(x).getType()))
5374
.boxed().collect(toList());
54-
if (!indexes.isEmpty() && !methodInvocationsToAdjust.containsKey(mi.getId())) {
55-
methodInvocationsToAdjust.put(mi.getId(), indexes);
75+
if (!indexes.isEmpty()) {
76+
methodInvocationsToAdjust.putIfAbsent(mi.getId(), indexes);
5677
}
5778
return mi;
5879
}
@@ -82,14 +103,24 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInv, Ex
82103
NEW_MOCKRESPONSE_BUILDER_FQN,
83104
null
84105
).getVisitor().visit(j, ctx);
85-
j = new JavaIsoVisitor<ExecutionContext>() {
106+
// j = (J) new ChangeType(
107+
// OLD_MOCKRESPONSE_FQN,
108+
// NEW_MOCKRESPONSE_FQN,
109+
// null
110+
// ).getVisitor().visit(j, ctx);
111+
j = (J) new ChangeType(
112+
OLD_MOCKWEBSERVER_FQN,
113+
NEW_MOCKWEBSERVER_FQN,
114+
null
115+
).getVisitor().visit(j, ctx);
116+
return new JavaIsoVisitor<ExecutionContext>() {
86117
@Override
87118
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInv, ExecutionContext ctx) {
88119
J.MethodInvocation mi = super.visitMethodInvocation(methodInv, ctx);
89-
List<Integer> indexes = methodInvocationsToAdjust.getOrDefault(mi.getId(), emptyList());
90-
if (!indexes.isEmpty()) {
91-
methodInvocationsToAdjust.remove(mi.getId());
120+
List<Integer> indexes = methodInvocationsToAdjust.remove(mi.getId());
121+
if (indexes != null) {
92122
StringBuilder sb = new StringBuilder();
123+
List<JRightPadded<Expression>> oldArgs = mi.getPadding().getArguments().getPadding().getElements();
93124
for (int i = 0; i < mi.getArguments().size(); i++) {
94125
sb.append("#{any()}");
95126
if (indexes.contains(i)) {
@@ -99,23 +130,85 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInv, Ex
99130
sb.append(", ");
100131
}
101132
}
102-
AutoFormatVisitor<Object> formatVisitor = new AutoFormatVisitor<>(null, true);
103-
return (J.MethodInvocation) formatVisitor.visit(
133+
Style s1 = IntelliJ.tabsAndIndents().withContinuationIndent(4);
134+
WrappingAndBracesStyle s2 = IntelliJ.wrappingAndBraces();
135+
s2 = s2.withChainedMethodCalls(
136+
s2.getChainedMethodCalls().withWrap(LineWrapSetting.WrapAlways)
137+
);
138+
AutoFormatVisitor<Object> formatVisitor = new AutoFormatVisitor<>(
139+
null,
140+
false,
141+
new NamedStyles(
142+
Tree.randomId(),
143+
"test",
144+
"test",
145+
"test",
146+
emptySet(),
147+
Arrays.asList(s1, s2)
148+
)
149+
);
150+
J.MethodInvocation mi3 = (J.MethodInvocation) formatVisitor.visit(
104151
JavaTemplate
105152
.builder(sb.toString())
106153
.contextSensitive()
107154
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockwebserver3"))
155+
.imports("mockwebserver3.MockResponse", "mockwebserver3.MockResponse.Builder", "mockwebserver3.MockWebServer")
108156
.build()
109157
.apply(getCursor(), mi.getCoordinates().replaceArguments(), mi.getArguments().toArray()),
110158
ctx,
111159
getCursor().getParent()
112160
);
161+
// TODO: Cleanup backpatching of parameter types for method invocations
162+
mi3 = mi3.withMethodType(mi.getMethodType().withParameterTypes(ListUtils.map(mi.getMethodType().getParameterTypes(), (index, x) -> {
163+
if (indexes.contains(index)) {
164+
return JavaType.buildType(NEW_MOCKRESPONSE_FQN);
165+
}
166+
return x;
167+
})));
168+
mi3 = mi3.getPadding().withArguments(mi3.getPadding().getArguments().getPadding().withElements(ListUtils.map(mi3.getPadding().getArguments().getPadding().getElements(), (index, x) -> {
169+
JRightPadded<Expression> oldArg = oldArgs.get(index);
170+
if (indexes.contains(index)) {
171+
// TODO: Cleanup backpatching of parameter types for method invocations
172+
x = x.withElement(((J.MethodInvocation) x.getElement()).withMethodType(newMethodType(NEW_MOCKRESPONSE_BUILDER_FQN, NEW_MOCKRESPONSE_FQN, "build")));
173+
}
174+
// Below is backpatching prefixes and afters to restore formatting prior to chaining `.build()`
175+
return x
176+
.withAfter(oldArg.getAfter())
177+
.withElement(x.getElement().withPrefix(oldArg.getElement().getPrefix()));
178+
})));
179+
// TODO: Cleanup backpatching of parameter types for method invocation's name's type
180+
mi3 = mi3.withName(mi3.getName().withType(((JavaType.Method) mi3.getName().getType()).withParameterTypes(mi3.getPadding().getArguments().getElements().stream().map(z -> z.getType()).collect(toList()))));
181+
return mi3;
113182
}
114183
return mi;
115184
}
116185
}.visit(j, ctx);
117-
return j;
118186
}
119187
});
120188
}
189+
190+
// TODO: figure out a nicer way of doing this potentially. This is taken from MethodMatcherTest in openrewrite/rewrite and altered slightly
191+
private static JavaType.Method newMethodType(String declaringType, @Nullable String returnType, String method, String... parameterTypes) {
192+
List<JavaType> parameterTypeList = Stream.of(parameterTypes)
193+
.map(name -> {
194+
JavaType.Primitive primitive = JavaType.Primitive.fromKeyword(name);
195+
return primitive != null ? primitive : JavaType.ShallowClass.build(name);
196+
})
197+
.map(JavaType.class::cast)
198+
.collect(toList());
199+
200+
return new JavaType.Method(
201+
null,
202+
1L,
203+
build(declaringType),
204+
method,
205+
returnType == null ? null : build(returnType),
206+
null,
207+
parameterTypeList,
208+
emptyList(),
209+
emptyList(),
210+
emptyList(),
211+
null
212+
);
213+
}
121214
}

src/test/java/org/openrewrite/java/testing/junit5/UpgradeOkHttpMockWebServerTest.java

Lines changed: 41 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ public void defaults(RecipeSpec spec) {
4242
description: Test.
4343
recipeList:
4444
- org.openrewrite.java.testing.junit5.UpdateMockWebServerMockResponse
45-
- org.openrewrite.java.ChangeType:
46-
oldFullyQualifiedTypeName: okhttp3.mockwebserver.MockWebServer
47-
newFullyQualifiedTypeName: mockwebserver3.MockWebServer
48-
#- org.openrewrite.java.ChangePackage:
49-
# oldPackageName: okhttp3.mockwebserver
50-
# newPackageName: mockwebserver3
51-
# recursive: true
5245
""",
5346
"org.openrewrite.test.MigrateMockResponse"
5447
);
@@ -135,7 +128,8 @@ void methodB() {
135128
mockWebServer.enqueue(
136129
new MockResponse.Builder()
137130
.status("hi")
138-
.headers(headersBuilder.build()).build()
131+
.headers(headersBuilder.build())
132+
.build()
139133
);
140134
}
141135
}
@@ -144,91 +138,51 @@ void methodB() {
144138
);
145139
}
146140

147-
@Test
148-
void wip() {
149-
rewriteRun(
150-
//language=java
151-
java(
152-
"""
153-
import okhttp3.Headers;
154-
import okhttp3.mockwebserver.MockResponse;
155-
156-
class A {
157-
void someMethod() {
158-
Headers headers = new Headers.Builder().build();
159-
MockResponse a = new MockResponse();
160-
// .status(String): void
161-
// .getStatus(): String
162-
// --
163-
// .setStatus(String): MockResponse[this]
164-
// ---
165-
// .headers(Headers): void
166-
// .setHeaders(Headers): MockResponse
167-
// .getHeaders(): Headers
168-
// ---
169-
// .addHeader(String): MockResponse
170-
// .addHeader(String,Object): MockResponse
171-
// .addHeaderLenient(String,Object): MockResponse
172-
// ---
173-
// .setHeader(String,Object): MockResponse
174-
// .removeHeader(String): MockResponse
175-
// .clearHeaders(): MockResponse
176-
a.header
177-
a.trailers(headers);
178-
}
179-
}
180-
"""
181-
)
182-
);
183-
}
141+
// @Test
142+
// void wip() {
143+
// rewriteRun(
144+
// //language=java
145+
// java(
146+
// """
147+
// import okhttp3.Headers;
148+
// import okhttp3.mockwebserver.MockResponse;
149+
//
150+
// class A {
151+
// void someMethod() {
152+
// Headers headers = new Headers.Builder().build();
153+
// MockResponse a = new MockResponse();
154+
// // .status(String): void
155+
// // .getStatus(): String
156+
// // --
157+
// // .setStatus(String): MockResponse[this]
158+
// // ---
159+
// // .headers(Headers): void
160+
// // .setHeaders(Headers): MockResponse
161+
// // .getHeaders(): Headers
162+
// // ---
163+
// // .addHeader(String): MockResponse
164+
// // .addHeader(String,Object): MockResponse
165+
// // .addHeaderLenient(String,Object): MockResponse
166+
// // ---
167+
// // .setHeader(String,Object): MockResponse
168+
// // .removeHeader(String): MockResponse
169+
// // .clearHeaders(): MockResponse
170+
// a.header
171+
// a.trailers(headers);
172+
// }
173+
// }
174+
// """
175+
// )
176+
// );
177+
// }
184178

185179
@DocumentExample
186180
@Test
187181
void shouldUpgradeMavenDependency() {
188182
rewriteRun(
183+
spec -> spec.recipeFromResource("/META-INF/rewrite/junit5.yml", "org.openrewrite.java.testing.junit5.UpgradeOkHttpMockWebServer"),
189184
mavenProject("project",
190-
srcTestJava(
191-
//language=java
192-
java(
193-
"""
194-
import okhttp3.mockwebserver.MockResponse;
195-
import okhttp3.mockwebserver.MockWebServer;
196-
import okhttp3.mockwebserver.RecordedRequest;
197-
198-
class Test {
199-
void test() {
200-
MockWebServer server = new MockWebServer();
201-
server.enqueue(
202-
new MockResponse().setHeader("Content-Type", "application/json")
203-
// new MockResponse()
204-
// .setHeader("Content-Type", "application/json")
205-
// .setResponseCode(200)
206-
// .setBody("{}")
207-
);
208-
// RecordedRequest recordedRequest = server.takeRequest();
209-
}
210-
}
211-
""",
212-
"""
213-
import mockwebserver3.MockResponse;
214-
import mockwebserver3.MockWebServer;
215-
import mockwebserver3.RecordedRequest;
216-
217-
class Test {
218-
void test() {
219-
MockWebServer server = new MockWebServer();
220-
server.enqueue(
221-
new MockResponse()
222-
// .setHeader("Content-Type", "application/json")
223-
// .setResponseCode(200)
224-
// .setBody("{}")
225-
);
226-
// RecordedRequest recordedRequest = server.takeRequest();
227-
}
228-
}
229-
"""
230-
)
231-
),
185+
// TODO: handle solely J.NewClass and update declarative recipe to include new one.
232186
//language=xml
233187
pomXml(
234188
"""

0 commit comments

Comments
 (0)