switch xml bean hyperlink provider to new spring index

This commit is contained in:
Martin Lippert
2024-12-21 20:37:05 +01:00
parent d81feb0bc1
commit 24492fe231
6 changed files with 45 additions and 79 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2021 Pivotal, Inc.
* Copyright (c) 2019, 2024 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
@@ -61,6 +61,7 @@ import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
import org.springframework.ide.vscode.boot.xml.XMLElementKey;
import org.springframework.ide.vscode.boot.xml.hyperlinks.BeanRefHyperlinkProvider;
@@ -93,7 +94,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
public XmlBeansConfigDefinitionHandler(SimpleTextDocumentService documents,
BootJavaConfig config,
JavaElementLocationProvider locationProvider,
SpringSymbolIndex symbolIndex,
SpringMetamodelIndex springIndex,
BootLanguageServerParams serverParams) {
this.documents = documents;
this.config = config;
@@ -101,7 +102,7 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
JavaTypeHyperlinkProvider javaTypeHyperlinkProvider = new JavaTypeHyperlinkProvider(projectFinder, locationProvider);
PropertyNameHyperlinkProvider propertyNameHyperlinkProvider = new PropertyNameHyperlinkProvider(projectFinder, locationProvider);
BeanRefHyperlinkProvider beanRefHyperlinkProvider = new BeanRefHyperlinkProvider(projectFinder, symbolIndex);
BeanRefHyperlinkProvider beanRefHyperlinkProvider = new BeanRefHyperlinkProvider(projectFinder, springIndex);
List<JavaTypeHyperlinkProvider> typeHandlersOnly = Arrays.asList(javaTypeHyperlinkProvider);
List<PropertyNameHyperlinkProvider> propertyNameHandlers = Arrays.asList(propertyNameHyperlinkProvider);
@@ -184,15 +185,22 @@ public class XmlBeansConfigDefinitionHandler implements DefinitionHandler, Langu
List<? extends XMLHyperlinkProvider> providers = hyperlinkProviders.get(key);
if (providers != null) {
ImmutableList.Builder<LocationLink> listBuilder = ImmutableList.builder();
for (XMLHyperlinkProvider provider : providers) {
Location location = provider.getDefinition(doc, namespace, node, attributeAt);
if (location != null) {
List<Location> locations = provider.getDefinition(doc, namespace, node, attributeAt);
if (locations != null) {
int start = attributeAt.getNodeAttrValue().getStart() + 1;
int end = attributeAt.getNodeAttrValue().getEnd() - 1;
listBuilder.add(new LocationLink(location.getUri(),
location.getRange(), location.getRange(),
doc.toRange(start, Math.max(0, end - start))));
for (Location location : locations) {
listBuilder.add(new LocationLink(location.getUri(),
location.getRange(), location.getRange(),
doc.toRange(start, Math.max(0, end - start))));
}
}
}
return listBuilder.build();

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2021 Pivotal, Inc.
* Copyright (c) 2019, 2024 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
@@ -10,22 +10,17 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.xml.hyperlinks;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.WorkspaceSymbol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -33,71 +28,30 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public class BeanRefHyperlinkProvider implements XMLHyperlinkProvider {
private static final Logger log = LoggerFactory.getLogger(BeanRefHyperlinkProvider.class);
private final JavaProjectFinder projectFinder;
private final SpringSymbolIndex symbolIndex;
private final SpringMetamodelIndex springIndex;
public BeanRefHyperlinkProvider(JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex) {
public BeanRefHyperlinkProvider(JavaProjectFinder projectFinder, SpringMetamodelIndex springIndex) {
this.projectFinder = projectFinder;
this.symbolIndex = symbolIndex;
this.springIndex = springIndex;
}
@Override
public Location getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
public List<Location> getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
Optional<IJavaProject> foundProject = this.projectFinder.find(doc.getId());
if (foundProject.isPresent()) {
final IJavaProject project = foundProject.get();
String projectLocation = project.getLocationUri() != null ? project.getLocationUri().toASCIIString() : "";
// make sure the project and the symbol location share the same prefix "file:///"
// looks like project locations are containing a "file:/" only
if (!projectLocation.startsWith("file:///")) {
projectLocation = "file:///" + projectLocation.substring("file:/".length());
}
String beanID = attributeAt.getValue();
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), beanID);
// make sure that only exact project locations are matched
if (!projectLocation.endsWith("/")) {
projectLocation = projectLocation + "/";
}
List<WorkspaceSymbol> symbols = symbolIndex.getSymbols(data -> symbolsFilter(data, attributeAt.getValue())).collect(Collectors.toList());
if (!symbols.isEmpty()) {
for (WorkspaceSymbol symbol : symbols) {
if (symbol.getLocation().isLeft()) {
Location location = symbol.getLocation().getLeft();
String uri = location.getUri();
if (uri != null && uri.startsWith(projectLocation)) {
return location;
}
}
}
// TODO: need better handling for the WorkspaceSymbolLocation case
for (WorkspaceSymbol symbol : symbols) {
if (symbol.getLocation().isLeft()) {
return symbol.getLocation().getLeft();
}
}
} else {
log.debug("No Symbols!!!");
if (beans != null && beans.length > 0) {
return Arrays.stream(beans)
.map(bean -> bean.getLocation())
.toList();
}
}
return null;
}
private boolean symbolsFilter(EnhancedSymbolInformation data, String beanId) {
SymbolAddOnInformation[] additionalInformation = data.getAdditionalInformation();
if (beanId != null && additionalInformation != null) {
for (SymbolAddOnInformation info : additionalInformation) {
if (info instanceof BeansSymbolAddOnInformation) {
String id = ((BeansSymbolAddOnInformation)info).getBeanID();
log.debug("Bean symbol id = " + id);
return beanId.equals(id);
}
}
}
return false;
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, Inc.
* Copyright (c) 2019, 2024 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
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.xml.hyperlinks;
import java.util.List;
import java.util.Optional;
import org.eclipse.lemminx.dom.DOMAttr;
@@ -35,7 +36,7 @@ public class JavaTypeHyperlinkProvider implements XMLHyperlinkProvider {
}
@Override
public Location getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
public List<Location> getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
Optional<IJavaProject> foundProject = this.projectFinder.find(doc.getId());
if (foundProject.isPresent()) {
IJavaProject project = foundProject.get();
@@ -43,7 +44,7 @@ public class JavaTypeHyperlinkProvider implements XMLHyperlinkProvider {
if (fqName != null) {
IType type = project.getIndex().findType(fqName);
if (type != null) {
return locationProvider.findLocation(project, type);
return List.of(locationProvider.findLocation(project, type));
}
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, Inc.
* Copyright (c) 2019, 2024 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
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.xml.hyperlinks;
import java.util.List;
import java.util.Optional;
import org.eclipse.lemminx.dom.DOMAttr;
@@ -35,18 +36,19 @@ public class PropertyNameHyperlinkProvider implements XMLHyperlinkProvider {
}
@Override
public Location getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
public List<Location> getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt) {
Optional<IJavaProject> foundProject = this.projectFinder.find(doc.getId());
String propertyName = attributeAt.getValue();
if (foundProject.isPresent() && propertyName != null && !propertyName.isEmpty()) {
IJavaProject project = foundProject.get();
String beanClass = PropertyNameCompletionProposalProvider.identifyBeanClass(node);
if (beanClass != null && beanClass.length() > 0) {
return PropertyNameCompletionProposalProvider.propertyNameCandidateMethods(project, beanClass)
.filter(method -> propertyName.equals(PropertyNameCompletionProposalProvider.getPropertyName(method)))
.map(method -> locationProvider.findLocation(project, method))
.findFirst()
.orElse(null);
.toList();
}
}
return null;

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, Inc.
* Copyright (c) 2019, 2024 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
@@ -10,6 +10,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.xml.hyperlinks;
import java.util.List;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lsp4j.Location;
@@ -20,6 +22,6 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public interface XMLHyperlinkProvider {
Location getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt);
List<Location> getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt);
}

View File

@@ -24,7 +24,6 @@ import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -172,7 +171,7 @@ public class XMLBeansHyperlinkTest {
}
@Test
@Disabled
// @Disabled
void testBeanRefHyperlink() throws Exception {
log.debug("------------------ testBeanRefHyperlink ----------------------");
Path xmlFilePath = Paths.get(project.getLocationUri()).resolve("beans.xml");