Skip to content

Commit 52339a8

Browse files
committed
migrate recipe as-is
1 parent 3f52b88 commit 52339a8

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2024 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.lombok;
17+
18+
import lombok.AccessLevel;
19+
import lombok.EqualsAndHashCode;
20+
import lombok.Value;
21+
import org.openrewrite.ExecutionContext;
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.tree.J;
28+
29+
import static java.util.Comparator.comparing;
30+
31+
@Value
32+
@EqualsAndHashCode(callSuper = false)
33+
public class UseNoArgsConstructor extends Recipe {
34+
35+
@Override
36+
public String getDisplayName() {
37+
//language=markdown
38+
return "Use `@NoArgsConstructor` where applicable";
39+
}
40+
41+
@Override
42+
public String getDescription() {
43+
//language=markdown
44+
return "Prefer the lombok annotation `@NoArgsConstructor` over explicitly written out constructors.\n" +
45+
"This recipe does not create annotations for implicit constructors.";
46+
}
47+
48+
@Override
49+
public TreeVisitor<?, ExecutionContext> getVisitor() {
50+
return new JavaIsoVisitor<ExecutionContext>() {
51+
public static final String FOUND_EMPTY_CONSTRUCTOR = "FOUND_EMPTY_CONSTRUCTOR";
52+
53+
54+
@Override
55+
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
56+
J.ClassDeclaration classDeclAfterVisit = super.visitClassDeclaration(classDecl, ctx);
57+
58+
J.MethodDeclaration message = getCursor().pollMessage(FOUND_EMPTY_CONSTRUCTOR);
59+
60+
//if no constructor is found return immediately
61+
if (message == null) {
62+
return classDecl;//since nothing changed the original can be returned
63+
}
64+
65+
maybeAddImport("lombok.NoArgsConstructor");
66+
67+
AccessLevel accessLevel = LombokUtils.getAccessLevel(message);
68+
69+
return getAnnotation(accessLevel).apply(
70+
updateCursor(classDeclAfterVisit),
71+
classDeclAfterVisit.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)));
72+
}
73+
74+
private JavaTemplate getAnnotation(AccessLevel accessLevel) {
75+
76+
JavaTemplate.Builder builder = AccessLevel.PUBLIC.equals(accessLevel)
77+
? JavaTemplate.builder("@NoArgsConstructor()\n")
78+
: JavaTemplate.builder("@NoArgsConstructor(access = AccessLevel." + accessLevel.name() + ")\n")
79+
.imports("lombok.AccessLevel");
80+
81+
return builder
82+
.imports("lombok.NoArgsConstructor")
83+
.javaParser(JavaParser.fromJavaVersion()
84+
.classpath("lombok"))
85+
.build();
86+
}
87+
88+
@Override
89+
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
90+
assert method.getMethodType() != null;
91+
if (method.getMethodType().getName().equals("<constructor>") //it's a constructor
92+
&& method.getParameters().get(0) instanceof J.Empty //no parameters
93+
&& method.getBody().getStatements().isEmpty() //no side effects (=> does nothing)
94+
) {
95+
getCursor().putMessageOnFirstEnclosing(J.ClassDeclaration.class, FOUND_EMPTY_CONSTRUCTOR, method);
96+
return null;
97+
}
98+
return super.visitMethodDeclaration(method, ctx);
99+
}
100+
101+
};
102+
}
103+
104+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2024 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.lombok;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.java.JavaParser;
21+
import org.openrewrite.test.RecipeSpec;
22+
import org.openrewrite.test.RewriteTest;
23+
24+
import static org.openrewrite.java.Assertions.java;
25+
26+
class UseNoArgsConstructorTest implements RewriteTest {
27+
28+
@Override
29+
public void defaults(RecipeSpec spec) {
30+
spec.recipe(new UseNoArgsConstructor())
31+
.parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true));
32+
}
33+
34+
@DocumentExample
35+
@Test
36+
void replaceEmptyPublicConstructor() {
37+
rewriteRun(// language=java
38+
java(
39+
"""
40+
class A {
41+
public A() {}
42+
}
43+
""",
44+
"""
45+
import lombok.NoArgsConstructor;
46+
47+
@NoArgsConstructor()
48+
class A {
49+
}
50+
"""
51+
)
52+
);
53+
}
54+
55+
@Test
56+
void keepNonEmptyPublicConstructor() {
57+
rewriteRun(
58+
java(
59+
"""
60+
class A {
61+
62+
int foo;
63+
64+
public A() {
65+
foo = 7;
66+
}
67+
}
68+
"""
69+
)
70+
);
71+
}
72+
73+
@Test
74+
void replaceEmptyProtectedConstructor() {
75+
rewriteRun(
76+
java(
77+
"""
78+
class A {
79+
protected A() {}
80+
}
81+
""",
82+
"""
83+
import lombok.NoArgsConstructor;
84+
85+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
86+
class A {
87+
}
88+
"""
89+
)
90+
);
91+
}
92+
93+
@Test
94+
void replaceEmptyPrivateConstructor() {
95+
rewriteRun(
96+
java(
97+
"""
98+
class A {
99+
private A() {}
100+
}
101+
""",
102+
"""
103+
import lombok.NoArgsConstructor;
104+
105+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
106+
class A {
107+
}
108+
"""
109+
)
110+
);
111+
}
112+
113+
@Test
114+
void replaceEmptyPackageConstructor() {
115+
rewriteRun(
116+
java(
117+
"""
118+
class A {
119+
A() {}
120+
}
121+
""",
122+
"""
123+
import lombok.NoArgsConstructor;
124+
125+
@NoArgsConstructor(access = AccessLevel.PACKAGE)
126+
class A {
127+
}
128+
"""
129+
)
130+
);
131+
}
132+
133+
}

0 commit comments

Comments
 (0)