This commit is contained in:
aboyko
2025-05-21 17:46:28 -07:00
2 changed files with 161 additions and 10 deletions

View File

@@ -18,6 +18,7 @@ import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
@@ -122,29 +123,45 @@ public class DataRepositoryAotMetadataService {
return methodMetadata.query().query();
}
private DataRepositoryAotMetadataMethod findMethod(DataRepositoryAotMetadata metadata, IMethodBinding method) {
public DataRepositoryAotMetadataMethod findMethod(DataRepositoryAotMetadata metadata, IMethodBinding method) {
String name = method.getName();
for (DataRepositoryAotMetadataMethod methodMetadata : metadata.methods()) {
// TODO: This check needs more exact method signature matching - which is a little more complicated
// due to runtime Method.toGenericString() output needs to be compared to IMethodBinding source level method information
if (methodMetadata.name() != null && methodMetadata.name().equals(name)) {
String signature = methodMetadata.signature();
JLRMethod parsedMethodSignature = JLRMethodParser.parse(signature);
String methodName = parsedMethodSignature.getMethodName();
String[] parameters = parsedMethodSignature.getParameters();
String returnType = parsedMethodSignature.getReturnType();
parsedMethodSignature.getFQClassName();
return methodMetadata;
if (parsedMethodSignature.getFQClassName().equals(metadata.name())
&& parsedMethodSignature.getMethodName().equals(method.getName())
&& parsedMethodSignature.getReturnType().equals(method.getReturnType().getQualifiedName())
&& parameterMatches(parsedMethodSignature, method)) {
return methodMetadata;
}
}
}
return null;
}
private boolean parameterMatches(JLRMethod parsedMethodSignature, IMethodBinding method) {
String[] parsedParameeterTypes = parsedMethodSignature.getParameters();
ITypeBinding[] methodParameters = method.getParameterTypes();
if (parsedParameeterTypes == null || methodParameters == null || parsedParameeterTypes.length != methodParameters.length) {
return false;
}
for (int i = 0; i < parsedParameeterTypes.length; i++) {
String qualifiedName = methodParameters[i].getQualifiedName();
if (qualifiedName != null && !qualifiedName.equals(parsedParameeterTypes[i])) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,134 @@
/*******************************************************************************
* Copyright (c) 2025 Broadcom, 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
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.net.URI;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
import org.springframework.ide.vscode.boot.java.data.DataRepositoryAotMetadata;
import org.springframework.ide.vscode.boot.java.data.DataRepositoryAotMetadataMethod;
import org.springframework.ide.vscode.boot.java.data.DataRepositoryAotMetadataService;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.parser.JLRMethodParser;
import org.springframework.ide.vscode.commons.java.parser.JLRMethodParser.JLRMethod;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@BootLanguageServerTest
@Import(SymbolProviderTestConf.class)
public class DataRepositoryAotMetadataServiceTest {
@Autowired private BootLanguageServerHarness harness;
@Autowired private JavaProjectFinder projectFinder;
@Autowired private SpringSymbolIndex indexer;
@Autowired private CompilationUnitCache cuCache;
private IJavaProject testProject;
@BeforeEach
public void setup() throws Exception {
testProject = ProjectsHarness.INSTANCE.mavenProject("aot-data-repositories-jpa");
harness.useProject(testProject);
harness.intialize(null);
// trigger project creation
projectFinder.find(new TextDocumentIdentifier(testProject.getLocationUri().toASCIIString())).get();
CompletableFuture<Void> initProject = indexer.waitOperation();
initProject.get(5, TimeUnit.SECONDS);
}
@Test
void testBasicRepositoryAotMetadataLookuo() throws Exception {
DataRepositoryAotMetadataService service = new DataRepositoryAotMetadataService();
DataRepositoryAotMetadata metadata = service.getRepositoryMetadata(testProject, "example.springdata.aot.UserRepository");
assertNotNull(metadata);
assertEquals("example.springdata.aot.UserRepository", metadata.name());
assertEquals("JPA", metadata.module());
}
@Test
void testRepositoryMethodsIntMetadata() throws Exception {
DataRepositoryAotMetadataService service = new DataRepositoryAotMetadataService();
DataRepositoryAotMetadata metadata = service.getRepositoryMetadata(testProject, "example.springdata.aot.UserRepository");
DataRepositoryAotMetadataMethod[] methods = metadata.methods();
assertEquals(32, methods.length);
DataRepositoryAotMetadataMethod methodMetadata = Arrays.stream(methods).filter(method -> method.name().equals("countUsersByLastnameLike")).findFirst().get();
assertEquals("countUsersByLastnameLike", methodMetadata.name());
assertEquals("public abstract java.lang.Long example.springdata.aot.UserRepository.countUsersByLastnameLike(java.lang.String)", methodMetadata.signature());
JLRMethod parsedMethodSignature = JLRMethodParser.parse(methodMetadata.signature());
assertEquals("example.springdata.aot.UserRepository", parsedMethodSignature.getFQClassName());
assertEquals("java.lang.Long", parsedMethodSignature.getReturnType());
assertEquals("countUsersByLastnameLike", parsedMethodSignature.getMethodName());
String[] parameters = parsedMethodSignature.getParameters();
assertEquals("java.lang.String", parameters[0]);
assertEquals(1, parameters.length);
}
@Test
void testRepositoryMethodsMatching() throws Exception {
DataRepositoryAotMetadataService service = new DataRepositoryAotMetadataService();
DataRepositoryAotMetadata metadata = service.getRepositoryMetadata(testProject, "example.springdata.aot.UserRepository");
URI docUri = testProject.getLocationUri().resolve("src/main/java/example/springdata/aot/UserRepository.java");
cuCache.withCompilationUnit(testProject, docUri, cu -> {
cu.accept(new ASTVisitor() {
public boolean visit(MethodDeclaration node) {
IMethodBinding binding = node.resolveBinding();
DataRepositoryAotMetadataMethod method = service.findMethod(metadata, binding);
assertNotNull(method);
if (method.name().equals("findUserByLastnameStartingWith") && binding.getParameterTypes().length == 1) {
assertEquals("public abstract java.util.List<example.springdata.aot.User> example.springdata.aot.UserRepository.findUserByLastnameStartingWith(java.lang.String)", method.signature());
}
else if (method.name().equals("findUserByLastnameStartingWith") && binding.getParameterTypes().length == 2) {
assertEquals("public abstract org.springframework.data.domain.Page<example.springdata.aot.User> example.springdata.aot.UserRepository.findUserByLastnameStartingWith(java.lang.String,org.springframework.data.domain.Pageable)", method.signature());
}
return true;
}
});
return null;
});
}
}