Skip to content

Commit edd78c0

Browse files
committed
Bean completion case of constructor with parameter
1 parent 7f36d34 commit edd78c0

File tree

3 files changed

+137
-36
lines changed

3 files changed

+137
-36
lines changed

headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/java/ConstructorInjectionRecipe.java

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,16 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ct
139139
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable,
140140
ExecutionContext ctx) {
141141

142-
Cursor blockCursor = getCursor().dropParentUntil(it -> it instanceof J.Block || it == Cursor.ROOT_VALUE);
142+
Cursor blockCursor = getCursor().getParentTreeCursor();
143143
if (!(blockCursor.getValue() instanceof J.Block)) {
144144
return multiVariable;
145145
}
146+
Cursor typeDeclCursor = blockCursor.getParentTreeCursor();
147+
if (!(typeDeclCursor.getValue() instanceof J.ClassDeclaration)) {
148+
return multiVariable;
149+
}
146150
VariableDeclarations mv = multiVariable;
147-
if (blockCursor.getParent() != null && blockCursor.getParent().getValue() instanceof ClassDeclaration
148-
&& multiVariable.getVariables().size() == 1
151+
if (multiVariable.getVariables().size() == 1
149152
&& fieldName.equals(multiVariable.getVariables().get(0).getName().getSimpleName())) {
150153
if (mv.getModifiers().stream().noneMatch(m -> m.getType() == J.Modifier.Type.Final)) {
151154
Space prefix = Space.firstPrefix(mv.getVariables());
@@ -236,31 +239,42 @@ public AddConstructorParameterAndAssignment(MethodDeclaration constructor, Strin
236239
@Override
237240
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, ExecutionContext p) {
238241
J.MethodDeclaration md = super.visitMethodDeclaration(method, p);
239-
if (md == this.constructor && md.getBody() != null) {
242+
if (md.getId().equals(constructor.getId()) && md.getBody() != null) {
240243

241-
List<Statement> newParams = new ArrayList<>(md.getParameters().stream().filter(s -> !(s instanceof J.Empty)).toList());
242-
J.VariableDeclarations vd = new J.VariableDeclarations(
243-
Tree.randomId(),
244-
newParams.isEmpty() ? Space.EMPTY : Space.SINGLE_SPACE,
245-
Markers.EMPTY,
246-
Collections.emptyList(),
247-
Collections.emptyList(),
248-
TypeTree.build(methodType),
249-
null,
250-
Collections.emptyList(),
251-
List.of(JRightPadded.build(new J.VariableDeclarations.NamedVariable(
252-
Tree.randomId(),
253-
Space.SINGLE_SPACE,
254-
Markers.EMPTY,
255-
createFieldNameIdentifier(),
256-
Collections.emptyList(),
257-
null,
258-
null
259-
)))
260-
);
261-
newParams.add(vd);
262-
md = md.withParameters(newParams);
263-
updateCursor(md);
244+
boolean parameterExists = md.getParameters().stream().filter(J.VariableDeclarations.class::isInstance).map(J.VariableDeclarations.class::cast).filter(vd -> {
245+
if (vd.getVariables().stream().anyMatch(vn -> fieldName.equals(vn.getSimpleName()))) {
246+
FullyQualified fqType = vd.getTypeAsFullyQualified();
247+
if (fqType != null && methodType.equals(fqType.getClassName())) {
248+
return true;
249+
}
250+
}
251+
return false;
252+
}).findFirst().isPresent();
253+
if (!parameterExists) {
254+
List<Statement> newParams = new ArrayList<>(md.getParameters().stream().filter(s -> !(s instanceof J.Empty)).toList());
255+
J.VariableDeclarations vd = new J.VariableDeclarations(
256+
Tree.randomId(),
257+
newParams.isEmpty() ? Space.EMPTY : Space.SINGLE_SPACE,
258+
Markers.EMPTY,
259+
Collections.emptyList(),
260+
Collections.emptyList(),
261+
TypeTree.build(methodType),
262+
null,
263+
Collections.emptyList(),
264+
List.of(JRightPadded.build(new J.VariableDeclarations.NamedVariable(
265+
Tree.randomId(),
266+
Space.SINGLE_SPACE,
267+
Markers.EMPTY,
268+
createFieldNameIdentifier(),
269+
Collections.emptyList(),
270+
null,
271+
null
272+
)))
273+
);
274+
newParams.add(vd);
275+
md = md.withParameters(newParams);
276+
updateCursor(md);
277+
}
264278

265279
if (!isConstructorInitializingField(md, fieldName)) {
266280
// noinspection ConstantConditions

headless-services/commons/commons-rewrite/src/test/java/org/springframework/ide/vscode/commons/rewrite/java/ConstructorInjectionRecipeTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,49 @@ public interface OwnerRepository{}
136136
runRecipeAndAssert(recipe, beforeSourceStr, expectedSourceStr, dependsOn);
137137
}
138138

139+
@Test
140+
void injectFieldIntoExistingSingleConstructorWithExisitngParameter() {
141+
142+
String beforeSourceStr = """
143+
package com.example.demo;
144+
145+
import com.example.test.OwnerRepository;
146+
147+
public class A {
148+
149+
private final OwnerRepository ownerRepository;
150+
151+
A(OwnerRepository ownerRepository) {
152+
}
153+
154+
}
155+
""";
156+
157+
String expectedSourceStr = """
158+
package com.example.demo;
159+
160+
import com.example.test.OwnerRepository;
161+
162+
public class A {
163+
164+
private final OwnerRepository ownerRepository;
165+
166+
A(OwnerRepository ownerRepository) {
167+
this.ownerRepository = ownerRepository;
168+
}
169+
170+
}
171+
""";
172+
173+
String dependsOn = """
174+
package com.example.test;
175+
public interface OwnerRepository{}
176+
""";
177+
178+
Recipe recipe = new ConstructorInjectionRecipe("com.example.test.OwnerRepository", "ownerRepository", "com.example.demo.A");
179+
runRecipeAndAssert(recipe, beforeSourceStr, expectedSourceStr, dependsOn);
180+
}
181+
139182
@Test
140183
void injectFieldIntoAutowiredConstructor() {
141184

headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/BeanCompletionProviderTest.java

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class BeanCompletionProviderTest {
6969
private Bean bean4;
7070
private Bean bean5;
7171
private Bean bean6;
72+
private Bean bean7;
7273

7374
@BeforeEach
7475
public void setup() throws Exception {
@@ -94,8 +95,9 @@ public void setup() throws Exception {
9495
bean4 = new Bean("visitService", "org.springframework.samples.petclinic.owner.VisitService", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
9596
bean5 = new Bean("petService", "org.springframework.samples.petclinic.pet.Inner.PetService", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
9697
bean6 = new Bean("testBeanCompletionClass", "org.sample.test.TestBeanCompletionClass", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
98+
bean7 = new Bean("testIntBean", "java.lang.Integer", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
9799

98-
springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2, bean3, bean4, bean5, bean6});
100+
springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2, bean3, bean4, bean5, bean6, bean7});
99101
}
100102

101103
@AfterEach
@@ -155,7 +157,7 @@ public void test() {
155157

156158
@Test
157159
public void noPrefix_secondCompletion() throws Exception {
158-
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 1,
160+
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 1,
159161
"""
160162
package org.sample.test;
161163
@@ -180,7 +182,7 @@ public void test() {
180182

181183
@Test
182184
public void testBeanCompletion_injectInnerClass() throws Exception {
183-
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 2,
185+
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 2,
184186
"""
185187
package org.sample.test;
186188
@@ -297,7 +299,7 @@ public void test() {
297299
}
298300
""";
299301

300-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testBeanCompletionClass", "visitRepository", "visitService"}, 1,
302+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testBeanCompletionClass", "testIntBean", "visitRepository", "visitService"}, 1,
301303
"""
302304
package org.sample.test;
303305
@@ -526,6 +528,48 @@ public void test() {
526528
""");
527529
}
528530

531+
@Test
532+
public void beanCompletionWithConstructorParameterPresent() throws Exception {
533+
String content = """
534+
package org.sample.test;
535+
536+
import org.springframework.stereotype.Controller;
537+
538+
@Controller
539+
public class TestBeanCompletionClass {
540+
541+
TestBeanCompletionClass(Integer testIntBean) {
542+
}
543+
544+
public void test() {
545+
this.testI<*>
546+
}
547+
}
548+
""";
549+
550+
551+
assertCompletions(content, new String[] {"testIntBean"}, 0,
552+
"""
553+
package org.sample.test;
554+
555+
import org.springframework.stereotype.Controller;
556+
557+
@Controller
558+
public class TestBeanCompletionClass {
559+
560+
private final Integer testIntBean;
561+
562+
TestBeanCompletionClass(Integer testIntBean) {
563+
this.testIntBean = testIntBean;
564+
}
565+
566+
public void test() {
567+
this.testIntBean<*>
568+
}
569+
}
570+
""");
571+
}
572+
529573
@Test
530574
public void noCompletionsInMethod_1() throws Exception {
531575
String content = """
@@ -659,7 +703,7 @@ public void test() {
659703
""";
660704

661705

662-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
706+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 0,
663707
"""
664708
package org.sample.test;
665709
@@ -965,7 +1009,7 @@ public TestBeanCompletionClass() {
9651009
""";
9661010

9671011

968-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
1012+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 0,
9691013
"""
9701014
package org.sample.test;
9711015
@@ -1002,7 +1046,7 @@ public TestBeanCompletionClass() {
10021046
""";
10031047

10041048

1005-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
1049+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 0,
10061050
"""
10071051
package org.sample.test;
10081052
@@ -1039,7 +1083,7 @@ public TestBeanCompletionClass() {
10391083
""";
10401084

10411085

1042-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
1086+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 0,
10431087
"""
10441088
package org.sample.test;
10451089
@@ -1076,7 +1120,7 @@ public TestBeanCompletionClass() {
10761120
""";
10771121

10781122

1079-
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
1123+
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testIntBean", "visitRepository", "visitService"}, 0,
10801124
"""
10811125
package org.sample.test;
10821126

0 commit comments

Comments
 (0)