Skip to content

Commit a300600

Browse files
author
Tim te Beek
authored
Add org.openrewrite.java.migrate.lang.StringFormatted to Java 17 recipes (#119)
* Bup SDKman to use 11.0.16 * Update .gitignore to support Spring Tool Suite * Add StringFormatted starter, with two items still left TODO * Resolve TODO items * Add org.openrewrite.java.migrate.lang.StringFormatted to Java 17 recipes * No need for StringBuilder * Also test a split second argument
1 parent bba4904 commit a300600

File tree

5 files changed

+212
-1
lines changed

5 files changed

+212
-1
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ build/
33
.idea/
44
.boot-releases
55
out/
6+
.classpath
7+
.project
8+
.settings/
9+
bin/

.sdkmanrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Enable auto-env through the sdkman_auto_env config
22
# Add key=value pairs of SDKs to use below
3-
java=11.0.14-tem
3+
java=11.0.16-tem
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
* <p>
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+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
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.migrate.lang;
17+
18+
import org.openrewrite.ExecutionContext;
19+
import org.openrewrite.Recipe;
20+
import org.openrewrite.TreeVisitor;
21+
import org.openrewrite.java.JavaParser;
22+
import org.openrewrite.java.JavaTemplate;
23+
import org.openrewrite.java.JavaVisitor;
24+
import org.openrewrite.java.MethodMatcher;
25+
import org.openrewrite.java.search.UsesMethod;
26+
import org.openrewrite.java.tree.Expression;
27+
import org.openrewrite.java.tree.J;
28+
29+
import java.time.Duration;
30+
import java.util.Collections;
31+
import java.util.List;
32+
33+
public class StringFormatted extends Recipe {
34+
35+
private static final MethodMatcher STRING_FORMAT = new MethodMatcher("java.lang.String format(..)");
36+
37+
@Override
38+
public String getDisplayName() {
39+
return "Replace `String#format(String, Object...)` with `String#formatted(Object...)`";
40+
}
41+
42+
@Override
43+
public String getDescription() {
44+
return "Call `String#formatted(Object...)` on first argument to `String#format(String, Object...)`.";
45+
}
46+
47+
@Override
48+
protected TreeVisitor<?, ExecutionContext> getSingleSourceApplicableTest() {
49+
return new UsesMethod<>(STRING_FORMAT);
50+
}
51+
52+
@Override
53+
protected StringFormattedVisitor getVisitor() {
54+
return new StringFormattedVisitor();
55+
}
56+
57+
private static class StringFormattedVisitor extends JavaVisitor<ExecutionContext> {
58+
@Override
59+
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext p) {
60+
J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, p);
61+
if (!STRING_FORMAT.matches(mi)) {
62+
return mi;
63+
}
64+
65+
List<Expression> arguments = mi.getArguments();
66+
String template = String.format(
67+
arguments.get(0) instanceof J.Literal
68+
? "#{any(java.lang.String)}.formatted(%s)"
69+
: "(#{any(java.lang.String)}).formatted(%s)",
70+
String.join(", ", Collections.nCopies(arguments.size() - 1, "#{any()}")));
71+
return mi.withTemplate(
72+
JavaTemplate.builder(this::getCursor, template)
73+
.javaParser(() -> JavaParser.fromJavaVersion().build())
74+
.build(),
75+
mi.getCoordinates().replace(),
76+
arguments.toArray());
77+
}
78+
}
79+
80+
@Override
81+
public Duration getEstimatedEffortPerOccurrence() {
82+
return Duration.ofMinutes(1);
83+
}
84+
85+
}

src/main/resources/META-INF/rewrite/java-version-17.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ recipeList:
3131
key: maven.compiler.target
3232
newValue: 17
3333
addIfMissing: false
34+
- org.openrewrite.java.migrate.lang.StringFormatted
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
* <p>
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+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
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.migrate.lang
17+
18+
import org.junit.jupiter.api.Test
19+
import org.openrewrite.Issue
20+
import org.openrewrite.java.Assertions.java
21+
import org.openrewrite.java.JavaParser
22+
import org.openrewrite.test.RecipeSpec
23+
import org.openrewrite.test.RewriteTest
24+
25+
class StringFormattedTest : RewriteTest {
26+
override fun defaults(spec: RecipeSpec) {
27+
spec.recipe(StringFormatted())
28+
spec.parser(JavaParser.fromJavaVersion().build())
29+
}
30+
31+
@Test
32+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
33+
fun oneArgument() = rewriteRun(
34+
java("""
35+
class A {
36+
String str = String.format("foo");
37+
}
38+
""",
39+
"""
40+
class A {
41+
String str = "foo".formatted();
42+
}
43+
""")
44+
)
45+
46+
@Test
47+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
48+
fun twoArguments() = rewriteRun(
49+
java("""
50+
class A {
51+
String str = String.format("foo %s", "a");
52+
}
53+
""",
54+
"""
55+
class A {
56+
String str = "foo %s".formatted("a");
57+
}
58+
""")
59+
)
60+
61+
@Test
62+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
63+
fun threeArguments() = rewriteRun(
64+
java("""
65+
class A {
66+
String str = String.format("foo %s %d", "a", 1);
67+
}
68+
""",
69+
"""
70+
class A {
71+
String str = "foo %s %d".formatted("a", 1);
72+
}
73+
""")
74+
)
75+
76+
@Test
77+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
78+
fun fourArguments() = rewriteRun(
79+
java("""
80+
class A {
81+
String str = String.format("foo %s %d %f", "a", 1, 2.0);
82+
}
83+
""",
84+
"""
85+
class A {
86+
String str = "foo %s %d %f".formatted("a", 1, 2.0);
87+
}
88+
""")
89+
)
90+
91+
@Test
92+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
93+
fun splitFirstArgument() = rewriteRun(
94+
java("""
95+
class A {
96+
String str = String.format("foo " + "%s", "a");
97+
}
98+
""",
99+
"""
100+
class A {
101+
String str = ("foo " + "%s").formatted("a");
102+
}
103+
""")
104+
)
105+
106+
@Test
107+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/77")
108+
fun splitSecondArgument() = rewriteRun(
109+
java("""
110+
class A {
111+
String str = String.format("foo %s", "a" + "b");
112+
}
113+
""",
114+
"""
115+
class A {
116+
String str = "foo %s".formatted("a" + "b");
117+
}
118+
""")
119+
)
120+
121+
}

0 commit comments

Comments
 (0)