Repository query methods completion accounts for Java Records

This commit is contained in:
aboyko
2023-09-20 19:20:37 -04:00
parent 8d4e41763e
commit e41f45dc8f
3 changed files with 121 additions and 27 deletions

View File

@@ -742,6 +742,23 @@ public class LanguageServerHarness {
assertEquals(expect.toString(), actual.toString());
}
public void assertOneOfCompletions(String textBefore, String expectTextAfter) throws Exception {
Editor editor = newEditor(textBefore);
StringBuilder actualCompletions = new StringBuilder();
List<? extends CompletionItem> completions = editor.getCompletions();
for (CompletionItem ci : completions) {
editor = newEditor(textBefore);
editor.apply(ci);
if (editor.getText().equals(expectTextAfter)) {
return;
}
actualCompletions.append(editor.getText());
actualCompletions.append("\n-------------------\n");
}
fail("Not found expected proposal completion in:\n" + actualCompletions);
}
public void assertCompletionDisplayString(String editorContents, String expected) throws Exception {
Editor editor = newEditor(editorContents);
CompletionItem completion = editor.getFirstCompletion();

View File

@@ -20,6 +20,8 @@ import java.util.Set;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.springframework.ide.vscode.commons.util.StringUtil;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@@ -58,38 +60,44 @@ public class DomainType extends SimpleType {
private List<DomainProperty> calculateDomainProperties(ITypeBinding typeBinding) {
if (!getPackageName().startsWith("java")) {
IMethodBinding[] methods = typeBinding.getDeclaredMethods();
if (methods != null && methods.length > 0) {
List<DomainProperty> properties = new ArrayList<>();
List<DomainProperty> properties = new ArrayList<>();
if (typeBinding.isRecord()) {
for (IVariableBinding f : typeBinding.getDeclaredFields()) {
properties.add(new DomainProperty(StringUtil.upCaseFirstChar(f.getName()), new DomainType(f.getType())));
}
} else {
IMethodBinding[] methods = typeBinding.getDeclaredMethods();
if (methods != null && methods.length > 0) {
for (IMethodBinding method : methods) {
String methodName = method.getName();
if (methodName != null) {
String propertyName = null;
if (methodName.startsWith("get")) {
propertyName = methodName.substring(3);
}
else if (methodName.startsWith("is")) {
propertyName = methodName.substring(2);
}
if (propertyName != null) {
properties.add(new DomainProperty(propertyName, new DomainType(method.getReturnType())));
for (IMethodBinding method : methods) {
String methodName = method.getName();
if (methodName != null) {
String propertyName = null;
if (methodName.startsWith("get")) {
propertyName = methodName.substring(3);
}
else if (methodName.startsWith("is")) {
propertyName = methodName.substring(2);
}
if (propertyName != null) {
properties.add(new DomainProperty(propertyName, new DomainType(method.getReturnType())));
}
}
}
}
if (typeBinding.getSuperclass() != null) {
properties.addAll(calculateDomainProperties(typeBinding.getSuperclass()));
}
if (typeBinding.getInterfaces() != null) {
for (ITypeBinding si : typeBinding.getInterfaces()) {
properties.addAll(calculateDomainProperties(si));
if (typeBinding.getSuperclass() != null) {
properties.addAll(calculateDomainProperties(typeBinding.getSuperclass()));
}
if (typeBinding.getInterfaces() != null) {
for (ITypeBinding si : typeBinding.getInterfaces()) {
properties.addAll(calculateDomainProperties(si));
}
}
}
return properties;
}
return properties;
}
return Collections.emptyList();
}

View File

@@ -114,6 +114,76 @@ public class DataRepositoryCompletionProcessorTest {
""");
}
@Test
void recordEntity() throws Exception {
harness.assertOneOfCompletions("""
package org.test;
import org.springframework.data.repository.CrudRepository;
import javax.persistence.Id;
public class Pets {
public record Pet(@Id Long id, String name) {}
public interface PetsRepositoryForCompletions extends CrudRepository<Pet, Long> {
findBy<*>
}
}
""", """
package org.test;
import org.springframework.data.repository.CrudRepository;
import javax.persistence.Id;
public class Pets {
public record Pet(@Id Long id, String name) {}
public interface PetsRepositoryForCompletions extends CrudRepository<Pet, Long> {
findByName<*>
}
}
""");
harness.assertOneOfCompletions("""
package org.test;
import org.springframework.data.repository.CrudRepository;
import javax.persistence.Id;
public class Pets {
public record Pet(@Id Long id, String name) {}
public interface PetsRepositoryForCompletions extends CrudRepository<Pet, Long> {
findBy<*>
}
}
""", """
package org.test;
import org.springframework.data.repository.CrudRepository;
import javax.persistence.Id;
import java.util.List;
public class Pets {
public record Pet(@Id Long id, String name) {}
public interface PetsRepositoryForCompletions extends CrudRepository<Pet, Long> {
List<Pet> findByName(String name);<*>
}
}
""");
}
@Test
void prefixSensitiveMethodCompletionWithImports_1() throws Exception {
checkCompletionResult("findByResponsibleEmployeeAndLastName", "findByResponsibleEmployeeAndLastName", """
@@ -251,7 +321,6 @@ public class DataRepositoryCompletionProcessorTest {
prepareCase("{\n}", "{\n\t" + prefix + "<*>\n}");
List<CompletionItem> completions = editor.getCompletions();
int i = 0;
for (CompletionItem foundCompletion : completions) {
if (foundCompletion.getLabel().contains(completionLabel)) {
Editor clonedEditor = editor.clone();