Merge branch 'master' of github.com:spring-projects/sts4
This commit is contained in:
@@ -250,9 +250,9 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
|||||||
providers.put(Annotations.SPRING_PATCH_MAPPING, new RequestMappingHoverProvider());
|
providers.put(Annotations.SPRING_PATCH_MAPPING, new RequestMappingHoverProvider());
|
||||||
providers.put(Annotations.PROFILE, new ActiveProfilesProvider());
|
providers.put(Annotations.PROFILE, new ActiveProfilesProvider());
|
||||||
|
|
||||||
providers.put(Annotations.AUTOWIRED, new AutowiredHoverProvider());
|
providers.put(Annotations.AUTOWIRED, new AutowiredHoverProvider(this));
|
||||||
providers.put(Annotations.COMPONENT, new ComponentInjectionsHoverProvider());
|
providers.put(Annotations.COMPONENT, new ComponentInjectionsHoverProvider(this));
|
||||||
providers.put(Annotations.BEAN, new BeanInjectedIntoHoverProvider());
|
providers.put(Annotations.BEAN, new BeanInjectedIntoHoverProvider(this));
|
||||||
|
|
||||||
providers.put(Annotations.CONDITIONAL, new ConditionalsLiveHoverProvider());
|
providers.put(Annotations.CONDITIONAL, new ConditionalsLiveHoverProvider());
|
||||||
providers.put(Annotations.CONDITIONAL_ON_BEAN, new ConditionalsLiveHoverProvider());
|
providers.put(Annotations.CONDITIONAL_ON_BEAN, new ConditionalsLiveHoverProvider());
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.eclipse.lsp4j.Hover;
|
|||||||
import org.eclipse.lsp4j.Range;
|
import org.eclipse.lsp4j.Range;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||||
import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHoverProvider;
|
import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHoverProvider;
|
||||||
@@ -42,6 +43,12 @@ import com.google.common.collect.ImmutableList;
|
|||||||
*/
|
*/
|
||||||
public class AutowiredHoverProvider implements HoverProvider {
|
public class AutowiredHoverProvider implements HoverProvider {
|
||||||
|
|
||||||
|
private BootJavaLanguageServer server;
|
||||||
|
|
||||||
|
public AutowiredHoverProvider(BootJavaLanguageServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||||
try {
|
try {
|
||||||
@@ -155,7 +162,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
|||||||
}
|
}
|
||||||
List<LiveBean> dependencyBeans = beans.getBeansOfName(injectedBean);
|
List<LiveBean> dependencyBeans = beans.getBeansOfName(injectedBean);
|
||||||
for (LiveBean dependencyBean : dependencyBeans) {
|
for (LiveBean dependencyBean : dependencyBeans) {
|
||||||
hover.append("- " + LiveHoverUtils.showBeanWithResource(dependencyBean, " ", project));
|
hover.append("- " + LiveHoverUtils.showBeanWithResource(server, dependencyBean, " ", project));
|
||||||
}
|
}
|
||||||
firstDependency = false;
|
firstDependency = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.links;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||||
|
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
|
||||||
|
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
|
||||||
|
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||||
|
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
|
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer;
|
||||||
|
import org.springframework.ide.vscode.commons.util.text.Region;
|
||||||
|
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base logic for {@link SourceLinks} independent of any client
|
||||||
|
*
|
||||||
|
* @author Alex Boyko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSourceLinks implements SourceLinks {
|
||||||
|
|
||||||
|
private static Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class));
|
||||||
|
|
||||||
|
private BootJavaLanguageServer server;
|
||||||
|
|
||||||
|
protected AbstractSourceLinks(BootJavaLanguageServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
|
||||||
|
Optional<File> classpathResource = project.getClasspath().findClasspathResourceContainer(fqName);
|
||||||
|
if (classpathResource.isPresent()) {
|
||||||
|
File file = classpathResource.get();
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
return javaSourceLinkUrl(project, fqName, file);
|
||||||
|
} else if (file.getName().endsWith(JAR)) {
|
||||||
|
return jarSourceLinkUrl(project, fqName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path) {
|
||||||
|
int idx = path.lastIndexOf(CLASS);
|
||||||
|
if (idx >= 0) {
|
||||||
|
Path p = Paths.get(path.substring(0, idx));
|
||||||
|
return sourceLinkUrlForFQName(project, p.toString().replace(File.separator, "."));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, File containerFolder) {
|
||||||
|
IClasspath classpath = project.getClasspath();
|
||||||
|
if (containerFolder.toPath().startsWith(classpath.getOutputFolder())) {
|
||||||
|
return project.getClasspath().getSourceFolders().stream()
|
||||||
|
.map(sourceFolder -> {
|
||||||
|
try {
|
||||||
|
return Paths.get(sourceFolder).toUri().toURL();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
LOG.get().warn("Failed to convert source folder " + sourceFolder + "to URI." + fqName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(url -> {
|
||||||
|
try {
|
||||||
|
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER.sourceUrl(url, fqName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(url -> {
|
||||||
|
try {
|
||||||
|
return Paths.get(url.toURI());
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
LOG.get().warn("Failed to convert URL " + url + " to path." + fqName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(sourcePath -> sourcePath != null && Files.exists(sourcePath))
|
||||||
|
.findFirst()
|
||||||
|
.map(sourcePath -> javaSourceLinkUrl(project, sourcePath, fqName));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String javaSourceLinkUrl(IJavaProject project, Path sourcePath, String fqName) {
|
||||||
|
Optional<String> linkOptional = sourceLinkForResourcePath(sourcePath);
|
||||||
|
if (linkOptional.isPresent()) {
|
||||||
|
Optional<String> positionLink = findCUForJavaSourceFile(sourcePath).map(cu -> positionLink(cu, fqName));
|
||||||
|
return positionLink.isPresent() ? linkOptional.get() + positionLink.get() : linkOptional.get();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected String positionLink(CompilationUnit cu, String fqName);
|
||||||
|
|
||||||
|
private Optional<CompilationUnit> findCUForJavaSourceFile(Path resourcePath) {
|
||||||
|
Optional<CompilationUnit> cu = findCUfromCache(resourcePath.toUri().toString());
|
||||||
|
if (cu == null) {
|
||||||
|
try {
|
||||||
|
char[] bytes = new String(Files.readAllBytes(resourcePath), Charset.defaultCharset()).toCharArray();
|
||||||
|
String uri = resourcePath.toUri().toString();
|
||||||
|
String unitName = resourcePath.getFileName().toString();
|
||||||
|
cu = Optional.ofNullable(CompilationUnitCache.parse(bytes, uri, unitName, new String[0]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.get().warn("Failed to create CompilationUnit from " + resourcePath, e);
|
||||||
|
cu = Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<CompilationUnit> findCUfromCache(String uri) {
|
||||||
|
Optional<CompilationUnit> cu = null;
|
||||||
|
if (server != null && server.getCompilationUnitCache() != null) {
|
||||||
|
TextDocument doc = server.getTextDocumentService().get(uri);
|
||||||
|
if (doc != null) {
|
||||||
|
cu = server.getCompilationUnitCache().withCompilationUnit(doc, compilationUnit -> compilationUnit == null ? null : Optional.of(compilationUnit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cu;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected Optional<String> jarUrl(IJavaProject project, String fqName, File jarFile);
|
||||||
|
|
||||||
|
private Optional<String> jarSourceLinkUrl(IJavaProject project, String fqName, File jarFile) {
|
||||||
|
return jarUrl(project, fqName, jarFile).map(sourceUrl -> {
|
||||||
|
Optional<String> positionLink = findCUForFQNameFromJar(project, jarFile, sourceUrl, fqName).map(cu -> positionLink(cu, fqName));
|
||||||
|
return positionLink.isPresent() ? sourceUrl + positionLink.get() : sourceUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, File jarFile, String clientSourceUri, String fqName) {
|
||||||
|
Optional<CompilationUnit> cu = findCUfromCache(clientSourceUri);
|
||||||
|
if (cu == null) {
|
||||||
|
cu = project.getClasspath().sourceContainer(jarFile)
|
||||||
|
.map(url -> {
|
||||||
|
try {
|
||||||
|
return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(url, fqName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(sourceUrl -> {
|
||||||
|
InputStream openStream = null;
|
||||||
|
try {
|
||||||
|
openStream = sourceUrl.openStream();
|
||||||
|
char[] bytes = IOUtils.toCharArray(openStream);
|
||||||
|
String uri = sourceUrl.toURI().toString();
|
||||||
|
String unitName = fqName;
|
||||||
|
return CompilationUnitCache.parse(bytes, uri, unitName, new String[0]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.get().warn("Failed to create CompilationUnit from " + sourceUrl, e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (openStream != null) {
|
||||||
|
try {
|
||||||
|
openStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.get().error("Failed to close stream from " + sourceUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return cu;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Region findTypeRegion(CompilationUnit cu, String fqName) {
|
||||||
|
if (cu == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int[] values = new int[] {0, -1};
|
||||||
|
int lastDotIndex = fqName.lastIndexOf('.');
|
||||||
|
String packageName = fqName.substring(0, lastDotIndex);
|
||||||
|
String typeName = fqName.substring(lastDotIndex + 1);
|
||||||
|
if (packageName.equals(cu.getPackage().getName().getFullyQualifiedName())) {
|
||||||
|
Stack<String> visitedType = new Stack<>();
|
||||||
|
cu.accept(new ASTVisitor() {
|
||||||
|
|
||||||
|
private boolean visitDeclaration(AbstractTypeDeclaration node) {
|
||||||
|
visitedType.push(node.getName().getIdentifier());
|
||||||
|
if (values[1] < 0) {
|
||||||
|
if (String.join("$", visitedType.toArray(new String[visitedType.size()])).equals(typeName)) {
|
||||||
|
values[0] = node.getName().getStartPosition();
|
||||||
|
values[1] = node.getName().getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values[1] < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(TypeDeclaration node) {
|
||||||
|
return visitDeclaration(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(AnnotationTypeDeclaration node) {
|
||||||
|
return visitDeclaration(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endVisit(AnnotationTypeDeclaration node) {
|
||||||
|
visitedType.pop();
|
||||||
|
super.endVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endVisit(TypeDeclaration node) {
|
||||||
|
visitedType.pop();
|
||||||
|
super.endVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return values[1] < 0 ? null : new Region(values[0], values[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.links;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for creating {@link SourceLinks}
|
||||||
|
*
|
||||||
|
* @author Alex Boyko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class SourceLinkFactory {
|
||||||
|
|
||||||
|
private static final SourceLinks NO_SOURCE_LINKS = new SourceLinks() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkForResourcePath(Path path) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link SourceLinks} for specific server based on client type
|
||||||
|
* @param server the boot LS
|
||||||
|
* @return appropriate source links object
|
||||||
|
*/
|
||||||
|
public static SourceLinks createSourceLinks(BootJavaLanguageServer server) {
|
||||||
|
switch (LspClient.currentClient()) {
|
||||||
|
case VSCODE:
|
||||||
|
return new VSCodeSourceLinks(server);
|
||||||
|
default:
|
||||||
|
return NO_SOURCE_LINKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.links;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance is able to provide client specific URL links to navigate to a
|
||||||
|
* specific file on the client given various types of data such as fully
|
||||||
|
* qualified java type name or classpath resource or just some file resource
|
||||||
|
* given by its path.
|
||||||
|
*
|
||||||
|
* @author Alex Boyko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SourceLinks {
|
||||||
|
|
||||||
|
static final String JAR = ".jar";
|
||||||
|
static final String CLASS = ".class";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates link to source file defining the type passed with it's fully qualified name
|
||||||
|
* @param project Java project in the context of which source file link is calculated
|
||||||
|
* @param fqName type's fully qualified name
|
||||||
|
* @return the link URL optional
|
||||||
|
*/
|
||||||
|
Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates link to source file corresponding to a classpath resource
|
||||||
|
* @param project project Java project in the context of which source file link is calculated
|
||||||
|
* @param path the path to the classpath resource
|
||||||
|
* @return the link URL optional
|
||||||
|
*/
|
||||||
|
Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates link to a file specified by it's path
|
||||||
|
* @param path the resource path
|
||||||
|
* @return the link URL optional
|
||||||
|
*/
|
||||||
|
Optional<String> sourceLinkForResourcePath(Path path);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.links;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
import org.springframework.ide.vscode.commons.util.text.Region;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VSCode specific source links implementation
|
||||||
|
*
|
||||||
|
* @author Alex Boyko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VSCodeSourceLinks extends AbstractSourceLinks {
|
||||||
|
|
||||||
|
private static Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class));
|
||||||
|
|
||||||
|
public VSCodeSourceLinks(BootJavaLanguageServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> sourceLinkForResourcePath(Path path) {
|
||||||
|
return Optional.of(path.toUri().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String positionLink(CompilationUnit cu, String fqName) {
|
||||||
|
if (cu != null) {
|
||||||
|
Region region = findTypeRegion(cu, fqName);
|
||||||
|
if (region != null) {
|
||||||
|
int column = cu.getColumnNumber(region.getOffset());
|
||||||
|
int line = cu.getLineNumber(region.getOffset());
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append('#');
|
||||||
|
sb.append(line);
|
||||||
|
sb.append(',');
|
||||||
|
sb.append(column + 1); // 1-based columns?
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<String> jarUrl(IJavaProject project, String fqName, File jarFile) {
|
||||||
|
try {
|
||||||
|
int lastDotIndex = fqName.lastIndexOf('.');
|
||||||
|
String packageName = fqName.substring(0, lastDotIndex);
|
||||||
|
String typeName = fqName.substring(lastDotIndex + 1);
|
||||||
|
String jarFileName = jarFile.getName();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("jdt://contents/");
|
||||||
|
sb.append(jarFileName);
|
||||||
|
sb.append("/");
|
||||||
|
sb.append(packageName);
|
||||||
|
sb.append("/");
|
||||||
|
sb.append(typeName);
|
||||||
|
sb.append(CLASS);
|
||||||
|
sb.append("?");
|
||||||
|
|
||||||
|
StringBuilder query = new StringBuilder();
|
||||||
|
query.append("=");
|
||||||
|
query.append(project.getElementName());
|
||||||
|
query.append("/");
|
||||||
|
String convertedPath = jarFile.toString().replace(File.separator, "\\/");
|
||||||
|
query.append(convertedPath);
|
||||||
|
query.append("<");
|
||||||
|
query.append(packageName);
|
||||||
|
query.append("(");
|
||||||
|
query.append(typeName);
|
||||||
|
query.append(CLASS);
|
||||||
|
|
||||||
|
sb.append(URLEncoder.encode(query.toString(), "UTF8"));
|
||||||
|
|
||||||
|
return Optional.of(sb.toString());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
LOG.get().warn("Failed creating source URI for jar " + jarFile + " type " + fqName + " in the context of project " + project.getElementName(), t);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2017 Pivotal, Inc.
|
* Copyright (c) 2017, 2018 Pivotal, Inc.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -22,6 +22,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
|
|||||||
import org.eclipse.lsp4j.Hover;
|
import org.eclipse.lsp4j.Hover;
|
||||||
import org.eclipse.lsp4j.Range;
|
import org.eclipse.lsp4j.Range;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||||
@@ -35,6 +36,12 @@ import com.google.common.collect.ImmutableList;
|
|||||||
|
|
||||||
public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider {
|
public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider {
|
||||||
|
|
||||||
|
protected BootJavaLanguageServer server;
|
||||||
|
|
||||||
|
public AbstractInjectedIntoHoverProvider(BootJavaLanguageServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||||
// Highlight if any running app contains an instance of this component
|
// Highlight if any running app contains an instance of this component
|
||||||
@@ -113,7 +120,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
|||||||
if (!firstDependency) {
|
if (!firstDependency) {
|
||||||
hover.append("\n");
|
hover.append("\n");
|
||||||
}
|
}
|
||||||
hover.append("- " + LiveHoverUtils.showBeanWithResource(dependingBean, " ", project));
|
hover.append("- " + LiveHoverUtils.showBeanWithResource(server, dependingBean, " ", project));
|
||||||
firstDependency = false;
|
firstDependency = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.eclipse.jdt.core.dom.MethodDeclaration;
|
|||||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||||
import org.eclipse.lsp4j.Hover;
|
import org.eclipse.lsp4j.Hover;
|
||||||
import org.eclipse.lsp4j.Range;
|
import org.eclipse.lsp4j.Range;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||||
@@ -29,6 +30,10 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
|||||||
|
|
||||||
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
|
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||||
|
|
||||||
|
public BeanInjectedIntoHoverProvider(BootJavaLanguageServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LiveBean getDefinedBean(Annotation annotation) {
|
protected LiveBean getDefinedBean(Annotation annotation) {
|
||||||
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod(annotation);
|
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod(annotation);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.eclipse.lsp4j.Hover;
|
|||||||
import org.eclipse.lsp4j.Range;
|
import org.eclipse.lsp4j.Range;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||||
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
|
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||||
@@ -43,6 +44,10 @@ import reactor.util.function.Tuple3;
|
|||||||
|
|
||||||
public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverProvider {
|
public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||||
|
|
||||||
|
public ComponentInjectionsHoverProvider(BootJavaLanguageServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addAutomaticallyWiredContructor(StringBuilder hover, Annotation annotation, LiveBeansModel beans, LiveBean bean, IJavaProject project) {
|
protected void addAutomaticallyWiredContructor(StringBuilder hover, Annotation annotation, LiveBeansModel beans, LiveBean bean, IJavaProject project) {
|
||||||
TypeDeclaration typeDecl = ASTUtils.findDeclaringType(annotation);
|
TypeDeclaration typeDecl = ASTUtils.findDeclaringType(annotation);
|
||||||
@@ -63,7 +68,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
|||||||
}
|
}
|
||||||
List<LiveBean> dependencyBeans = beans.getBeansOfName(injectedBean);
|
List<LiveBean> dependencyBeans = beans.getBeansOfName(injectedBean);
|
||||||
for (LiveBean dependencyBean : dependencyBeans) {
|
for (LiveBean dependencyBean : dependencyBeans) {
|
||||||
hover.append("- " + LiveHoverUtils.showBeanWithResource(dependencyBean, " ", project));
|
hover.append("- " + LiveHoverUtils.showBeanWithResource(server, dependencyBean, " ", project));
|
||||||
}
|
}
|
||||||
firstDependency = false;
|
firstDependency = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ package org.springframework.ide.vscode.boot.java.livehover;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.springframework.ide.vscode.boot.java.utils.SourceLinks;
|
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||||
|
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||||
|
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.SpringResource;
|
import org.springframework.ide.vscode.boot.java.utils.SpringResource;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||||
@@ -34,18 +36,19 @@ public class LiveHoverUtils {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String showBeanWithResource(LiveBean bean, String indentStr, IJavaProject project) {
|
public static String showBeanWithResource(BootJavaLanguageServer server, LiveBean bean, String indentStr, IJavaProject project) {
|
||||||
String newline = " \n"+indentStr; //Note: the double space before newline makes markdown see it as a real line break
|
String newline = " \n"+indentStr; //Note: the double space before newline makes markdown see it as a real line break
|
||||||
|
|
||||||
String type = bean.getType(true);
|
String type = bean.getType(true);
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder("Bean: ");
|
StringBuilder buf = new StringBuilder("Bean: ");
|
||||||
buf.append(bean.getId());
|
buf.append(bean.getId());
|
||||||
|
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
// Try creating a URL link to open source for the type
|
// Try creating a URL link to open source for the type
|
||||||
buf.append(newline);
|
buf.append(newline);
|
||||||
buf.append("Type: ");
|
buf.append("Type: ");
|
||||||
Optional<String> url = SourceLinks.sourceLinkUrlForFQName(project, type);
|
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||||
if (url.isPresent()) {
|
if (url.isPresent()) {
|
||||||
buf.append(Renderables.link(type, url.get()).toMarkdown());
|
buf.append(Renderables.link(type, url.get()).toMarkdown());
|
||||||
} else {
|
} else {
|
||||||
@@ -56,13 +59,13 @@ public class LiveHoverUtils {
|
|||||||
if (StringUtil.hasText(resource)) {
|
if (StringUtil.hasText(resource)) {
|
||||||
buf.append(newline);
|
buf.append(newline);
|
||||||
buf.append("Resource: ");
|
buf.append("Resource: ");
|
||||||
buf.append(showResource(resource, project));
|
buf.append(showResource(sourceLinks, resource, project));
|
||||||
}
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String showResource(String resource, IJavaProject project) {
|
public static String showResource(SourceLinks sourceLinks, String resource, IJavaProject project) {
|
||||||
return new SpringResource(resource, project).toMarkdown();
|
return new SpringResource(sourceLinks, resource, project).toMarkdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String niceAppName(SpringBootApp app) {
|
public static String niceAppName(SpringBootApp app) {
|
||||||
|
|||||||
@@ -133,6 +133,14 @@ public final class CompilationUnitCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
|
public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
|
||||||
|
String[] classpathEntries = getClasspathEntries(document, project);
|
||||||
|
String docURI = document.getUri();
|
||||||
|
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||||
|
char[] source = document.get(0, document.getLength()).toCharArray();
|
||||||
|
return parse(source, docURI, unitName, classpathEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception {
|
||||||
ASTParser parser = ASTParser.newParser(AST.JLS9);
|
ASTParser parser = ASTParser.newParser(AST.JLS9);
|
||||||
Map<String, String> options = JavaCore.getOptions();
|
Map<String, String> options = JavaCore.getOptions();
|
||||||
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
|
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
|
||||||
@@ -142,14 +150,11 @@ public final class CompilationUnitCache {
|
|||||||
parser.setBindingsRecovery(true);
|
parser.setBindingsRecovery(true);
|
||||||
parser.setResolveBindings(true);
|
parser.setResolveBindings(true);
|
||||||
|
|
||||||
String[] classpathEntries = getClasspathEntries(document, project);
|
|
||||||
String[] sourceEntries = new String[] {};
|
String[] sourceEntries = new String[] {};
|
||||||
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
||||||
|
|
||||||
String docURI = document.getUri();
|
|
||||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
|
||||||
parser.setUnitName(unitName);
|
parser.setUnitName(unitName);
|
||||||
parser.setSource(document.get(0, document.getLength()).toCharArray());
|
parser.setSource(source);
|
||||||
|
|
||||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||||
|
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* 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.utils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
|
||||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
|
||||||
import org.springframework.ide.vscode.commons.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for creating code navigate links for Markdown format documentation.
|
|
||||||
* The utility looks at the environment variable "sts.lsp.client" to create a URL supported on a specific client
|
|
||||||
*
|
|
||||||
* @author Alex Boyko
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class SourceLinks {
|
|
||||||
|
|
||||||
static final String JAR = ".jar";
|
|
||||||
static final String JAVA = ".java";
|
|
||||||
static final String CLASS = ".class";
|
|
||||||
|
|
||||||
public static Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
|
|
||||||
switch (LspClient.currentClient()) {
|
|
||||||
case VSCODE:
|
|
||||||
return createVSCodeSourceLink(project, fqName);
|
|
||||||
default:
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path) {
|
|
||||||
switch (LspClient.currentClient()) {
|
|
||||||
case VSCODE:
|
|
||||||
return createVSCodeSourceLinkForClasspathResource(project, path);
|
|
||||||
default:
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<String> sourceLinkForResourcePath(Path path) {
|
|
||||||
switch (LspClient.currentClient()) {
|
|
||||||
case VSCODE:
|
|
||||||
return Optional.of(createVSCodeLink(path));
|
|
||||||
default:
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<String> createVSCodeSourceLinkForClasspathResource(IJavaProject project, String path) {
|
|
||||||
int idx = path.lastIndexOf(SourceLinks.CLASS);
|
|
||||||
if (idx >= 0) {
|
|
||||||
Path p = Paths.get(path.substring(0, idx));
|
|
||||||
return SourceLinks.sourceLinkUrlForFQName(project, p.toString().replace(File.separator, "."));
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String createVSCodeLink(Path path) {
|
|
||||||
return path.toUri().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<String> createVSCodeSourceLink(IJavaProject project, String fqName) {
|
|
||||||
Optional<File> classpathResource = project.getClasspath().findClasspathResourceContainer(fqName);
|
|
||||||
if (classpathResource.isPresent()) {
|
|
||||||
File file = classpathResource.get();
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
return javaSourceLinkUrl(project, fqName, file);
|
|
||||||
} else if (file.getName().endsWith(JAR)) {
|
|
||||||
return jarSourceLinkUrl(project, fqName, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<String> javaSourceLinkUrl(IJavaProject project, String javaRelativePath, String fqName) {
|
|
||||||
Path path = Paths.get(javaRelativePath);
|
|
||||||
Optional<Path> sourceResource = project.getClasspath().getSourceFolders().stream()
|
|
||||||
.map(r -> Paths.get(r).resolve(path)).filter(r -> Files.exists(r)).findFirst();
|
|
||||||
if (sourceResource.isPresent()) {
|
|
||||||
return Optional.of(sourceResource.get().toUri().toString());
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, File containerFolder) {
|
|
||||||
IClasspath classpath = project.getClasspath();
|
|
||||||
if (containerFolder.toPath().startsWith(classpath.getOutputFolder())) {
|
|
||||||
int innerTypeIdx = fqName.indexOf('$');
|
|
||||||
String topLevelType = innerTypeIdx > 0 ? fqName.substring(0, innerTypeIdx) : fqName;
|
|
||||||
return javaSourceLinkUrl(project, topLevelType.replaceAll("\\.", "/") + JAVA, fqName);
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<String> jarSourceLinkUrl(IJavaProject project, String fqName, File jarFile) {
|
|
||||||
try {
|
|
||||||
int lastDotIndex = fqName.lastIndexOf('.');
|
|
||||||
String packageName = fqName.substring(0, lastDotIndex);
|
|
||||||
String typeName = fqName.substring(lastDotIndex + 1);
|
|
||||||
String jarFileName = jarFile.getName();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("jdt://contents/");
|
|
||||||
sb.append(jarFileName);
|
|
||||||
sb.append("/");
|
|
||||||
sb.append(packageName);
|
|
||||||
sb.append("/");
|
|
||||||
sb.append(typeName);
|
|
||||||
sb.append(CLASS);
|
|
||||||
sb.append("?");
|
|
||||||
|
|
||||||
StringBuilder query = new StringBuilder();
|
|
||||||
query.append("=");
|
|
||||||
query.append(project.getElementName());
|
|
||||||
query.append("/");
|
|
||||||
String convertedPath = jarFile.toString().replace(File.separator, "\\/");
|
|
||||||
query.append(convertedPath);
|
|
||||||
query.append("<");
|
|
||||||
query.append(packageName);
|
|
||||||
query.append("(");
|
|
||||||
query.append(typeName);
|
|
||||||
query.append(CLASS);
|
|
||||||
|
|
||||||
sb.append(URLEncoder.encode(query.toString(), "UTF8"));
|
|
||||||
|
|
||||||
return Optional.of(sb.toString());
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.log(t);
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// private static Optional<Region> findTypeRange(CompilationUnit cu, String fqName) {
|
|
||||||
// int[] values = new int[] {0, -1};
|
|
||||||
// int lastDotIndex = fqName.lastIndexOf('.');
|
|
||||||
// String packageName = fqName.substring(0, lastDotIndex);
|
|
||||||
// String typeName = fqName.substring(lastDotIndex + 1);
|
|
||||||
// if (packageName.equals(cu.getPackage().getName().getFullyQualifiedName())) {
|
|
||||||
// Stack<String> visitedType = new Stack<>();
|
|
||||||
// cu.accept(new ASTVisitor() {
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public boolean visit(TypeDeclaration node) {
|
|
||||||
// if (values[1] < 0) {
|
|
||||||
// visitedType.push(node.getName().getIdentifier());
|
|
||||||
// if (String.join("$", visitedType.toArray(new String[visitedType.size()])).equals(typeName)) {
|
|
||||||
// values[0] = node.getName().getStartPosition();
|
|
||||||
// values[1] = node.getName().getLength();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return values[1] < 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void endVisit(TypeDeclaration node) {
|
|
||||||
// visitedType.pop();
|
|
||||||
// super.endVisit(node);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// return Optional.ofNullable(values[1] < 0 ? null : new Region(values[0], values[1]));
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,16 +10,15 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.springframework.ide.vscode.boot.java.utils;
|
package org.springframework.ide.vscode.boot.java.utils;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
|
||||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,13 +30,15 @@ public class SpringResource {
|
|||||||
private static final String FILE = "file";
|
private static final String FILE = "file";
|
||||||
private static final String CLASS_PATH_RESOURCE = "class path resource";
|
private static final String CLASS_PATH_RESOURCE = "class path resource";
|
||||||
|
|
||||||
|
private SourceLinks sourceLinks;
|
||||||
private String type;
|
private String type;
|
||||||
private String path;
|
private String path;
|
||||||
private IJavaProject project;
|
private IJavaProject project;
|
||||||
|
|
||||||
private static final Pattern BRACKETS = Pattern.compile("\\[[^\\]]*\\]");
|
private static final Pattern BRACKETS = Pattern.compile("\\[[^\\]]*\\]");
|
||||||
|
|
||||||
public SpringResource(String toParse, IJavaProject project) {
|
public SpringResource(SourceLinks sourceLinks, String toParse, IJavaProject project) {
|
||||||
|
this.sourceLinks = sourceLinks;
|
||||||
this.project = project;
|
this.project = project;
|
||||||
Matcher matcher = BRACKETS.matcher(toParse);
|
Matcher matcher = BRACKETS.matcher(toParse);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
@@ -57,15 +58,15 @@ public class SpringResource {
|
|||||||
case FILE:
|
case FILE:
|
||||||
String relativePath = projectRelativePath(path);
|
String relativePath = projectRelativePath(path);
|
||||||
if (relativePath != path && path.endsWith(SourceLinks.CLASS)) {
|
if (relativePath != path && path.endsWith(SourceLinks.CLASS)) {
|
||||||
linkUrl = SourceLinks.sourceLinkUrlForClasspathResource(project, relativePath);
|
linkUrl = sourceLinks.sourceLinkUrlForClasspathResource(project, relativePath);
|
||||||
} else {
|
} else {
|
||||||
linkUrl = SourceLinks.sourceLinkForResourcePath(Paths.get(path));
|
linkUrl = sourceLinks.sourceLinkForResourcePath(Paths.get(path));
|
||||||
}
|
}
|
||||||
// not a project relative path
|
// not a project relative path
|
||||||
return linkUrl.isPresent() ? Renderables.link(relativePath, linkUrl.get()).toMarkdown()
|
return linkUrl.isPresent() ? Renderables.link(relativePath, linkUrl.get()).toMarkdown()
|
||||||
: "`" + projectRelativePath(path) + "`";
|
: "`" + projectRelativePath(path) + "`";
|
||||||
case CLASS_PATH_RESOURCE:
|
case CLASS_PATH_RESOURCE:
|
||||||
linkUrl = SourceLinks.sourceLinkUrlForClasspathResource(project, path);
|
linkUrl = sourceLinks.sourceLinkUrlForClasspathResource(project, path);
|
||||||
return linkUrl.isPresent() ? Renderables.link(path, linkUrl.get()).toMarkdown() : "`"+path+"`";
|
return linkUrl.isPresent() ? Renderables.link(path, linkUrl.get()).toMarkdown() : "`"+path+"`";
|
||||||
default:
|
default:
|
||||||
return path;
|
return path;
|
||||||
|
|||||||
@@ -18,11 +18,8 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.ide.vscode.boot.java.utils.SourceLinks;
|
import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
|
||||||
import org.springframework.ide.vscode.commons.maven.MavenBuilder;
|
import org.springframework.ide.vscode.commons.maven.MavenBuilder;
|
||||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||||
@@ -50,42 +47,38 @@ public class VSCodeSourceLinksTest {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setupAll() throws Exception {
|
|
||||||
System.setProperty("sts.lsp.client", LspClient.Client.VSCODE.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDownAll() throws Exception {
|
|
||||||
System.setProperty("sts.lsp.client", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJavaSourceUrl() throws Exception {
|
public void testJavaSourceUrl() throws Exception {
|
||||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||||
Optional<String> url = SourceLinks.sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
|
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
|
||||||
assertTrue(url.isPresent());
|
assertTrue(url.isPresent());
|
||||||
Path projectPath = Paths.get(project.pom().getParent());
|
Path projectPath = Paths.get(project.pom().getParent());
|
||||||
Path relativePath = projectPath.relativize(Paths.get(new URL(url.get()).toURI()));
|
Path relativePath = projectPath.relativize(Paths.get(new URL(url.get()).getPath()));
|
||||||
assertEquals(Paths.get("src/main/java/com/example/EmptyBoot15WebAppApplication.java"), relativePath);
|
assertEquals(Paths.get("src/main/java/com/example/EmptyBoot15WebAppApplication.java"), relativePath);
|
||||||
|
String positionPart = url.get().substring(url.get().lastIndexOf('#'));
|
||||||
|
assertEquals("#7,14", positionPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJarUrl() throws Exception {
|
public void testJarUrl() throws Exception {
|
||||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||||
Optional<String> url = SourceLinks.sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication");
|
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication");
|
||||||
assertTrue(url.isPresent());
|
assertTrue(url.isPresent());
|
||||||
String headerPart = url.get().substring(0, url.get().indexOf('?'));
|
String headerPart = url.get().substring(0, url.get().indexOf('?'));
|
||||||
assertEquals("jdt://contents/spring-boot-autoconfigure-1.5.8.RELEASE.jar/org.springframework.boot.autoconfigure/SpringBootApplication.class", headerPart);
|
assertEquals("jdt://contents/spring-boot-autoconfigure-1.5.8.RELEASE.jar/org.springframework.boot.autoconfigure/SpringBootApplication.class", headerPart);
|
||||||
|
String positionPart = url.get().substring(url.get().lastIndexOf('#'));
|
||||||
|
assertEquals("#55,19", positionPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJarUrlInnerType() throws Exception {
|
public void testJarUrlInnerType() throws Exception {
|
||||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||||
Optional<String> url = SourceLinks.sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback");
|
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback");
|
||||||
assertTrue(url.isPresent());
|
assertTrue(url.isPresent());
|
||||||
String headerPart = url.get().substring(0, url.get().indexOf('?'));
|
String headerPart = url.get().substring(0, url.get().indexOf('?'));
|
||||||
assertEquals("jdt://contents/spring-web-4.3.12.RELEASE.jar/org.springframework.web.client/RestTemplate$AcceptHeaderRequestCallback.class", headerPart);
|
assertEquals("jdt://contents/spring-web-4.3.12.RELEASE.jar/org.springframework.web.client/RestTemplate$AcceptHeaderRequestCallback.class", headerPart);
|
||||||
|
String positionPart = url.get().substring(url.get().lastIndexOf('#'));
|
||||||
|
assertEquals("#747,16", positionPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class GradleProjectClasspath extends JandexClasspath {
|
|||||||
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
|
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
|
||||||
return new HtmlJavadocProvider(
|
return new HtmlJavadocProvider(
|
||||||
(type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
(type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(javadocUrl, type));
|
.sourceUrl(javadocUrl, type.getFullyQualifiedName()));
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
Log.log(e);
|
Log.log(e);
|
||||||
return null;
|
return null;
|
||||||
@@ -150,7 +150,7 @@ public class GradleProjectClasspath extends JandexClasspath {
|
|||||||
if (classpathFolder.isPresent()) {
|
if (classpathFolder.isPresent()) {
|
||||||
return new ParserJavadocProvider(type -> {
|
return new ParserJavadocProvider(type -> {
|
||||||
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(classpathFolder.get().toURI().toURL(), type);
|
.sourceUrl(classpathFolder.get().toURI().toURL(), type.getFullyQualifiedName());
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -248,4 +248,9 @@ public class GradleProjectClasspath extends JandexClasspath {
|
|||||||
return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder());
|
return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<URL> sourceContainer(File classpathResource) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package org.springframework.ide.vscode.commons.java;
|
package org.springframework.ide.vscode.commons.java;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@@ -179,4 +180,10 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<URL> sourceContainer(File classpathResource) {
|
||||||
|
T t = cachedClasspath.get();
|
||||||
|
return t == null ? Optional.empty() : t.sourceContainer(classpathResource);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package org.springframework.ide.vscode.commons.java;
|
package org.springframework.ide.vscode.commons.java;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -64,4 +65,6 @@ public interface IClasspath {
|
|||||||
ClasspathData createClasspathData() throws Exception;
|
ClasspathData createClasspathData() throws Exception;
|
||||||
|
|
||||||
void reindex();
|
void reindex();
|
||||||
|
|
||||||
|
Optional<URL> sourceContainer(File classpathResource);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,51 +14,54 @@ package org.springframework.ide.vscode.commons.javadoc;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import org.springframework.ide.vscode.commons.java.IType;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface SourceUrlProviderFromSourceContainer {
|
public interface SourceUrlProviderFromSourceContainer {
|
||||||
|
|
||||||
public static final SourceUrlProviderFromSourceContainer JAR_SOURCE_URL_PROVIDER = (sourceContainerUrl, type) -> {
|
static String extractTopLevelType(String fqName) {
|
||||||
|
int innerTypeIdx = fqName.indexOf('$');
|
||||||
|
return innerTypeIdx > 0 ? fqName.substring(0, innerTypeIdx) : fqName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final SourceUrlProviderFromSourceContainer JAR_SOURCE_URL_PROVIDER = (sourceContainerUrl, fqName) -> {
|
||||||
StringBuilder sourceUrlStr = new StringBuilder();
|
StringBuilder sourceUrlStr = new StringBuilder();
|
||||||
sourceUrlStr.append("jar:");
|
sourceUrlStr.append("jar:");
|
||||||
sourceUrlStr.append(sourceContainerUrl);
|
sourceUrlStr.append(sourceContainerUrl);
|
||||||
sourceUrlStr.append("!");
|
sourceUrlStr.append("!");
|
||||||
sourceUrlStr.append('/');
|
sourceUrlStr.append('/');
|
||||||
sourceUrlStr.append(type.getFullyQualifiedName().replaceAll("\\.", "/"));
|
sourceUrlStr.append(extractTopLevelType(fqName).replaceAll("\\.", "/"));
|
||||||
sourceUrlStr.append(".java");
|
sourceUrlStr.append(".java");
|
||||||
return new URL(sourceUrlStr.toString());
|
return new URL(sourceUrlStr.toString());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final SourceUrlProviderFromSourceContainer SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, type) -> {
|
public static final SourceUrlProviderFromSourceContainer SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
|
||||||
return Paths.get(sourceContainerUrl.toURI()).resolve(type.getFullyQualifiedName().replaceAll("\\.", "/") + ".java").toUri().toURL();
|
return Paths.get(sourceContainerUrl.toURI()).resolve(extractTopLevelType(fqName).replaceAll("\\.", "/") + ".java").toUri().toURL();
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final SourceUrlProviderFromSourceContainer JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, type) -> {
|
public static final SourceUrlProviderFromSourceContainer JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, fqName) -> {
|
||||||
StringBuilder sourceUrlStr = new StringBuilder();
|
StringBuilder sourceUrlStr = new StringBuilder();
|
||||||
sourceUrlStr.append("jar:");
|
sourceUrlStr.append("jar:");
|
||||||
sourceUrlStr.append(javadocContainerUrl);
|
sourceUrlStr.append(javadocContainerUrl);
|
||||||
sourceUrlStr.append("!");
|
sourceUrlStr.append("!");
|
||||||
sourceUrlStr.append('/');
|
sourceUrlStr.append('/');
|
||||||
// Inner classes are in separate Top.Nesting1.Nesting2.Nesting3.MyType.html files
|
// Inner classes are in separate Top.Nesting1.Nesting2.Nesting3.MyType.html files
|
||||||
sourceUrlStr.append(type.getFullyQualifiedName().replaceAll("\\.", "/").replaceAll("\\$", "."));
|
sourceUrlStr.append(fqName.replaceAll("\\.", "/").replaceAll("\\$", "."));
|
||||||
sourceUrlStr.append(".html");
|
sourceUrlStr.append(".html");
|
||||||
return new URL(sourceUrlStr.toString());
|
return new URL(sourceUrlStr.toString());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final SourceUrlProviderFromSourceContainer JAVADOC_FOLDER_URL_SUPPLIER = (sourceContainerUrl, type) -> {
|
public static final SourceUrlProviderFromSourceContainer JAVADOC_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
|
||||||
String urlStr = sourceContainerUrl.toString();
|
String urlStr = sourceContainerUrl.toString();
|
||||||
StringBuilder sb = new StringBuilder(urlStr);
|
StringBuilder sb = new StringBuilder(urlStr);
|
||||||
if (!urlStr.endsWith("/")) {
|
if (!urlStr.endsWith("/")) {
|
||||||
sb.append('/');
|
sb.append('/');
|
||||||
}
|
}
|
||||||
// Inner classes are in separate Top.Nesting1.Nesting2.Nesting3.MyType.html files
|
// Inner classes are in separate Top.Nesting1.Nesting2.Nesting3.MyType.html files
|
||||||
sb.append(type.getFullyQualifiedName().replaceAll("\\.", "/").replaceAll("\\$", ".") + ".html");
|
sb.append(fqName.replaceAll("\\.", "/").replaceAll("\\$", ".") + ".html");
|
||||||
return new URL(sb.toString());
|
return new URL(sb.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
URL sourceUrl(URL sourceContainerUrl, IType type) throws Exception;
|
URL sourceUrl(URL sourceContainerUrl, String fqName) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class MavenCore {
|
|||||||
javaVersion = "8";
|
javaVersion = "8";
|
||||||
}
|
}
|
||||||
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
|
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
|
||||||
return new HtmlJavadocProvider((type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER.sourceUrl(javadocUrl, type));
|
return new HtmlJavadocProvider((type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER.sourceUrl(javadocUrl, type.getFullyQualifiedName()));
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
Log.log(e);
|
Log.log(e);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -184,6 +185,7 @@ public class MavenProjectClasspath extends JandexClasspath {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IJavadocProvider createParserJavadocProvider(File classpathResource) {
|
protected IJavadocProvider createParserJavadocProvider(File classpathResource) {
|
||||||
if (cachedData == null) {
|
if (cachedData == null) {
|
||||||
@@ -193,32 +195,46 @@ public class MavenProjectClasspath extends JandexClasspath {
|
|||||||
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
|
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
|
||||||
return new ParserJavadocProvider(type -> {
|
return new ParserJavadocProvider(type -> {
|
||||||
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(new File(cachedData.sourceDirectory).toURI().toURL(), type);
|
.sourceUrl(new File(cachedData.sourceDirectory).toURI().toURL(), type.getFullyQualifiedName());
|
||||||
});
|
});
|
||||||
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
|
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
|
||||||
return new ParserJavadocProvider(type -> {
|
return new ParserJavadocProvider(type -> {
|
||||||
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(new File(cachedData.testSourceDirectory).toURI().toURL(), type);
|
.sourceUrl(new File(cachedData.testSourceDirectory).toURI().toURL(), type.getFullyQualifiedName());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
|
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Assume it's a JAR file
|
// Assume it's a JAR file
|
||||||
return new ParserJavadocProvider(type -> {
|
return new ParserJavadocProvider(type -> sourceContainer(classpathResource).map(url -> {
|
||||||
try {
|
try {
|
||||||
Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get();
|
return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(url,
|
||||||
URL sourceContainer = maven.getSources(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
|
type.getFullyQualifiedName());
|
||||||
return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(sourceContainer,
|
} catch (Exception e) {
|
||||||
type);
|
Log.log(e);
|
||||||
} catch (MavenException e) {
|
return null;
|
||||||
Log.log("Failed to find sources JAR for " + classpathResource, e);
|
}
|
||||||
|
}).get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<URL> sourceContainer(File classpathResource) {
|
||||||
|
if (cachedData == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().map(artifact -> {
|
||||||
|
try {
|
||||||
|
return maven.getSources(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
Log.log("Invalid URL for sources JAR for " + classpathResource, e);
|
Log.log("Invalid URL for sources JAR for " + classpathResource, e);
|
||||||
|
return null;
|
||||||
|
} catch (MavenException e) {
|
||||||
|
Log.log("Failed to find sources JAR for " + classpathResource, e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,12 +246,12 @@ public class MavenProjectClasspath extends JandexClasspath {
|
|||||||
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
|
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
|
||||||
return new HtmlJavadocProvider(type -> {
|
return new HtmlJavadocProvider(type -> {
|
||||||
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type);
|
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type.getFullyQualifiedName());
|
||||||
});
|
});
|
||||||
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
|
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
|
||||||
return new ParserJavadocProvider(type -> {
|
return new ParserJavadocProvider(type -> {
|
||||||
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
|
||||||
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type);
|
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type.getFullyQualifiedName());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
|
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
|
||||||
@@ -247,7 +263,7 @@ public class MavenProjectClasspath extends JandexClasspath {
|
|||||||
Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get();
|
Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get();
|
||||||
URL sourceContainer = maven.getJavadoc(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
|
URL sourceContainer = maven.getJavadoc(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
|
||||||
return SourceUrlProviderFromSourceContainer.JAR_JAVADOC_URL_PROVIDER.sourceUrl(sourceContainer,
|
return SourceUrlProviderFromSourceContainer.JAR_JAVADOC_URL_PROVIDER.sourceUrl(sourceContainer,
|
||||||
type);
|
type.getFullyQualifiedName());
|
||||||
} catch (MavenException e) {
|
} catch (MavenException e) {
|
||||||
Log.log("Failed to find sources JAR for " + classpathResource, e);
|
Log.log("Failed to find sources JAR for " + classpathResource, e);
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package org.springframework.ide.vscode.commons.maven.java.classpathfile;
|
package org.springframework.ide.vscode.commons.maven.java.classpathfile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -108,4 +109,9 @@ public class FileClasspath implements IClasspath {
|
|||||||
@Override
|
@Override
|
||||||
public void reindex() {
|
public void reindex() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<URL> sourceContainer(File classpathResource) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user