Skip to content

Commit

Permalink
switch xml bean hyperlink provider to new spring index
Browse files Browse the repository at this point in the history
  • Loading branch information
martinlippert committed Dec 21, 2024
1 parent d81feb0 commit 24492fe
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -61,6 +61,7 @@
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;
Expand Down Expand Up @@ -93,15 +94,15 @@ 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;
JavaProjectFinder projectFinder = serverParams.projectFinder;

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);
Expand Down Expand Up @@ -184,15 +185,22 @@ public List<LocationLink> handle(CancelChecker cancelToken, DefinitionParams par

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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,94 +10,48 @@
*******************************************************************************/
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;

/**
* @author Alex Boyko
*/
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());
}

// make sure that only exact project locations are matched
if (!projectLocation.endsWith("/")) {
projectLocation = projectLocation + "/";
}
String beanID = attributeAt.getValue();
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), beanID);

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;
}

}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -35,15 +36,15 @@ public JavaTypeHyperlinkProvider(JavaProjectFinder projectFinder, JavaElementLoc
}

@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();
String fqName = attributeAt.getValue();
if (fqName != null) {
IType type = project.getIndex().findType(fqName);
if (type != null) {
return locationProvider.findLocation(project, type);
return List.of(locationProvider.findLocation(project, type));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -35,18 +36,19 @@ public PropertyNameHyperlinkProvider(JavaProjectFinder projectFinder, JavaElemen
}

@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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -20,6 +22,6 @@
*/
public interface XMLHyperlinkProvider {

Location getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt);
List<Location> getDefinition(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
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;
Expand Down Expand Up @@ -172,7 +171,7 @@ void testBeanPropertyNameFromSuperClassHyperlink() throws Exception {
}

@Test
@Disabled
// @Disabled
void testBeanRefHyperlink() throws Exception {
log.debug("------------------ testBeanRefHyperlink ----------------------");
Path xmlFilePath = Paths.get(project.getLocationUri()).resolve("beans.xml");
Expand Down

0 comments on commit 24492fe

Please sign in to comment.