very simple findby code completion for repository interfaces

This commit is contained in:
Martin Lippert
2018-11-20 15:28:45 +01:00
parent 792867fa20
commit 07053fbe7f
5 changed files with 175 additions and 11 deletions

View File

@@ -23,6 +23,7 @@ import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.util.StringUtils;
/**
* @author Martin Lippert
@@ -39,18 +40,45 @@ public class DataRepositoryCompletionProcessor implements CompletionProvider {
TypeDeclaration type = ASTUtils.findDeclaringType(node);
DataRepositoryDefinition repo = getDataRepositoryDefinition(type);
if (repo != null) {
DocumentEdits edits = new DocumentEdits(null);
edits.insert(offset, "List<Customer> findByLastName${1|(String lastName);,And,Or|}");
DocumentEdits additionalEdits = new DocumentEdits(null);
// additionalEdits.insert(offset, "(String lastName);");
completions.add(new FindByCompletionProposal("findByLastName(String lastName);", CompletionItemKind.Method, edits, null, null, Optional.of(additionalEdits)));
System.out.println("data completion proposal calculation for: " + node.toString());
DomainType domainType = repo.getDomainType();
if (domainType != null) {
DomainProperty[] properties = domainType.getProperties();
for (DomainProperty property : properties) {
completions.add(generateCompletionProposal(offset, repo, property));
}
}
}
}
protected ICompletionProposal generateCompletionProposal(int offset, DataRepositoryDefinition repoDef, DomainProperty domainProperty) {
StringBuilder label = new StringBuilder();
label.append("findBy");
label.append(StringUtils.capitalize(domainProperty.getName()));
label.append("(");
label.append(domainProperty.getType().getSimpleName());
label.append(" ");
label.append(StringUtils.uncapitalize(domainProperty.getName()));
label.append(");");
DocumentEdits edits = new DocumentEdits(null);
StringBuilder completion = new StringBuilder();
completion.append("List<");
completion.append(repoDef.getDomainType().getSimpleName());
completion.append("> findBy");
completion.append(StringUtils.capitalize(domainProperty.getName()));
completion.append("(");
completion.append(domainProperty.getType().getSimpleName());
completion.append(" ");
completion.append(StringUtils.uncapitalize(domainProperty.getName()));
completion.append(");");
edits.insert(offset, completion.toString());
DocumentEdits additionalEdits = new DocumentEdits(null);
return new FindByCompletionProposal(label.toString(), CompletionItemKind.Method, edits, null, null, Optional.of(additionalEdits));
}
private DataRepositoryDefinition getDataRepositoryDefinition(TypeDeclaration type) {
if (type != null) {
ITypeBinding resolvedType = type.resolveBinding();
@@ -75,7 +103,14 @@ public class DataRepositoryCompletionProcessor implements CompletionProvider {
}
if (Constants.REPOSITORY_TYPE.equals(simplifiedType)) {
return new DataRepositoryDefinition();
DomainType domainType = null;
if (resolvedInterface.isParameterizedType()) {
ITypeBinding[] typeParameters = resolvedInterface.getTypeArguments();
if (typeParameters != null && typeParameters.length > 0) {
domainType = new DomainType(typeParameters[0]);
}
}
return createDataRepositoryDefinitionFromType(domainType);
}
else {
DataRepositoryDefinition repo = getDataRepositoryDefinition(type, resolvedInterface);
@@ -93,4 +128,8 @@ public class DataRepositoryCompletionProcessor implements CompletionProvider {
}
return null;
}
private DataRepositoryDefinition createDataRepositoryDefinitionFromType(DomainType domainType) {
return new DataRepositoryDefinition(domainType);
}
}

View File

@@ -10,6 +10,20 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data;
/**
* @author Martin Lippert
*/
public class DataRepositoryDefinition {
private final DomainType domainType;
public DataRepositoryDefinition(DomainType domainType) {
super();
this.domainType = domainType;
}
public DomainType getDomainType() {
return domainType;
}
}

View File

@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data;
/**
* @author Martin Lippert
*/
public class DomainProperty {
private final String name;
private final DomainType type;
public DomainProperty(String name, DomainType type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public DomainType getType() {
return type;
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
/**
* @author Martin Lippert
*/
public class DomainType {
private final String packageName;
private final String fullName;
private final String simpleName;
private DomainProperty[] properties;
public DomainType(String packageName, String fullName, String simpleName) {
this.packageName = packageName;
this.fullName = fullName;
this.simpleName = simpleName;
}
public DomainType(ITypeBinding typeBinding) {
this.packageName = typeBinding.getPackage().getName();
this.fullName = typeBinding.getQualifiedName();
this.simpleName = typeBinding.getName();
if (!this.packageName.startsWith("java")) {
IMethodBinding[] methods = typeBinding.getDeclaredMethods();
if (methods != null && methods.length > 0) {
List<DomainProperty> properties = new ArrayList<>();
for (IMethodBinding method : methods) {
String methodName = method.getName();
if (methodName != null && methodName.startsWith("get")) {
String propertyName = methodName.substring(3);
properties.add(new DomainProperty(propertyName, new DomainType(method.getReturnType())));
}
}
this.properties = (DomainProperty[]) properties.toArray(new DomainProperty[properties.size()]);
}
else {
this.properties = new DomainProperty[0];
}
}
}
public String getPackageName() {
return packageName;
}
public String getFullName() {
return fullName;
}
public String getSimpleName() {
return simpleName;
}
public DomainProperty[] getProperties() {
return properties;
}
}

View File

@@ -54,7 +54,8 @@ public class DataRepositoryCompletionProcessorTest {
public void testStandardFindByCompletions() throws Exception {
prepareCase("{", "{<*>");
assertContainsAnnotationCompletions(
"List<Customer> findByLastName${1|(String lastName);,And,Or|}");
"List<Customer> findByFirstName(String firstName);",
"List<Customer> findByLastName(String lastName);");
}
private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception {