diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java index ae0ebb408..8e1624e50 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java @@ -182,7 +182,8 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La method.setAccessible(true); method.invoke(sourceViewer); } catch (InvocationTargetException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) { - LanguageServerCommonsActivator.logError(e, ""); + // don't log the exception + ((ISourceViewerExtension5) sourceViewer).updateCodeMinings(); } } else { ((ISourceViewerExtension5) sourceViewer).updateCodeMinings(); @@ -312,7 +313,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La JavadocResponse response = new JavadocResponse(); try { String content = JavadocUtils.javadoc(JavaDoc2MarkdownConverter::getMarkdownContentReader, - URI.create(params.getProjectUri()), params.getBindingKey()); + URI.create(params.getProjectUri()), params.getBindingKey(), JavaDataParams.isLookInOtherProjects(params)); response.setContent(content); } catch (Exception e) { LanguageServerCommonsActivator.logError(e, "Failed getting javadoc for " + params.toString()); @@ -347,7 +348,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La @Override public CompletableFuture javaType(JavaDataParams params) { - JavaTypeResponse response = new JavaTypeResponse(JAVA_DATA.typeData(params.getProjectUri(), params.getBindingKey())); + JavaTypeResponse response = new JavaTypeResponse(JAVA_DATA.typeData(params.getProjectUri(), params.getBindingKey(), JavaDataParams.isLookInOtherProjects(params))); return CompletableFuture.completedFuture(response); } @@ -355,7 +356,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La public CompletableFuture javadocHoverLink(JavaDataParams params) { JavadocHoverLinkResponse response = new JavadocHoverLinkResponse(null); try { - IJavaElement element = JavaData.findElement(URI.create(params.getProjectUri()), params.getBindingKey()); + IJavaElement element = JavaData.findElement(URI.create(params.getProjectUri()), params.getBindingKey(), JavaDataParams.isLookInOtherProjects(params)); if (element != null) { response.setLink(JavaElementLinks.createURI(JavaElementLinks.OPEN_LINK_SCHEME, element)); } diff --git a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java index ed35a83c4..5370dca08 100644 --- a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java +++ b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -90,20 +90,26 @@ public class GradleProjectClasspath implements IClasspath { for (EclipseProjectDependency dep : project.getProjectDependencies()) { EclipseProject peer = findPeer(root, dep.getTargetProject().getName()); if (peer!=null) { - entries.add(new CPE(Classpath.ENTRY_KIND_BINARY, - peer.getProjectDirectory().toPath().resolve(peer.getOutputLocation().getPath()).toString() - )); + for (EclipseSourceDirectory sf : peer.getSourceDirectories()) { + entries.add(createSourceCPE(peer, sf)); + } } } for (EclipseSourceDirectory sf : project.getSourceDirectories()) { - File sourceFolder = sf.getDirectory(); - String of = sf.getOutput(); - entries.add(CPE.source(sourceFolder.getAbsoluteFile(), new File(project.getProjectDirectory(), of))); + CPE cpe = createSourceCPE(project, sf); + cpe.setOwn(true); + entries.add(cpe); } return entries.build(); } } + private static CPE createSourceCPE(EclipseProject project, EclipseSourceDirectory sf) { + File sourceFolder = sf.getDirectory(); + String of = sf.getOutput(); + return CPE.source(sourceFolder.getAbsoluteFile(), new File(project.getProjectDirectory(), of)); + } + private EclipseProject findPeer(EclipseProject root, String name) { return root.getChildren().stream().filter(p -> p.getName().equals(name)).findFirst().orElse(null); } diff --git a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinder.java b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinder.java index 2eb8a1024..a1bf7839c 100644 --- a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinder.java +++ b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -14,6 +14,7 @@ import java.io.File; import java.nio.file.FileSystems; import java.nio.file.PathMatcher; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -23,19 +24,19 @@ import org.springframework.ide.vscode.commons.util.FileUtils; /** * Finder for Gradle Projects - * + * * @author Alex Boyko * */ public class GradleProjectFinder extends FileBasedJavaProjectFinder { - + private static List PATH_MATCHERS = Arrays.asList( FileSystems.getDefault().getPathMatcher("glob:**/" + GradleCore.GRADLE_BUILD_FILE), FileSystems.getDefault().getPathMatcher("glob:" + GradleCore.GLOB_GRADLE_FILE) ); - + private GradleProjectCache cache; - + public GradleProjectFinder(GradleProjectCache cache) { super(); this.cache = cache; @@ -50,4 +51,9 @@ public class GradleProjectFinder extends FileBasedJavaProjectFinder { protected Optional findProjectByName(String name) { return cache.projectByName(name); } + + @Override + public Collection all() { + return cache.all(); + } } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/javadoc/JdtLsJavadocProvider.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/javadoc/JdtLsJavadocProvider.java index e7a20c4af..ba9b2b5b2 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/javadoc/JdtLsJavadocProvider.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/javadoc/JdtLsJavadocProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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,7 +61,7 @@ public class JdtLsJavadocProvider implements IJavadocProvider { long start = System.currentTimeMillis(); try { log.info("Fetching javadoc {}", element.getBindingKey()); - JavadocResponse response = client.javadoc(new JavaDataParams(projectUri, element.getBindingKey())).get(10, TimeUnit.SECONDS); + JavadocResponse response = client.javadoc(new JavaDataParams(projectUri, element.getBindingKey(), false)).get(10, TimeUnit.SECONDS); log.info("Fetching javadoc {} took {} ms", element.getBindingKey(), System.currentTimeMillis()-start); return produceJavadocFromMd(response); } catch (InterruptedException | ExecutionException | TimeoutException e) { diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractJavaProjectCache.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractJavaProjectCache.java index 723912e12..8a9764d7f 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractJavaProjectCache.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/AbstractJavaProjectCache.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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.commons.languageserver.java; +import java.util.Collection; import java.util.Optional; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; @@ -21,29 +22,28 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.Sts4LanguageServer; import org.springframework.ide.vscode.commons.util.FileObserver; import org.springframework.ide.vscode.commons.util.ListenerList; -import org.springframework.ide.vscode.commons.util.Log; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; /** * Abstract implementation of java project cache indexed by keys - * + * * @author Alex Boyko * * @param key class * @param

project class */ public abstract class AbstractJavaProjectCache implements JavaProjectCache { - + private static final Logger log = LoggerFactory.getLogger(AbstractJavaProjectCache.class); - + protected Sts4LanguageServer server; private ListenerList listeners = new ListenerList<>(); protected Cache cache = CacheBuilder.newBuilder().build(); - + public AbstractJavaProjectCache(Sts4LanguageServer server) { this.server = server; } @@ -70,16 +70,16 @@ public abstract class AbstractJavaProjectCache implem } } } catch (ExecutionException e) { - Log.log(e); + log.error("", e); return null; } } return null; } - + public Optional projectByName(String name) { ConcurrentMap map = cache.asMap(); - + for (P project : map.values()) { if (project != null && project.getElementName().equals(name)) { return Optional.of(project); @@ -88,11 +88,11 @@ public abstract class AbstractJavaProjectCache implem return Optional.empty(); } - + abstract protected P createProject(K key) throws Exception; - + protected void attachListeners(K key, P project) { - + } @Override @@ -105,17 +105,17 @@ public abstract class AbstractJavaProjectCache implem public void removeListener(Listener listener) { listeners.remove(listener); } - + final protected void notifyProjectCreated(P project) { log.debug("project created {}", project); listeners.forEach(l -> l.created(project)); } - + final protected void notifyProjectChanged(P project) { log.debug("project changed {}", project); listeners.forEach(l -> l.changed(project)); } - + final protected void notifyProjectDeleted(P project) { log.debug("project deleted {}", project); listeners.forEach(l -> l.deleted(project)); @@ -124,4 +124,8 @@ public abstract class AbstractJavaProjectCache implem final protected FileObserver getFileObserver() { return server.getWorkspaceService().getFileObserver(); } + + final public Collection all() { + return cache.asMap().values(); + } } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/CompositeJavaProjectFinder.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/CompositeJavaProjectFinder.java index 73dc1136c..922957182 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/CompositeJavaProjectFinder.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/CompositeJavaProjectFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -19,32 +19,34 @@ import java.util.Optional; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.springframework.ide.vscode.commons.java.IJavaProject; +import com.google.common.collect.ImmutableList; + /** * Composite project manager that acts a single project manager but consists of many project managers - * + * * @author Alex Boyko * */ public class CompositeJavaProjectFinder implements JavaProjectFinder { - + private final List projectFinders; - + public CompositeJavaProjectFinder(Collection projectFinders) { this.projectFinders = new ArrayList<>(projectFinders); } - + public CompositeJavaProjectFinder() { this(Collections.emptyList()); } - + public boolean addJavaProjectFinder(JavaProjectFinder javaProjectFinder) { return projectFinders.add(javaProjectFinder); } - + public boolean removeJavaProjectFinder(JavaProjectFinder javaProjectFinder) { return projectFinders.remove(javaProjectFinder); } - + @Override public Optional find(TextDocumentIdentifier doc) { for (JavaProjectFinder finder : projectFinders) { @@ -56,4 +58,13 @@ public class CompositeJavaProjectFinder implements JavaProjectFinder { return Optional.empty(); } + @Override + public Collection all() { + ImmutableList.Builder builder = ImmutableList.builder(); + for (JavaProjectFinder projectFinder : projectFinders) { + builder.addAll(projectFinder.all()); + } + return builder.build(); + } + } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java index 095302477..18dca4f42 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 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,9 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.languageserver.java; +import java.util.Collection; import java.util.Optional; -import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; +import java.util.stream.Collectors; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -28,13 +29,31 @@ public interface JavaProjectFinder { Optional find(TextDocumentIdentifier doc); + Collection all(); + default JavaProjectFinder filter(Predicate acceptWhen) { - return doc -> this.find(doc).flatMap(jp -> { - if (acceptWhen.test(jp)) { - return Optional.of(jp); + + final JavaProjectFinder delegate = this; + + return new JavaProjectFinder() { + + @Override + public Optional find(TextDocumentIdentifier doc) { + return delegate.find(doc).flatMap(jp -> { + if (acceptWhen.test(jp)) { + return Optional.of(jp); + } + return Optional.empty(); + }); } - return Optional.empty(); - }); + + @Override + public Collection all() { + return delegate.all().stream().filter(acceptWhen).collect(Collectors.toList()); + } + + }; + } } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/Classpath.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/Classpath.java index 4926a0cbf..0706e7a2d 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/Classpath.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/Classpath.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -57,6 +57,7 @@ public class Classpath { private URL sourceContainerUrl; private URL javadocContainerUrl; private boolean isSystem = false; + private boolean isOwn = false; public String getOutputFolder() { return outputFolder; @@ -127,10 +128,19 @@ public class Classpath { this.isSystem = isSystem; } + public boolean isOwn() { + return isOwn; + } + + public void setOwn(boolean isOwn) { + this.isOwn = isOwn; + } + @Override public int hashCode() { final int prime = 31; int result = 1; + result = prime * result + (isOwn ? 1231 : 1237); result = prime * result + (isSystem ? 1231 : 1237); result = prime * result + ((javadocContainerUrl == null) ? 0 : javadocContainerUrl.hashCode()); result = prime * result + ((kind == null) ? 0 : kind.hashCode()); @@ -149,6 +159,8 @@ public class Classpath { if (getClass() != obj.getClass()) return false; CPE other = (CPE) obj; + if (isOwn != other.isOwn) + return false; if (isSystem != other.isSystem) return false; if (javadocContainerUrl == null) { @@ -181,12 +193,19 @@ public class Classpath { @Override public String toString() { - return "CPE [kind=" + kind + ", path=" + path + ", isSystem=" + isSystem + "]"; + return "CPE [kind=" + kind + ", path=" + path + ", outputFolder=" + outputFolder + ", sourceContainerUrl=" + + sourceContainerUrl + ", javadocContainerUrl=" + javadocContainerUrl + ", isSystem=" + isSystem + + ", isOwn=" + isOwn + "]"; } + } public static boolean isSource(CPE e) { return e!=null && Classpath.ENTRY_KIND_SOURCE.equals(e.getKind()); } + public static boolean isProjectSource(CPE e) { + return isSource(e) && e.isOwn(); + } + } \ No newline at end of file diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/JavaDataParams.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/JavaDataParams.java index d7810b842..2908623c6 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/JavaDataParams.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/ls/JavaDataParams.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -14,11 +14,13 @@ public class JavaDataParams { private String projectUri; private String bindingKey; + private Boolean lookInOtherProjects; - public JavaDataParams(String projectUri, String bindingKey) { + public JavaDataParams(String projectUri, String bindingKey, Boolean lookInOtherProjects) { super(); this.projectUri = projectUri; this.bindingKey = bindingKey; + this.lookInOtherProjects = lookInOtherProjects; } public String getBindingKey() { @@ -37,9 +39,26 @@ public class JavaDataParams { this.projectUri = project; } + public Boolean getLookInOtherProjects() { + return lookInOtherProjects; + } + @Override public String toString() { - return "JavaDataParams [projectUri=" + projectUri + ", bindingKey=" + bindingKey + "]"; + return "JavaDataParams [projectUri=" + projectUri + ", bindingKey=" + bindingKey + ", lookInOtherProjects=" + + lookInOtherProjects + "]"; + } + + public void setLookInOtherProjects(Boolean lookInOtherProjects) { + this.lookInOtherProjects = lookInOtherProjects; + } + + public static boolean isLookInOtherProjects(JavaDataParams params) { + return isLookInOtherProjects(params.projectUri, params.getLookInOtherProjects()); + } + + public static boolean isLookInOtherProjects(String projectUri, Boolean lookInOtherProjects) { + return projectUri == null ? true : lookInOtherProjects == null ? false : lookInOtherProjects.booleanValue(); } } diff --git a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java index c46bad025..2332c15e3 100644 --- a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java +++ b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java @@ -122,6 +122,7 @@ public class MavenProjectClasspath implements IClasspath { File sourceFolder = new File(project.getBuild().getSourceDirectory()); File outputFolder = new File(project.getBuild().getOutputDirectory()); CPE cpe = CPE.source(sourceFolder, outputFolder); + cpe.setOwn(true); safe(() -> { String reportingDir = project.getModel().getReporting().getOutputDirectory(); if (reportingDir!=null) { @@ -138,7 +139,9 @@ public class MavenProjectClasspath implements IClasspath { if (targetPath==null) { targetPath = project.getBuild().getOutputDirectory(); } - entries.add(CPE.source(sourceFolder, new File(targetPath))); + CPE cpe = CPE.source(sourceFolder, new File(targetPath)); + cpe.setOwn(true); + entries.add(cpe); } } { //test/resources @@ -148,13 +151,16 @@ public class MavenProjectClasspath implements IClasspath { if (targetPath==null) { targetPath = project.getBuild().getTestOutputDirectory(); } - entries.add(CPE.source(sourceFolder, targetPath==null ? null : new File(targetPath))); + CPE cpe = CPE.source(sourceFolder, targetPath==null ? null : new File(targetPath)); + cpe.setOwn(true); + entries.add(cpe); } } { //test/java File sourceFolder = new File(project.getBuild().getTestSourceDirectory()); File outputFolder = new File(project.getBuild().getTestOutputDirectory()); CPE cpe = CPE.source(sourceFolder, outputFolder); + cpe.setOwn(true); safe(() -> { String reportingDir = project.getModel().getReporting().getOutputDirectory(); if (reportingDir!=null) { diff --git a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectFinder.java b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectFinder.java index b662c072e..8e67e1777 100644 --- a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectFinder.java +++ b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.commons.maven.java; import java.io.File; +import java.util.Collection; import java.util.Optional; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -20,14 +21,14 @@ import org.springframework.ide.vscode.commons.util.FileUtils; /** * Finds Maven projects. Looks for pom.xml file - * + * * @author Alex Boyko * */ public class MavenProjectFinder extends FileBasedJavaProjectFinder { - + private MavenProjectCache cache; - + public MavenProjectFinder(MavenProjectCache cache) { this.cache = cache; } @@ -45,4 +46,9 @@ public class MavenProjectFinder extends FileBasedJavaProjectFinder { protected Optional findProjectByName(String name) { return cache.projectByName(name); } + + @Override + public Collection all() { + return cache.all(); + } } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java index 7537d8585..b146d7e75 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/Classpath.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -59,6 +59,7 @@ public class Classpath { private URL sourceContainerUrl; private URL javadocContainerUrl; private boolean isSystem = false; + private boolean isOwn = false; public String getOutputFolder() { return outputFolder; @@ -128,11 +129,19 @@ public class Classpath { this.isSystem = isSystem; } + public boolean isOwn() { + return isOwn; + } + + public void setOwn(boolean isOwn) { + this.isOwn = isOwn; + } + @Override public String toString() { - return "CPE [kind=" + kind + ", isSystem=" + isSystem + ", path=" + path + ", outputFolder=" + outputFolder - + ", sourceContainerUrl=" + sourceContainerUrl + ", javadocContainerUrl=" + javadocContainerUrl - + "]"; + return "CPE [kind=" + kind + ", path=" + path + ", outputFolder=" + outputFolder + ", sourceContainerUrl=" + + sourceContainerUrl + ", javadocContainerUrl=" + javadocContainerUrl + ", isSystem=" + isSystem + + ", isOwn=" + isOwn + "]"; } } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java index 26c278154..7431f61d5 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -81,10 +81,7 @@ public class ClasspathUtil { if (entries != null) { for (IClasspathEntry entry : entries) { try { - CPE cpe = createCpe(systemLibs, javaProject, entry); - if (cpe != null) { - cpEntries.add(cpe); - } + cpEntries.addAll(createCpes(systemLibs, javaProject, entry)); } catch (Exception e) { logger.log(e); } @@ -97,8 +94,8 @@ public class ClasspathUtil { private static AtomicBoolean enabledDownloadSources = new AtomicBoolean(false); - public static CPE createCpe(IJavaProject javaProject, IClasspathEntry entry) throws MalformedURLException, JavaModelException { - return createCpe(getSystemLibraryPaths(javaProject), javaProject, entry); + public static List createCpes(IJavaProject javaProject, IClasspathEntry entry) throws MalformedURLException, JavaModelException { + return createCpes(getSystemLibraryPaths(javaProject), javaProject, entry); } private static void enableDownloadSources() { @@ -108,7 +105,7 @@ public class ClasspathUtil { } } - private static CPE createCpe(Set systemLibs, IJavaProject javaProject, IClasspathEntry entry) + private static List createCpes(Set systemLibs, IJavaProject javaProject, IClasspathEntry entry) throws MalformedURLException, JavaModelException { String kind = toContentKind(entry); switch (kind) { @@ -127,52 +124,64 @@ public class ClasspathUtil { // // } } - return cpe; + return Collections.singletonList(cpe); } case Classpath.ENTRY_KIND_SOURCE: { if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { IPath projectPath = entry.getPath(); - return resolveProjectOutputFolder(projectPath); - } else { - IPath sourcePath = entry.getPath(); - // log("source entry =" + sourcePath); - IPath absoluteSourcePath = resolveWorkspacePath(sourcePath); - // log("absoluteSourcePath =" + absoluteSourcePath); - if (absoluteSourcePath != null) { - IPath of = entry.getOutputLocation(); - // log("outputFolder =" + of); - IPath absoluteOutFolder; - if (of != null) { - absoluteOutFolder = resolveWorkspacePath(of); - } else { - absoluteOutFolder = resolveWorkspacePath(javaProject.getOutputLocation()); - } - return CPE.source(absoluteSourcePath.toFile(), absoluteOutFolder.toFile()); - } + return resolveDependencyProjectCPEs(projectPath); + } else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + CPE cpe = createSourceCPE(javaProject, entry); + cpe.setOwn(true); + return cpe == null ? null : Collections.singletonList(cpe); } - break; } default: break; } + return Collections.emptyList(); + } + + private static CPE createSourceCPE(IJavaProject javaProject, IClasspathEntry entry) throws JavaModelException { + IPath sourcePath = entry.getPath(); + // log("source entry =" + sourcePath); + IPath absoluteSourcePath = resolveWorkspacePath(sourcePath); + // log("absoluteSourcePath =" + absoluteSourcePath); + if (absoluteSourcePath != null) { + IPath of = entry.getOutputLocation(); + // log("outputFolder =" + of); + IPath absoluteOutFolder; + if (of != null) { + absoluteOutFolder = resolveWorkspacePath(of); + } else { + absoluteOutFolder = resolveWorkspacePath(javaProject.getOutputLocation()); + } + return CPE.source(absoluteSourcePath.toFile(), absoluteOutFolder.toFile()); + } return null; } - private static CPE resolveProjectOutputFolder(IPath projectPath) throws JavaModelException { + private static List resolveDependencyProjectCPEs(IPath projectPath) throws JavaModelException { if (projectPath.segmentCount() == 1) { IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(projectPath.segment(0)); if (p.isAccessible()) { IJavaProject jp = JavaCore.create(p); - IPath outputFolder = jp.getOutputLocation(); - if (outputFolder != null) { - outputFolder = resolveWorkspacePath(outputFolder); - return CPE.binary(outputFolder.toFile().getAbsolutePath()); + IClasspathEntry[] rawClasspath = jp.getRawClasspath(); + ArrayList cpes = new ArrayList<>(rawClasspath.length); + for (IClasspathEntry entry : rawClasspath) { + if (toContentKind(entry) == Classpath.ENTRY_KIND_SOURCE && entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + CPE cpe = createSourceCPE(jp, entry); + if (cpe != null) { + cpes.add(cpe); + } + } } + return cpes; } } - return null; + return Collections.emptyList(); } - + private static IPath resolveWorkspacePath(IPath path) { if (path.segmentCount()>0) { String projectName = path.segment(0); diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaData.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaData.java index 3776b0c9f..dc5caa14c 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaData.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaData.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -13,8 +13,10 @@ package org.springframework.tooling.jdt.ls.commons.java; import java.net.MalformedURLException; import java.net.URI; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IField; @@ -29,6 +31,7 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.springframework.tooling.jdt.ls.commons.Logger; +import org.springframework.tooling.jdt.ls.commons.classpath.Classpath.CPE; import org.springframework.tooling.jdt.ls.commons.classpath.ClasspathUtil; import org.springframework.tooling.jdt.ls.commons.java.TypeData.AnnotationData; import org.springframework.tooling.jdt.ls.commons.java.TypeData.ClasspathEntryData; @@ -47,9 +50,9 @@ public class JavaData { this.logger = logger; } - public TypeData typeData(String projectUri, String bindingKey) { + public TypeData typeData(String projectUri, String bindingKey, boolean lookInOtherProjects) { try { - IJavaElement element = findElement(URI.create(projectUri), bindingKey); + IJavaElement element = findElement(projectUri == null ? null : URI.create(projectUri), bindingKey, lookInOtherProjects); if (element instanceof IType) { return createTypeData((IType) element); } @@ -59,12 +62,20 @@ public class JavaData { return null; } - public static IJavaElement findElement(URI projectUri, String bindingKey) throws Exception { - IJavaProject javaProject = ResourceUtils.getJavaProject(projectUri); - if (javaProject != null) { - return findElement(javaProject, bindingKey); + public static IJavaElement findElement(URI projectUri, String bindingKey, boolean lookInOtherProjects) throws Exception { + IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri); + IJavaElement element = javaProject == null ? null : findElement(javaProject, bindingKey); + if (lookInOtherProjects && element == null) { + for (IJavaProject jp : ResourceUtils.allJavaProjects()) { + if (jp != javaProject) { + element = findElement(jp, bindingKey); + if (element != null) { + break; + } + } + } } - return null; + return element; } private static IJavaElement findElement(IJavaProject project, String bindingKey) { @@ -259,7 +270,11 @@ public class JavaData { try { IClasspathEntry entry = packageFragmentRoot.getRawClasspathEntry(); if (entry != null) { - data.setCpe(ClasspathUtil.createCpe(packageFragmentRoot.getJavaProject(), entry)); + List cpes = ClasspathUtil.createCpes(packageFragmentRoot.getJavaProject(), entry); + Assert.isTrue(cpes.size() < 2); + if (!cpes.isEmpty()) { + data.setCpe(cpes.get(0)); + } } } catch (JavaModelException | MalformedURLException e) { logger.log(e); diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaDataParams.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaDataParams.java index e5ab6380f..4b62d2832 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaDataParams.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/JavaDataParams.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -14,6 +14,7 @@ public class JavaDataParams { private String projectUri; private String bindingKey; + private Boolean lookInOtherProjects; public JavaDataParams(String projectUri, String bindingKey) { super(); @@ -37,9 +38,26 @@ public class JavaDataParams { this.projectUri = project; } + public Boolean getLookInOtherProjects() { + return lookInOtherProjects; + } + @Override public String toString() { - return "JavaDataParams [projectUri=" + projectUri + ", bindingKey=" + bindingKey + "]"; + return "JavaDataParams [projectUri=" + projectUri + ", bindingKey=" + bindingKey + ", lookInOtherProjects=" + + lookInOtherProjects + "]"; + } + + public void setLookInOtherProjects(Boolean lookInOtherProjects) { + this.lookInOtherProjects = lookInOtherProjects; + } + + public static boolean isLookInOtherProjects(JavaDataParams params) { + return isLookInOtherProjects(params.projectUri, params.getLookInOtherProjects()); + } + + public static boolean isLookInOtherProjects(String projectUri, Boolean lookInOtherProjects) { + return projectUri == null ? true : lookInOtherProjects == null ? false : lookInOtherProjects.booleanValue(); } } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/javadoc/JavadocUtils.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/javadoc/JavadocUtils.java index e03ea7f2d..0bdf9c91a 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/javadoc/JavadocUtils.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/javadoc/JavadocUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -39,8 +39,8 @@ public class JavadocUtils { return null; } - public static final String javadoc(Function readerProvider, URI projectUri, String bindingKey) throws Exception { - IJavaElement element = JavaData.findElement(projectUri, bindingKey); + public static final String javadoc(Function readerProvider, URI projectUri, String bindingKey, boolean lookInOtherProjects) throws Exception { + IJavaElement element = JavaData.findElement(projectUri, bindingKey, lookInOtherProjects); return computeJavadoc(readerProvider, element); } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java index c8c394f7c..5dacd5b8d 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/resources/ResourceUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -12,13 +12,16 @@ package org.springframework.tooling.jdt.ls.commons.resources; import java.io.File; import java.net.URI; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; @@ -56,6 +59,24 @@ public final class ResourceUtils { throw new Exception("Resolve classpath: unable to resolve a Java project from : " + resourceUri); } + + public static Collection allJavaProjects() { + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + ArrayList javaProjects = new ArrayList<>(projects.length); + for (IProject project : projects) { + try { + if (project.isAccessible() && project.hasNature(JavaCore.NATURE_ID)) { + IJavaProject javaProject = JavaCore.create(project); + if (javaProject != null) { + javaProjects.add(javaProject); + } + } + } catch (CoreException e) { + // ignore + } + } + return javaProjects; + } /** * Returns the resource URI, IFF it exists. Throws exception if it doesn't exist. diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavaTypeHanlder.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavaTypeHanlder.java index d941c3a47..565b9871b 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavaTypeHanlder.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavaTypeHanlder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -17,6 +17,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler; import org.springframework.tooling.jdt.ls.commons.Logger; import org.springframework.tooling.jdt.ls.commons.java.JavaData; +import org.springframework.tooling.jdt.ls.commons.java.JavaDataParams; import org.springframework.tooling.jdt.ls.commons.java.JavaTypeResponse; public class JavaTypeHanlder implements IDelegateCommandHandler { @@ -30,7 +31,8 @@ public class JavaTypeHanlder implements IDelegateCommandHandler { Map obj = (Map) arguments.get(0); String uri = (String) obj.get("projectUri"); String bindingKey = (String) obj.get("bindingKey"); - return new JavaTypeResponse(JAVA_DATA.typeData(uri, bindingKey)); + Boolean lookInOtherProjects = (Boolean) obj.get("lookInOtherProjects"); + return new JavaTypeResponse(JAVA_DATA.typeData(uri, bindingKey, JavaDataParams.isLookInOtherProjects(uri, lookInOtherProjects))); } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHandler.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHandler.java index 347442046..1dca81b5c 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHandler.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -18,6 +18,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler; import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2; import org.springframework.tooling.jdt.ls.commons.Logger; +import org.springframework.tooling.jdt.ls.commons.java.JavaDataParams; import org.springframework.tooling.jdt.ls.commons.javadoc.JavadocResponse; import org.springframework.tooling.jdt.ls.commons.javadoc.JavadocUtils; @@ -29,7 +30,9 @@ public class JavadocHandler implements IDelegateCommandHandler { String uri = (String) obj.get("projectUri"); URI projectUri = URI.create(uri); String bindingKey = (String) obj.get("bindingKey"); - String content = JavadocUtils.javadoc(JavadocContentAccess2::getMarkdownContentReader, projectUri, bindingKey); + Boolean lookInOtherProjects = (Boolean) obj.get("lookInOtherProjects"); + String content = JavadocUtils.javadoc(JavadocContentAccess2::getMarkdownContentReader, projectUri, bindingKey, + JavaDataParams.isLookInOtherProjects(uri, lookInOtherProjects)); JavadocResponse response = new JavadocResponse(); response.setContent(content); return response; diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHoverLinkHandler.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHoverLinkHandler.java index 42f2e08ff..6d93c6dd0 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHoverLinkHandler.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/src/org/springframework/tooling/jdt/ls/extension/JavadocHoverLinkHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -31,9 +31,11 @@ public class JavadocHoverLinkHandler implements IDelegateCommandHandler { Map obj = (Map) arguments.get(0); String uri = (String) obj.get("projectUri"); String bindingKey = (String) obj.get("bindingKey"); + Boolean lookInOtherProjectsObj = (Boolean) obj.get("lookInOtherProjects"); + boolean lookInOtherProjects = uri == null ? true : lookInOtherProjectsObj == null ? false : lookInOtherProjectsObj.booleanValue(); JavadocHoverLinkResponse response = new JavadocHoverLinkResponse(null); try { - IJavaElement element = JavaData.findElement(URI.create(uri), bindingKey); + IJavaElement element = JavaData.findElement(uri == null ? null : URI.create(uri), bindingKey, lookInOtherProjects); if (element != null) { // Bug in JDT server one '(' not encoded while everything else in the query is // encoded diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java index 927695d71..e895d7f25 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -80,10 +80,10 @@ public class BootLanguagServerBootApp { return new ValueProviderRegistry(); } - @Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties) { + @Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties, SourceLinks sourceLinks) { return () -> { - r.def("logger-name", LoggerNameProvider.factory(adHocProperties)); - r.def("class-reference", ClassReferenceProvider.FACTORY); + r.def("logger-name", LoggerNameProvider.factory(adHocProperties, sourceLinks)); + r.def("class-reference", ClassReferenceProvider.factory(sourceLinks)); }; } @@ -93,8 +93,8 @@ public class BootLanguagServerBootApp { } @ConditionalOnMissingClass("org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness") - @Bean SourceLinks sourceLinks(SimpleLanguageServer server, CompilationUnitCache cuCache) { - return SourceLinkFactory.createSourceLinks(server, cuCache); + @Bean SourceLinks sourceLinks(SimpleLanguageServer server, CompilationUnitCache cuCache, BootLanguageServerParams params) { + return SourceLinkFactory.createSourceLinks(server, cuCache, params.projectFinder); } @Bean CompilationUnitCache cuCache(BootLanguageServerParams params, SimpleTextDocumentService documents) { @@ -133,13 +133,13 @@ public class BootLanguagServerBootApp { return YamlStructureProvider.DEFAULT; } - @Bean YamlAssistContextProvider yamlAssistContextProvider(BootLanguageServerParams params, JavaElementLocationProvider javaElementLocationProvider) { + @Bean YamlAssistContextProvider yamlAssistContextProvider(BootLanguageServerParams params, JavaElementLocationProvider javaElementLocationProvider, SourceLinks sourceLinks) { return new YamlAssistContextProvider() { @Override public YamlAssistContext getGlobalAssistContext(YamlDocument ydoc) { IDocument doc = ydoc.getDocument(); FuzzyMap index = params.indexProvider.getIndex(doc); - return ApplicationYamlAssistContext.global(ydoc, index, new PropertyCompletionFactory(), params.typeUtilProvider.getTypeUtil(doc), RelaxedNameConfig.COMPLETION_DEFAULTS, javaElementLocationProvider); + return ApplicationYamlAssistContext.global(ydoc, index, new PropertyCompletionFactory(), params.typeUtilProvider.getTypeUtil(sourceLinks, doc), RelaxedNameConfig.COMPLETION_DEFAULTS, javaElementLocationProvider); } }; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java index 74e8b294e..2354dbb0b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -70,7 +70,7 @@ public class BootLanguageServerInitializer implements InitializingBean { //TODO: ComposableLanguageServer object instance serves no purpose anymore. The constructor really just contains // some server intialization code. Migrate that code and get rid of the ComposableLanguageServer class CompositeLanguageServerComponents.Builder builder = new CompositeLanguageServerComponents.Builder(); - builder.add(new BootPropertiesLanguageServerComponents(server, params, javaElementLocationProvider, parser, yamlStructureProvider, yamlAssistContextProvider)); + builder.add(new BootPropertiesLanguageServerComponents(server, params, javaElementLocationProvider, parser, yamlStructureProvider, yamlAssistContextProvider, sourceLinks)); builder.add(new BootJavaLanguageServerComponents(server, params, sourceLinks, cuCache, adHocProperties)); components = builder.build(server); params.projectObserver.addListener(reconcileOpenDocuments(server, components)); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerParams.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerParams.java index 8e476c714..09083fda5 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerParams.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerParams.java @@ -13,10 +13,12 @@ package org.springframework.ide.vscode.boot.app; import java.nio.file.Paths; import java.time.Duration; import java.util.Arrays; +import java.util.Collection; import java.util.Optional; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog; import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsService; import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsServiceWithFallback; @@ -101,7 +103,7 @@ public class BootLanguageServerParams { jdtProjectCache.filter(project -> SpringProjectUtil.isBootProject(project) || SpringProjectUtil.isSpringProject(project)), jdtProjectCache, indexProvider, - (IDocument doc) -> new TypeUtil(jdtProjectCache.find(new TextDocumentIdentifier(doc.getUri()))), + (SourceLinks sourceLinks, IDocument doc) -> new TypeUtil(sourceLinks, jdtProjectCache.find(new TextDocumentIdentifier(doc.getUri()))), RunningAppProvider.createDefault(server), SpringLiveHoverWatchdog.DEFAULT_INTERVAL ); @@ -141,6 +143,11 @@ public class BootLanguageServerParams { public IJavadocProvider javadocProvider(String projectUri, CPE cpe) { return javadocService.javadocProvider(projectUri, cpe); } + + @Override + public Collection all() { + return javaProjectFinder.all(); + } }; } @@ -164,7 +171,7 @@ public class BootLanguageServerParams { javaProjectFinder.filter(project -> SpringProjectUtil.isBootProject(project) || SpringProjectUtil.isSpringProject(project)), projectObserver, indexProvider, - (IDocument doc) -> new TypeUtil(javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri()))), + (SourceLinks sourceLinks, IDocument doc) -> new TypeUtil(sourceLinks, javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri()))), RunningAppProvider.NULL, SpringLiveHoverWatchdog.DEFAULT_INTERVAL ); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java index 47b923fb2..7327b9e3a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -18,6 +18,7 @@ import org.eclipse.lsp4j.TextDocumentPositionParams; import org.gradle.internal.impldep.com.google.common.collect.ImmutableList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; @@ -46,6 +47,9 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu @Autowired private JavaElementLocationProvider javaElementLocationProvider; + @Autowired + private SourceLinks sourceLinks; + @Autowired private BootLanguageServerParams params; @@ -53,7 +57,7 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu public List handle(TextDocumentPositionParams position) { try { TextDocument doc = documents.get(position); - TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(doc); + TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc); FuzzyMap index = params.indexProvider.getIndex(doc); int offset; offset = doc.toOffset(position.getPosition()); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java index 3ecfc0562..a87d920f5 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -264,7 +264,7 @@ public class AutowiredHoverProvider implements HoverProvider { } private static boolean isCompatibleBeanType(IJavaProject jp, LiveBean bean, String bindingQualifiedName) { - String rawLiveBeanFqName = bean.getType(); + String rawLiveBeanFqName = bean.getType(true); int idx = rawLiveBeanFqName.indexOf('<'); // Trim the generic parameters part if it's present String liveBeanTypeFQName = idx < 0 ? rawLiveBeanFqName : rawLiveBeanFqName.substring(0, idx); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java index c722a19f7..e96d30b50 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java @@ -10,9 +10,11 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.handlers; +import java.io.File; import java.net.URI; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.List; import java.util.Optional; import org.eclipse.jdt.core.dom.ASTNode; @@ -42,6 +44,7 @@ import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.java.ls.Classpath; import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; import org.springframework.ide.vscode.commons.util.text.DocumentRegion; @@ -105,14 +108,28 @@ public class BootJavaHoverProvider implements HoverHandler { if (!hasActuatorDependency(project.get())) { // double check the running apps in case there is a non-boot app running with live beans enabled boolean nonBootLiveBeansAround = false; + boolean onAppsClasspath = false; for (SpringBootApp bootApp : runningBootApps) { if (bootApp.providesNonBootLiveBeans()) { nonBootLiveBeansAround = true; break; + } else { + try { + List binaryRoots = IClasspathUtil.getBinaryRoots(project.get().getClasspath(), Classpath::isSource); + for (String path : bootApp.getClasspath()) { + File file = new File(path); + if (binaryRoots.contains(file)) { + onAppsClasspath = true; + break; + } + } + } catch (Exception e) { + logger.error("", e); + } } } - if (!nonBootLiveBeansAround) { + if (!nonBootLiveBeansAround && !onAppsClasspath) { return new CodeLens[0]; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AbstractSourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AbstractSourceLinks.java index 035a91c77..d7ba09a92 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AbstractSourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AbstractSourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -14,7 +14,6 @@ import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Optional; import java.util.Stack; @@ -31,6 +30,7 @@ import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavaModuleData; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.text.Region; /** @@ -45,12 +45,30 @@ public abstract class AbstractSourceLinks implements SourceLinks { private CompilationUnitCache cuCache; - protected AbstractSourceLinks(CompilationUnitCache cuCache) { + private JavaProjectFinder projectFinder; + + protected AbstractSourceLinks(CompilationUnitCache cuCache, JavaProjectFinder projectFinder) { this.cuCache = cuCache; + this.projectFinder = projectFinder; } @Override public Optional sourceLinkUrlForFQName(IJavaProject project, String fqName) { + Optional url = project == null ? Optional.empty() : getSourceLinkUrlForFQName(project, fqName); + if (!url.isPresent()) { + for (IJavaProject jp : projectFinder.all()) { + if (jp != project) { + url = getSourceLinkUrlForFQName(jp, fqName); + if (url.isPresent()) { + break; + } + } + } + } + return url; + } + + private Optional getSourceLinkUrlForFQName(IJavaProject project, String fqName) { IJavaModuleData classpathResource = project.getIndex().findClasspathResourceContainer(fqName); if (classpathResource != null) { File file = classpathResource.getContainer(); @@ -64,17 +82,10 @@ public abstract class AbstractSourceLinks implements SourceLinks { } @Override - public Optional 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(); + public Optional sourceLinkUrlForClasspathResource(String path) { + return SourceLinks.sourceLinkUrlForClasspathResource(this, projectFinder, path); } - - private Optional javaSourceLinkUrl(IJavaProject project, String fqName, IJavaModuleData folderModuleData) { IClasspath classpath = project.getClasspath(); return SourceLinks.sourceFromSourceFolder(fqName, classpath) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AtomSourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AtomSourceLinks.java index 29e58bf83..1d40793aa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AtomSourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/AtomSourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.commons.java.IJavaModuleData; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.text.Region; import com.google.common.base.Supplier; @@ -36,8 +37,8 @@ public class AtomSourceLinks extends AbstractSourceLinks { private static Supplier LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class)); - public AtomSourceLinks(CompilationUnitCache cuCache) { - super(cuCache); + public AtomSourceLinks(CompilationUnitCache cuCache, JavaProjectFinder projectFinder) { + super(cuCache, projectFinder); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseSourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseSourceLinks.java index 5a9e1b3db..c0c8e4576 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseSourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/EclipseSourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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,12 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.links; -import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Optional; import org.slf4j.Logger; @@ -23,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.IMember; import org.springframework.ide.vscode.commons.java.IType; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; /** * Source links for Eclipse client. Eclipse IntroURLs. @@ -47,21 +46,37 @@ public class EclipseSourceLinks implements SourceLinks { private static final Logger log = LoggerFactory.getLogger(EclipseSourceLinks.class); - @Override - public Optional sourceLinkUrlForFQName(IJavaProject project, String fqName) { - return Optional.ofNullable(eclipseIntroUri(project, fqName)).map(uri -> uri.toString()); + private JavaProjectFinder projectFinder; + + public EclipseSourceLinks(JavaProjectFinder projectFinder) { + this.projectFinder = projectFinder; } @Override - public Optional 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, ".")); + public Optional sourceLinkUrlForFQName(IJavaProject project, String fqName) { + return findProjectForFQName(project, fqName).map(p -> eclipseIntroUri(p, fqName)).map(uri -> uri.toString()); + } + + private Optional findProjectForFQName(IJavaProject project, String fqName) { + if (project != null && project.findType(fqName) != null) { + return Optional.of(project); + } else { + for (IJavaProject jp : projectFinder.all()) { + if (jp != project) { + if (jp.findType(fqName) != null) { + return Optional.of(jp); + } + } + } } return Optional.empty(); } + @Override + public Optional sourceLinkUrlForClasspathResource(String path) { + return SourceLinks.sourceLinkUrlForClasspathResource(this, projectFinder, path); + } + @Override public Optional sourceLinkForResourcePath(Path path) { return Optional.ofNullable(eclipseIntroUri(path)).map(uri -> uri.toString()); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/JavaServerSourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/JavaServerSourceLinks.java index b63e99757..70de5a7f2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/JavaServerSourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/JavaServerSourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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,9 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.links; -import java.io.File; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -20,15 +18,18 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.java.ls.JavaDataParams; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; public class JavaServerSourceLinks implements SourceLinks { private SimpleLanguageServer server; + private JavaProjectFinder projectFinder; - public JavaServerSourceLinks(SimpleLanguageServer server) { + public JavaServerSourceLinks(SimpleLanguageServer server, JavaProjectFinder projectFinder) { this.server = server; + this.projectFinder = projectFinder; } @Override @@ -37,7 +38,8 @@ public class JavaServerSourceLinks implements SourceLinks { bindingKey.append('L'); bindingKey.append(fqName.replace('.', '/')); bindingKey.append(';'); - CompletableFuture> link = server.getClient().javadocHoverLink(new JavaDataParams(project.getLocationUri().toString(), bindingKey.toString())) + String projectUri = project == null ? null : project.getLocationUri().toString(); + CompletableFuture> link = server.getClient().javadocHoverLink(new JavaDataParams(projectUri, bindingKey.toString(), true)) .thenApply(response -> Optional.ofNullable(response.getLink())); try { return link.get(10, TimeUnit.SECONDS); @@ -48,13 +50,8 @@ public class JavaServerSourceLinks implements SourceLinks { } @Override - public Optional 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(); + public Optional sourceLinkUrlForClasspathResource(String path) { + return SourceLinks.sourceLinkUrlForClasspathResource(this, projectFinder, path); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinkFactory.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinkFactory.java index 391cf1492..988d7f15a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinkFactory.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinkFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -13,9 +13,9 @@ package org.springframework.ide.vscode.boot.java.links; import java.nio.file.Path; import java.util.Optional; -import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents; import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.LspClient; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; @@ -35,7 +35,7 @@ public final class SourceLinkFactory { } @Override - public Optional sourceLinkUrlForClasspathResource(IJavaProject project, String path) { + public Optional sourceLinkUrlForClasspathResource(String path) { return Optional.empty(); } @@ -51,26 +51,20 @@ public final class SourceLinkFactory { * @param server the boot LS * @return appropriate source links object */ - public static SourceLinks createSourceLinks(SimpleLanguageServer server, CompilationUnitCache cuCache) { + public static SourceLinks createSourceLinks(SimpleLanguageServer server, CompilationUnitCache cuCache, JavaProjectFinder projectFinder) { switch (LspClient.currentClient()) { case VSCODE: - return /*new VSCodeSourceLinks(cuCache);*/server == null ? new VSCodeSourceLinks(cuCache) :new JavaServerSourceLinks(server); + return /*new VSCodeSourceLinks(cuCache);*/server == null ? new VSCodeSourceLinks(cuCache, projectFinder) :new JavaServerSourceLinks(server, projectFinder); case THEIA: - return new VSCodeSourceLinks(cuCache); + return new VSCodeSourceLinks(cuCache, projectFinder); case ECLIPSE: - return /*new EclipseSourceLinks();*/server == null ? new EclipseSourceLinks() : new JavaServerSourceLinks(server); + return /*new EclipseSourceLinks();*/server == null ? new EclipseSourceLinks(projectFinder) : new JavaServerSourceLinks(server, projectFinder); case ATOM: - return new AtomSourceLinks(cuCache); + return new AtomSourceLinks(cuCache, projectFinder); default: return NO_SOURCE_LINKS; } } - @Deprecated - public static SourceLinks createSourceLinks(BootJavaLanguageServerComponents server) { - return server == null - ? createSourceLinks(null, (CompilationUnitCache)null) - : createSourceLinks(server.getServer(), server.getCompilationUnitCache()); - } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinks.java index af347170b..b918aee79 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/SourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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.java.links; +import java.io.File; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -18,6 +19,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; +import org.eclipse.lsp4j.TextDocumentIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IClasspath; @@ -25,6 +27,9 @@ import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaModuleData; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.java.ls.Classpath; +import org.springframework.ide.vscode.commons.languageserver.java.ls.Classpath.CPE; /** * Instance is able to provide client specific URL links to navigate to a @@ -99,6 +104,36 @@ public interface SourceLinks { return Optional.empty(); } + public static Optional sourceLinkUrlForClasspathResource(SourceLinks sourceLinks, JavaProjectFinder projectFinder, String path) { + if (projectFinder != null) { + int idx = path.lastIndexOf(CLASS); + if (idx >= 0) { + Path filePath = Paths.get(path.substring(0, idx)); + IJavaProject project = projectFinder.find(new TextDocumentIdentifier(filePath.toUri().toString())).orElse(null); + if (project != null) { + try { + for (CPE cpe : project.getClasspath().getClasspathEntries()) { + if (Classpath.isSource(cpe)) { + Path cpeBinaryPath = IClasspathUtil.binaryLocation(cpe).toPath(); + if (filePath.startsWith(cpeBinaryPath)) { + String fqName = cpeBinaryPath.relativize(filePath).toString().replace(File.separator, "."); + Optional link = sourceLinks.sourceLinkUrlForFQName(project, fqName); + if (link.isPresent()) { + return link; + } + } + } + } + } catch (Exception e) { + log.error("", e); + } + } + + } + } + return Optional.empty(); + } + /** * Creates link to source file defining the type passed with it's fully qualified name @@ -114,7 +149,7 @@ public interface SourceLinks { * @param path the path to the classpath resource * @return the link URL optional */ - Optional sourceLinkUrlForClasspathResource(IJavaProject project, String path); + Optional sourceLinkUrlForClasspathResource(String path); /** * Creates link to a file specified by it's path diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/VSCodeSourceLinks.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/VSCodeSourceLinks.java index c34b2551c..b8b9d08cc 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/VSCodeSourceLinks.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/links/VSCodeSourceLinks.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -17,6 +17,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.commons.java.IJavaModuleData; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.text.Region; /** @@ -27,8 +28,8 @@ import org.springframework.ide.vscode.commons.util.text.Region; */ public class VSCodeSourceLinks extends AbstractSourceLinks { - public VSCodeSourceLinks(CompilationUnitCache cuCache) { - super(cuCache); + public VSCodeSourceLinks(CompilationUnitCache cuCache, JavaProjectFinder projectFinder) { + super(cuCache, projectFinder); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java index 9873ee7de..7f54f281d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -145,7 +145,7 @@ public class LiveHoverUtils { LiveBeansModel beansModel = app.getBeans(); if (beansModel != null) { List relevantBeans = beansModel.getBeansOfName(definedBean.getId()); - String type = definedBean.getType(); + String type = definedBean.getType(true); if (type != null) { // TODO: check if we should check for bean type rather than id that we build ourselves based on type // if (relevantBeans.isEmpty()) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java index 095120b96..635a34998 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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.java.utils; +import java.io.File; +import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; @@ -241,18 +243,18 @@ public class SpringLiveChangeDetectionWatchdog { for (IJavaProject project : projects) { if (SpringResource.FILE.equals(type)) { - String relativePath = SpringResource.projectRelativePath(project, path); - - if (relativePath != path && path.endsWith(SourceLinks.CLASS)) { - result = sourceLinks.sourceLinkUrlForClasspathResource(project, relativePath).get(); - break; - } else { + result = sourceLinks.sourceLinkUrlForClasspathResource(path).get(); + if (result == null) { result = sourceLinks.sourceLinkForResourcePath(Paths.get(path)).get(); - break; } + break; } else if (SpringResource.CLASS_PATH_RESOURCE.equals(type)) { - result = sourceLinks.sourceLinkUrlForClasspathResource(project, path).get(); + int idx = path.lastIndexOf(SourceLinks.CLASS); + if (idx >= 0) { + Path p = Paths.get(path.substring(0, idx)); + result = sourceLinks.sourceLinkUrlForFQName(project, p.toString().replace(File.separator, ".")).get(); + } break; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java index 423d8b2fb..b59efa279 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -67,20 +67,22 @@ public class SpringResource { if (type==null) { return path; //path is just the raw text in this case } - Optional linkUrl; + Optional linkUrl = Optional.empty(); switch (type) { case FILE: - String relativePath = projectRelativePath(project, path); - if (relativePath != path && path.endsWith(SourceLinks.CLASS)) { - linkUrl = sourceLinks.sourceLinkUrlForClasspathResource(project, relativePath); - } else { + linkUrl = sourceLinks.sourceLinkUrlForClasspathResource(path); + if (!linkUrl.isPresent()) { linkUrl = sourceLinks.sourceLinkForResourcePath(Paths.get(path)); } // not a project relative path - return linkUrl.isPresent() ? Renderables.link(relativePath, linkUrl.get()).toMarkdown() + return linkUrl.isPresent() ? Renderables.link(projectRelativePath(project, path), linkUrl.get()).toMarkdown() : "`" + projectRelativePath(project, path) + "`"; case CLASS_PATH_RESOURCE: - linkUrl = sourceLinks.sourceLinkUrlForClasspathResource(project, path); + int idx = path.lastIndexOf(SourceLinks.CLASS); + if (idx >= 0) { + Path p = Paths.get(path.substring(0, idx)); + linkUrl = sourceLinks.sourceLinkUrlForFQName(project, p.toString().replace(File.separator, ".")); + } return linkUrl.isPresent() ? Renderables.link(path, linkUrl.get()).toMarkdown() : "`"+path+"`"; default: return path; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JavaProjectsServiceWithFallback.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JavaProjectsServiceWithFallback.java index 5689c8485..5a075d1bd 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JavaProjectsServiceWithFallback.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JavaProjectsServiceWithFallback.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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.jdt.ls; +import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -24,6 +25,7 @@ import org.springframework.ide.vscode.commons.util.Assert; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableList; import reactor.core.Disposable; @@ -113,4 +115,18 @@ public class JavaProjectsServiceWithFallback implements JavaProjectsService { return IJavadocProvider.NULL; } + @Override + public Collection all() { + if (mainServiceInitialized.isDone()) { + if (mainServiceInitialized.isCompletedExceptionally()) { + return fallback.get().all(); + } else { + return main.all(); + } + } else { + log.debug("find => NOT INITIALIZED YET"); + } + return ImmutableList.of(); + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java index 2b74615da..c59e40b91 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -210,4 +210,9 @@ public class JdtLsProjectCache implements InitializableJavaProjectsService { } }); } + + @Override + public Collection all() { + return table.values(); + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java index 8932f0f9d..ac65b2410 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -18,12 +18,14 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry.ValueProviderStrategy; import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint; import org.springframework.ide.vscode.commons.java.Flags; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.IType; -import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.StringUtil; import com.google.common.cache.Cache; @@ -40,36 +42,35 @@ import reactor.core.publisher.Flux; * @author Alex Boyko */ public class ClassReferenceProvider extends CachingValueProvider { - + + private static final Logger log = LoggerFactory.getLogger(ClassReferenceProvider.class); + /** * Default value for the 'concrete' parameter. */ private static final boolean DEFAULT_CONCRETE = true; - private static final ClassReferenceProvider UNTARGETTED_INSTANCE = new ClassReferenceProvider(null, DEFAULT_CONCRETE); + private static final ClassReferenceProvider UNTARGETTED_INSTANCE = new ClassReferenceProvider(null, DEFAULT_CONCRETE, null); - public static final Function, ValueProviderStrategy> FACTORY = applyOn( - 1, TimeUnit.MINUTES, - (params) -> { - String target = getTarget(params); - Boolean concrete = getConcrete(params); - if (target!=null || concrete!=null) { - if (concrete==null) { - concrete = DEFAULT_CONCRETE; - } - return new ClassReferenceProvider(target, concrete); - } - return UNTARGETTED_INSTANCE; - } - ); - - private static Function applyOn(long duration, TimeUnit unit, Function func) { - Cache cache = CacheBuilder.newBuilder().expireAfterAccess(duration, unit).expireAfterWrite(duration, unit).build(); - return (k) -> { + public static final Function, ValueProviderStrategy> factory(SourceLinks sourceLinks) { + long duration = 1; + TimeUnit unit = TimeUnit.MINUTES; + Cache, ValueProviderStrategy> cache = CacheBuilder.newBuilder().expireAfterAccess(duration, unit).expireAfterWrite(duration, unit).build(); + return (params) -> { try { - return cache.get(k, () -> func.apply(k)); + return cache.get(params, () -> { + String target = getTarget(params); + Boolean concrete = getConcrete(params); + if (target!=null || concrete!=null) { + if (concrete==null) { + concrete = DEFAULT_CONCRETE; + } + return new ClassReferenceProvider(target, concrete, sourceLinks); + } + return UNTARGETTED_INSTANCE; + }); } catch (ExecutionException e) { - Log.log(e); + log.error("", e); return null; } }; @@ -92,7 +93,7 @@ public class ClassReferenceProvider extends CachingValueProvider { try { return type.isInterface() || Flags.isAbstract(type.getFlags()); } catch (Exception e) { - Log.log(e); + log.error("", e); return false; } } @@ -109,7 +110,7 @@ public class ClassReferenceProvider extends CachingValueProvider { } } } catch (Exception e) { - Log.log(e); + log.error("", e); } return null; } @@ -124,9 +125,12 @@ public class ClassReferenceProvider extends CachingValueProvider { */ private boolean concrete; - private ClassReferenceProvider(String target, boolean concrete) { + private SourceLinks sourceLinks; + + private ClassReferenceProvider(String target, boolean concrete, SourceLinks sourceLinks) { this.target = target; this.concrete = concrete; + this.sourceLinks = sourceLinks; } @Override @@ -147,7 +151,7 @@ public class ClassReferenceProvider extends CachingValueProvider { .fuzzySearchTypes(query, type -> allSubclasses.contains(type)) .collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())) .flatMapIterable(l -> l) - .map(t -> StsValueHint.create(javaProject, t.getT1())); + .map(t -> StsValueHint.create(sourceLinks, javaProject, t.getT1())); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java index fb8bfb194..e0e27d22b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -15,8 +15,8 @@ import java.util.Collection; import java.util.Map; import java.util.SortedMap; import java.util.function.Function; -import java.util.function.Predicate; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry.ValueProviderStrategy; import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -41,15 +41,17 @@ public class LoggerNameProvider extends CachingValueProvider { private static final String LOGGING_GROUPS_PREFIX = "logging.group."; private final ProjectBasedPropertyIndexProvider adhocProperties; private final boolean includeGroups; + private final SourceLinks sourceLinks; - public LoggerNameProvider(ProjectBasedPropertyIndexProvider adhocProperties, boolean includeGroups) { + public LoggerNameProvider(ProjectBasedPropertyIndexProvider adhocProperties, boolean includeGroups, SourceLinks sourceLinks) { this.adhocProperties = adhocProperties; this.includeGroups = includeGroups; + this.sourceLinks = sourceLinks; } - public static final Function, ValueProviderStrategy> factory(ProjectBasedPropertyIndexProvider adhocProperties) { + public static final Function, ValueProviderStrategy> factory(ProjectBasedPropertyIndexProvider adhocProperties, SourceLinks sourceLinks) { return (params) -> { - return new LoggerNameProvider(adhocProperties, (boolean) params.getOrDefault("group", true)); + return new LoggerNameProvider(adhocProperties, (boolean) params.getOrDefault("group", true), sourceLinks); }; } @@ -83,7 +85,7 @@ public class LoggerNameProvider extends CachingValueProvider { .map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())), javaProject.getIndex() .fuzzySearchTypes(query, null) - .map(t -> Tuples.of(StsValueHint.create(javaProject, t.getT1()), t.getT2())) + .map(t -> Tuples.of(StsValueHint.create(sourceLinks, javaProject, t.getT1()), t.getT2())) ) .collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())) .flatMapIterable(l -> l) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java index 48edecf36..84a589ad7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -15,8 +15,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.boot.configurationmetadata.ValueHint; -import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents; -import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory; import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.util.DeprecationUtil; @@ -63,8 +61,8 @@ public class StsValueHint { /** * Creates a hint out of an IJavaElement. */ - public static StsValueHint create(String value, IJavaProject project, IJavaElement javaElement) { - return new StsValueHint(value, javaDocSnippet(project, javaElement), DeprecationUtil.extract(javaElement)) { + public static StsValueHint create(SourceLinks sourceLinks, String value, IJavaProject project, IJavaElement javaElement) { + return new StsValueHint(value, javaDocSnippet(sourceLinks, project, javaElement), DeprecationUtil.extract(javaElement)) { @Override public IJavaElement getJavaElement() { return javaElement; @@ -86,7 +84,7 @@ public class StsValueHint { if (jp!=null) { IType type = jp.findType(fqName); if (type!=null) { - return create(jp, type); + return create(typeUtil.getSourceLinks(), jp, type); } } } catch (Exception e) { @@ -95,8 +93,8 @@ public class StsValueHint { return null; } - public static StsValueHint create(IJavaProject project, IType klass) { - return new StsValueHint(klass.getFullyQualifiedName(), javaDocSnippet(project, klass), DeprecationUtil.extract(klass)) { + public static StsValueHint create(SourceLinks sourceLinks, IJavaProject project, IType klass) { + return new StsValueHint(klass.getFullyQualifiedName(), javaDocSnippet(sourceLinks, project, klass), DeprecationUtil.extract(klass)) { @Override public IJavaElement getJavaElement() { return klass; @@ -122,9 +120,8 @@ public class StsValueHint { return description; } - private static Renderable javaDocSnippet(IJavaProject project, IJavaElement je) { + private static Renderable javaDocSnippet(SourceLinks sourceLinks, IJavaProject project, IJavaElement je) { return Renderables.lazy(() -> { - SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null); return PropertyDocUtils.documentJavaElement(sourceLinks, project, je); }); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java index 37a696bcd..697b90bb6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -39,8 +39,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.convert.DurationStyle; import org.springframework.ide.vscode.boot.configurationmetadata.Deprecation; -import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents; -import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory; import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.ResourceHintProvider; import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry.ValueProviderStrategy; @@ -134,16 +132,18 @@ public class TypeUtil { } private IJavaProject javaProject; + private SourceLinks sourceLinks; - public TypeUtil(IJavaProject jp) { + public TypeUtil(SourceLinks sourceLinks, IJavaProject jp) { //Note javaProject is allowed to be null, but only in unit testing context // (This is so some tests can be run without an explicit jp needing to be created) this.javaProject = jp; + this.sourceLinks = sourceLinks; } - public TypeUtil(Optional maybeProject) { - this(maybeProject.orElse(null)); + public TypeUtil(SourceLinks sourceLinks, Optional maybeProject) { + this(sourceLinks, maybeProject.orElse(null)); } private static final Map PRIMITIVE_TYPE_NAMES = new HashMap<>(); @@ -334,10 +334,10 @@ public class TypeUtil { type.getFields().filter(f -> f.isEnumConstant()).forEach(f -> { String rawName = f.getElementName(); if (addOriginal) { - enums.add(StsValueHint.create(rawName, javaProject, f)); + enums.add(StsValueHint.create(sourceLinks, rawName, javaProject, f)); } if (addLowerCased) { - enums.add(StsValueHint.create(StringUtil.upperCaseToHyphens(rawName), javaProject, f)); + enums.add(StsValueHint.create(sourceLinks, StringUtil.upperCaseToHyphens(rawName), javaProject, f)); } }); return enums.build(); @@ -655,6 +655,10 @@ public class TypeUtil { valueHints("org.springframework.core.io.Resource", new ResourceHintProvider()); } + public SourceLinks getSourceLinks() { + return sourceLinks; + } + /** * Determine properties that are setable on object of given type. *

@@ -695,7 +699,6 @@ public class TypeUtil { //TODO: handle type parameters. if (typeFromIndex != null) { - SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null); IJavaProject project = getJavaProject(); ArrayList properties = new ArrayList<>(); getGetterMethods(typeFromIndex).forEach(m -> { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtilProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtilProvider.java index ab608e32e..5d559cdf2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtilProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtilProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -11,9 +11,10 @@ package org.springframework.ide.vscode.boot.metadata.types; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.commons.util.text.IDocument; @FunctionalInterface public interface TypeUtilProvider { - TypeUtil getTypeUtil(IDocument doc); + TypeUtil getTypeUtil(SourceLinks sourceLinks, IDocument doc); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/BootPropertiesLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/BootPropertiesLanguageServerComponents.java index 91c101d7a..29b6428c4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/BootPropertiesLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/BootPropertiesLanguageServerComponents.java @@ -15,6 +15,7 @@ import java.util.Set; import org.springframework.ide.vscode.boot.app.BootLanguageServerParams; import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; import org.springframework.ide.vscode.boot.properties.completions.SpringPropertiesCompletionEngine; @@ -80,7 +81,7 @@ public class BootPropertiesLanguageServerComponents implements LanguageServerCom private SpringPropertiesReconcileEngine propertiesReconciler; private ApplicationYamlReconcileEngine ymlReconciler; - + private SourceLinks sourceLinks; public BootPropertiesLanguageServerComponents( SimpleLanguageServer server, @@ -88,7 +89,8 @@ public class BootPropertiesLanguageServerComponents implements LanguageServerCom JavaElementLocationProvider javaElementLocationProvider, YamlASTProvider parser, YamlStructureProvider yamlStructureProvider, - YamlAssistContextProvider yamlAssistContextProvider) { + YamlAssistContextProvider yamlAssistContextProvider, + SourceLinks sourceLinks) { this.server = server; this.parser = parser; this.indexProvider = serverParams.indexProvider; @@ -97,15 +99,16 @@ public class BootPropertiesLanguageServerComponents implements LanguageServerCom this.projectObserver = serverParams.projectObserver; this.yamlStructureProvider = yamlStructureProvider; this.yamlAssistContextProvider = yamlAssistContextProvider; + this.sourceLinks = sourceLinks; server.getClientCapabilities().thenAccept(clientCapabilities -> { CommonQuickfixes commonQuickfixes = new CommonQuickfixes(server.getQuickfixRegistry(), javaProjectFinder, clientCapabilities); this.propertiesReconciler = new SpringPropertiesReconcileEngine(indexProvider, - typeUtilProvider, new AppPropertiesQuickFixes(server.getQuickfixRegistry(), commonQuickfixes)); + typeUtilProvider, new AppPropertiesQuickFixes(server.getQuickfixRegistry(), commonQuickfixes), sourceLinks); this.ymlReconciler = new ApplicationYamlReconcileEngine(parser, indexProvider, typeUtilProvider, new AppYamlQuickfixes(server.getQuickfixRegistry(), server.getTextDocumentService(), - yamlStructureProvider, commonQuickfixes)); + yamlStructureProvider, commonQuickfixes), sourceLinks); }); indexProvider.onChange(() -> { @@ -125,7 +128,7 @@ public class BootPropertiesLanguageServerComponents implements LanguageServerCom @Override public ICompletionEngine getCompletionEngine() { - ICompletionEngine propertiesCompletions = new SpringPropertiesCompletionEngine(indexProvider, typeUtilProvider, javaProjectFinder); + ICompletionEngine propertiesCompletions = new SpringPropertiesCompletionEngine(indexProvider, typeUtilProvider, javaProjectFinder, sourceLinks); ICompletionEngine yamlCompletions = new YamlCompletionEngine(yamlStructureProvider, yamlAssistContextProvider, COMPLETION_OPTIONS); return (TextDocument document, int offset) -> { String uri = document.getUri(); @@ -142,7 +145,7 @@ public class BootPropertiesLanguageServerComponents implements LanguageServerCom @Override public HoverHandler getHoverProvider() { - HoverInfoProvider propertiesHovers = new PropertiesHoverInfoProvider(indexProvider, typeUtilProvider, javaProjectFinder); + HoverInfoProvider propertiesHovers = new PropertiesHoverInfoProvider(indexProvider, typeUtilProvider, javaProjectFinder, sourceLinks); HoverInfoProvider ymlHovers = new YamlHoverInfoProvider(parser, yamlStructureProvider, yamlAssistContextProvider); HoverInfoProvider combined = (IDocument document, int offset) -> { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java index 47bd33375..a5038bc07 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -14,6 +14,7 @@ package org.springframework.ide.vscode.boot.properties.completions; import java.util.Collection; import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; @@ -32,15 +33,17 @@ public class SpringPropertiesCompletionEngine implements ICompletionEngine { private SpringPropertyIndexProvider indexProvider; private TypeUtilProvider typeUtilProvider; private PropertyCompletionFactory completionFactory = null; + private SourceLinks sourceLinks; /** * Constructor used in 'production'. Wires up stuff properly for running inside a normal * Eclipse runtime. */ - public SpringPropertiesCompletionEngine(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder projectFinder) { + public SpringPropertiesCompletionEngine(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder projectFinder, SourceLinks sourceLinks) { this.indexProvider = indexProvider; this.typeUtilProvider = typeUtilProvider; this.completionFactory = new PropertyCompletionFactory(); + this.sourceLinks = sourceLinks; } /** @@ -49,7 +52,7 @@ public class SpringPropertiesCompletionEngine implements ICompletionEngine { @Override public Collection getCompletions(TextDocument doc, int offset) throws BadLocationException { return new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc), - typeUtilProvider.getTypeUtil(doc), completionFactory, doc, offset, preferLowerCaseEnums).calculate(); + typeUtilProvider.getTypeUtil(sourceLinks, doc), completionFactory, doc, offset, preferLowerCaseEnums).calculate(); } public boolean getPreferLowerCaseEnums() { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java index 2e3179176..49ab72b88 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016-2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 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 @@ -11,12 +11,9 @@ package org.springframework.ide.vscode.boot.properties.hover; -import java.util.Optional; - -import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; -import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.Renderable; @@ -26,20 +23,22 @@ import org.springframework.ide.vscode.commons.util.text.IRegion; import reactor.util.function.Tuple2; public class PropertiesHoverInfoProvider implements HoverInfoProvider { - + private SpringPropertyIndexProvider indexProvider; private TypeUtilProvider typeUtilProvider; private JavaProjectFinder projectFinder; - - public PropertiesHoverInfoProvider(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder projectFinder) { + private SourceLinks sourceLinks; + + public PropertiesHoverInfoProvider(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder projectFinder, SourceLinks sourceLinks) { this.indexProvider = indexProvider; this.typeUtilProvider = typeUtilProvider; this.projectFinder = projectFinder; + this.sourceLinks = sourceLinks; } @Override public Tuple2 getHoverInfo(IDocument document, int offset) throws Exception { return new PropertiesHoverCalculator(indexProvider.getIndex(document), - typeUtilProvider.getTypeUtil(document), document, offset).calculate(); + typeUtilProvider.getTypeUtil(sourceLinks, document), document, offset).calculate(); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java index 99c16e94f..3b54a48db 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java @@ -21,6 +21,7 @@ import java.util.regex.Pattern; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; @@ -78,11 +79,13 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { private TypeUtilProvider typeUtilProvider; private Parser parser = new AntlrParser(); private AppPropertiesQuickFixes quickFixes; + private SourceLinks sourceLinks; - public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider, AppPropertiesQuickFixes quickFixes) { + public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider, AppPropertiesQuickFixes quickFixes, SourceLinks sourceLinks) { this.fIndexProvider = provider; this.typeUtilProvider = typeUtilProvider; this.quickFixes = quickFixes; + this.sourceLinks = sourceLinks; } @Override @@ -119,7 +122,7 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { problemCollector.accept(problemDeprecated(propertyNameRegion, validProperty, quickFixes.DEPRECATED_PROPERTY)); } int offset = validProperty.getId().length() + propertyNameRegion.getStart(); - PropertyNavigator navigator = new PropertyNavigator(doc, problemCollector, typeUtilProvider.getTypeUtil(doc), propertyNameRegion); + PropertyNavigator navigator = new PropertyNavigator(doc, problemCollector, typeUtilProvider.getTypeUtil(sourceLinks, doc), propertyNameRegion); Type valueType = navigator.navigate(offset, TypeParser.parse(validProperty.getType())); if (valueType!=null) { reconcileType(doc, valueType, pair.getValue(), problemCollector); @@ -207,7 +210,7 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { } private void reconcileType(DocumentRegion escapedValue, Type expectType, IProblemCollector problems) { - TypeUtil typeUtil = typeUtilProvider.getTypeUtil(escapedValue.getDocument()); + TypeUtil typeUtil = typeUtilProvider.getTypeUtil(sourceLinks, escapedValue.getDocument()); ValueParser parser = typeUtil.getValueParser(expectType); if (parser!=null) { try { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java index db5451c08..70264ff96 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2018 Pivotal, Inc. + * Copyright (c) 2015, 2019 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 @@ -613,7 +613,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon if (jes != null) { for (IJavaElement je : jes) { if (je instanceof IMember) { - SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null); + SourceLinks sourceLinks = typeUtil.getSourceLinks(); IJavaProject project = typeUtil.getJavaProject(); return PropertyDocUtils.documentJavaElement(sourceLinks, project, je); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java index ef5392b36..2fd8f94e9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.yaml.reconcile; import static org.springframework.ide.vscode.boot.yaml.reconcile.ApplicationYamlProblems.Type.YAML_SYNTAX_ERROR; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.IndexNavigator; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; @@ -30,12 +31,14 @@ public class ApplicationYamlReconcileEngine extends YamlReconcileEngine { private SpringPropertyIndexProvider indexProvider; private TypeUtilProvider typeUtilProvider; private AppYamlQuickfixes quickFixes; + private SourceLinks sourceLinks; - public ApplicationYamlReconcileEngine(YamlASTProvider astProvider, SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, AppYamlQuickfixes quickFixes) { + public ApplicationYamlReconcileEngine(YamlASTProvider astProvider, SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, AppYamlQuickfixes quickFixes, SourceLinks sourceLinks) { super(astProvider); this.indexProvider = indexProvider; this.typeUtilProvider = typeUtilProvider; this.quickFixes = quickFixes; + this.sourceLinks = sourceLinks; } @Override @@ -43,7 +46,7 @@ public class ApplicationYamlReconcileEngine extends YamlReconcileEngine { FuzzyMap index = indexProvider.getIndex(doc); if (index!=null && !index.isEmpty()) { IndexNavigator nav = IndexNavigator.with(index); - return new ApplicationYamlASTReconciler(problemCollector, nav, typeUtilProvider.getTypeUtil(doc), quickFixes); + return new ApplicationYamlASTReconciler(problemCollector, nav, typeUtilProvider.getTypeUtil(sourceLinks, doc), quickFixes); } return null; } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/bootiful/PropertyEditorTestConf.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/bootiful/PropertyEditorTestConf.java index f0733d9c7..ff825842b 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/bootiful/PropertyEditorTestConf.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/bootiful/PropertyEditorTestConf.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -59,7 +59,7 @@ public class PropertyEditorTestConf { @Bean BootLanguageServerParams serverParams(SimpleLanguageServer server, PropertyIndexHarness indexHarness) { JavaProjectFinder projectFinder = indexHarness.getProjectFinder(); - TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(projectFinder.find(new TextDocumentIdentifier(doc.getUri()))); + TypeUtilProvider typeUtilProvider = (SourceLinks sourceLinks, IDocument doc) -> new TypeUtil(sourceLinks, projectFinder.find(new TextDocumentIdentifier(doc.getUri()))); return new BootLanguageServerParams( projectFinder, diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/AbstractPropsEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/AbstractPropsEditorTest.java index ad46c243d..ce4e0f6f9 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/AbstractPropsEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/AbstractPropsEditorTest.java @@ -39,6 +39,8 @@ import org.springframework.ide.vscode.languageserver.testharness.Editor; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; +import com.google.common.collect.ImmutableList; + public abstract class AbstractPropsEditorTest { public static final String INTEGER = Integer.class.getName(); @@ -61,6 +63,11 @@ public abstract class AbstractPropsEditorTest { public Optional find(TextDocumentIdentifier doc) { return Optional.ofNullable(getTestProject()); } + + @Override + public Collection all() { + return getTestProject() == null ? ImmutableList.of() : ImmutableList.of(getTestProject()); + } })); abstract public Editor newEditor(String contents) throws Exception; diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java index 6df77492f..71a91fd36 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java @@ -10,11 +10,15 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.editor.harness; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.gradle.internal.impldep.com.google.common.collect.ImmutableList; import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.ide.vscode.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.boot.configurationmetadata.ValueHint; @@ -574,7 +578,19 @@ public class PropertyIndexHarness { } public JavaProjectFinder getProjectFinder() { - return (doc) -> Optional.ofNullable(testProject); + return new JavaProjectFinder() { + + @Override + public Optional find(TextDocumentIdentifier doc) { + return Optional.ofNullable(testProject); + } + + @Override + public Collection all() { + // TODO Auto-generated method stub + return testProject == null ? Collections.emptyList() : ImmutableList.of(testProject); + } + }; } public IJavaProject getTestProject() { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java index 6feea840e..1d0356d28 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -163,6 +163,59 @@ public class ComponentInjectionsHoverProviderTest { ); } + @Test + public void componentWithOneCGILibInjection() throws Exception { + LiveBeansModel beans = LiveBeansModel.builder() + .add(LiveBean.builder() + .id("fooImplementation") + .type("com.example.FooImplementation$$EnhancerBySpringCGLIB$$Blah") + .build() + ) + .add(LiveBean.builder() + .id("myController") + .type("com.example.MyController$$EnhancerBySpringCGLIB$$Blah") + .dependencies("fooImplementation") + .build() + ) + .add(LiveBean.builder() + .id("irrelevantBean") + .type("com.example.IrrelevantBean$$EnhancerBySpringCGLIB$$Blah") + .dependencies("myController") + .build() + ) + .build(); + mockAppProvider.builder() + .isSpringBootApp(true) + .processId("111") + .processName("the-app") + .beans(beans) + .build(); + + Editor editor = harness.newEditor(LanguageId.JAVA, + "package com.example;\n" + + "\n" + + "import org.springframework.stereotype.Component;\n" + + "\n" + + "@Component\n" + + "public class FooImplementation implements Foo {\n" + + "\n" + + " @Override\n" + + " public void doSomeFoo() {\n" + + " System.out.println(\"Foo do do do!\");\n" + + " }\n" + + "}\n" + ); + editor.assertHighlights("@Component"); + editor.assertTrimmedHover("@Component", + "**→ `MyController`**\n" + + "- Bean: `myController` \n" + + " Type: `com.example.MyController`\n" + + " \n" + + "Bean id: `fooImplementation` \n" + + "Process [PID=111, name=`the-app`]\n" + ); + } + @Test public void componentWithMultipleInjections() throws Exception { LiveBeansModel beans = LiveBeansModel.builder() diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/VSCodeSourceLinksTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/VSCodeSourceLinksTest.java index ccd6e8e52..8fbab1a72 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/VSCodeSourceLinksTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/VSCodeSourceLinksTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -56,7 +56,7 @@ public class VSCodeSourceLinksTest { @Test public void testJavaSourceUrl() throws Exception { MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app"); - Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null)).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication"); + Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication"); assertTrue(url.isPresent()); Path projectPath = Paths.get(project.pom().getParent()); URI uri = URI.create(url.get()); @@ -73,7 +73,7 @@ public class VSCodeSourceLinksTest { @Test public void testJarUrl() throws Exception { MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app"); - Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null)).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication"); + Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication"); assertTrue(url.isPresent()); 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); @@ -84,7 +84,7 @@ public class VSCodeSourceLinksTest { @Test public void testJarUrlInnerType() throws Exception { MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app"); - Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null)).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback"); + Optional url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null), null).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback"); assertTrue(url.isPresent()); 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); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java index c03d08a2d..73b739eaf 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/MockProjects.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 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 @@ -63,6 +63,11 @@ public class MockProjects { return Optional.empty(); } } + + @Override + public Collection all() { + return projectsByName.values(); + } }; public MockFileObserver fileObserver = new MockFileObserver(); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueCompletionTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueCompletionTest.java index 7e74e5199..6081f1252 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueCompletionTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueCompletionTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -14,12 +14,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import org.apache.commons.io.IOUtils; import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.xtend.lib.annotations.Accessors; +import org.gradle.internal.impldep.com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -86,7 +90,19 @@ public class ValueCompletionTest { } @Bean JavaProjectFinder projectFinder(MavenJavaProject testProject) { - return (doc) -> Optional.of(testProject); + return new JavaProjectFinder() { + + @Override + public Optional find(TextDocumentIdentifier doc) { + return Optional.ofNullable(testProject); + } + + @Override + public Collection all() { + // TODO Auto-generated method stub + return testProject == null ? Collections.emptyList() : ImmutableList.of(testProject); + } + }; } @Bean BootLanguageServerHarness harness(SimpleLanguageServer server, BootLanguageServerParams serverParams, PropertyIndexHarness indexHarness, JavaProjectFinder projectFinder) throws Exception { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProviderTest.java index 7ed16be0a..20f42e94a 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProviderTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2019 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 @@ -121,7 +121,7 @@ public class LoggerNameProviderTest { } private LoggerNameProvider create() { - return (LoggerNameProvider) LoggerNameProvider.factory(null).apply(ImmutableMap.of()); + return (LoggerNameProvider) LoggerNameProvider.factory(null, null).apply(ImmutableMap.of()); } private void assertElementsAtLeast(List results, String[] expecteds) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java index 139e550e6..e029a3e71 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Pivotal, Inc. + * Copyright (c) 2015, 2019 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 @@ -29,17 +29,17 @@ import org.springframework.ide.vscode.project.harness.ProjectsHarness; /** * Tests for TypeUtil - * + * * @author Kris De Volder - * @author Alex Boyko + * @author Alex Boyko * */ public class TypeUtilTest { - + private ProjectsHarness projects = ProjectsHarness.INSTANCE; private IJavaProject project; private TypeUtil typeUtil; - + private Type getPropertyType(Type type, String propName, EnumCaseMode enumMode, BeanPropertyNameMode beanMode) { List props = getProperties(type, enumMode, beanMode); assertNotNull(props); @@ -139,7 +139,7 @@ public class TypeUtilTest { private void useProject(String name) throws Exception { project = projects.mavenProject(name);; - typeUtil = new TypeUtil(project); + typeUtil = new TypeUtil(null, project); } }