Skip to content

Commit 6c285bd

Browse files
authored
Add Type information to the generated Lambda of MemberReferenceToMethodInvocation (#774)
1 parent 483535d commit 6c285bd

File tree

4 files changed

+86
-7
lines changed

4 files changed

+86
-7
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ recipeDependencies {
5959
parserClasspath("org.springframework.boot:spring-boot:3.+")
6060

6161
parserClasspath("org.springframework.boot:spring-boot-autoconfigure:2.+")
62+
parserClasspath("org.springframework.boot:spring-boot-autoconfigure:3.+")
6263
parserClasspath("org.springframework.boot:spring-boot-actuator:2.+")
6364
parserClasspath("org.springframework.boot:spring-boot-actuator:2.5.+")
6465
parserClasspath("org.springframework.boot:spring-boot-test:2.+")

src/main/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocation.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
*/
1616
package org.openrewrite.java.spring.util;
1717

18+
import lombok.RequiredArgsConstructor;
1819
import lombok.Value;
1920
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.internal.ListUtils;
2022
import org.openrewrite.internal.StringUtils;
23+
import org.openrewrite.java.JavaIsoVisitor;
2124
import org.openrewrite.java.JavaTemplate;
2225
import org.openrewrite.java.JavaVisitor;
2326
import org.openrewrite.java.VariableNameUtils;
@@ -26,6 +29,7 @@
2629

2730
import java.util.ArrayList;
2831
import java.util.List;
32+
import java.util.Optional;
2933

3034
import static java.util.stream.Collectors.joining;
3135

@@ -50,14 +54,16 @@ public J visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx)
5054
mr.getContaining(),
5155
mr.getReference().getSimpleName());
5256
} else {
53-
templateCode = String.format("(%s) -> %s.%s()",
54-
args.stream().map(Param::toString).collect(joining(", ")),
57+
templateCode = String.format("%1$s -> %1$s.%2$s()",
5558
args.get(0).getName(),
5659
mr.getReference().getSimpleName());
5760
}
58-
return JavaTemplate.builder(templateCode)
61+
J.Lambda lambda = JavaTemplate.builder(templateCode)
5962
.contextSensitive()
60-
.build().apply(getCursor(), mr.getCoordinates().replace())
63+
.build()
64+
.apply(getCursor(), mr.getCoordinates().replace());
65+
66+
return new AddLambdaTypeInformation(mr, args).visitNonNull(lambda, ctx)
6167
.withPrefix(mr.getPrefix());
6268
}
6369

@@ -76,13 +82,41 @@ private List<Param> getLambdaArgNames(JavaType.Method methodType) {
7682
}
7783
if (params.isEmpty()) {
7884
JavaType.FullyQualified type = methodType.getDeclaringType();
79-
String uniqueVariableName = VariableNameUtils.generateVariableName(StringUtils.uncapitalize(type.getClassName()), getCursor(), VariableNameUtils.GenerationStrategy.INCREMENT_NUMBER);
85+
String uniqueVariableName = VariableNameUtils.generateVariableName(StringUtils.uncapitalize(keepFromLastCapitalLetter(type.getClassName())), getCursor(), VariableNameUtils.GenerationStrategy.INCREMENT_NUMBER);
8086

8187
params.add(new Param(type, uniqueVariableName));
8288
}
8389
return params;
8490
}
8591

92+
@RequiredArgsConstructor
93+
private static class AddLambdaTypeInformation extends JavaIsoVisitor<ExecutionContext> {
94+
95+
private final J.MemberReference mr;
96+
private final List<Param> args;
97+
98+
@Override
99+
public J.Identifier visitIdentifier(J.Identifier ident, ExecutionContext ctx) {
100+
Optional<Param> arg = args.stream().filter(a -> a.getName().equals(ident.getSimpleName())).findFirst();
101+
if (arg.isPresent()) {
102+
JavaType type = arg.get().getType();
103+
return ident.withType(type).withFieldType(ident.getFieldType() == null ? null : ident.getFieldType().withType(type));
104+
}
105+
return super.visitIdentifier(ident, ctx);
106+
}
107+
108+
@Override
109+
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations mv, ExecutionContext ctx) {
110+
return mv.withVariables(ListUtils.map(mv.getVariables(), (index, variable) -> variable.withType(args.get(index).getType())));
111+
}
112+
113+
@Override
114+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) {
115+
return mi.withMethodType(mr.getMethodType());
116+
}
117+
118+
}
119+
86120
@Value
87121
class Param {
88122
JavaType type;
@@ -93,4 +127,13 @@ public String toString() {
93127
return String.format("%s %s", type.toString().replaceFirst("^java.lang.", ""), name);
94128
}
95129
}
130+
131+
private static String keepFromLastCapitalLetter(String input) {
132+
for (int i = input.length() - 1; i >= 0; i--) {
133+
if (Character.isUpperCase(input.charAt(i))) {
134+
return input.substring(i);
135+
}
136+
}
137+
return input;
138+
}
96139
}
110 KB
Binary file not shown.

src/test/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocationTest.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class MemberReferenceToMethodInvocationTest implements RewriteTest {
3232
@Override
3333
public void defaults(RecipeSpec spec) {
3434
spec.recipe(toRecipe(MemberReferenceToMethodInvocation::new))
35-
.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-core-6"));
35+
.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-core-6", "spring-boot-autoconfigure-3.+"));
3636
}
3737

3838
@DocumentExample
@@ -84,7 +84,7 @@ void test() {
8484
8585
class A {
8686
void test() {
87-
byte[] result = Optional.of("Test").map((String string) -> string.getBytes()).orElse(null);
87+
byte[] result = Optional.of("Test").map(string -> string.getBytes()).orElse(null);
8888
}
8989
}
9090
"""
@@ -121,4 +121,39 @@ public Supplier<String> getString() {
121121
)
122122
);
123123
}
124+
125+
@Test
126+
void typesArePresent() {
127+
//language=java
128+
rewriteRun(
129+
java(
130+
"""
131+
import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails;
132+
import java.util.List;
133+
import java.util.Optional;
134+
135+
public class KafkaConfig {
136+
public List<String> getProducerServers(KafkaConnectionDetails connectionDetails) {
137+
return Optional.ofNullable(connectionDetails)
138+
.map(KafkaConnectionDetails::getProducerBootstrapServers)
139+
.orElse(null);
140+
}
141+
}
142+
""",
143+
"""
144+
import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails;
145+
import java.util.List;
146+
import java.util.Optional;
147+
148+
public class KafkaConfig {
149+
public List<String> getProducerServers(KafkaConnectionDetails connectionDetails) {
150+
return Optional.ofNullable(connectionDetails)
151+
.map(details -> details.getProducerBootstrapServers())
152+
.orElse(null);
153+
}
154+
}
155+
"""
156+
)
157+
);
158+
}
124159
}

0 commit comments

Comments
 (0)