PT #155474415: CTRL-CLICK navigation from .properties to Java
This commit is contained in:
@@ -45,6 +45,8 @@ class BindingKeyUtils {
|
||||
sb.append(getBindingKey(field.declaringClass()));
|
||||
sb.append('.');
|
||||
sb.append(field.name());
|
||||
sb.append(')');
|
||||
sb.append(getGeneralTypeBindingKey(field.type()));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -104,6 +106,9 @@ class BindingKeyUtils {
|
||||
sb.append(getGeneralTypeBindingKey(argument));
|
||||
}
|
||||
sb.append('>');
|
||||
if (type.owner() == null) {
|
||||
sb.append(';');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class TypeImpl implements IType {
|
||||
@Override
|
||||
public IType getDeclaringType() {
|
||||
DotName enclosingClass = info.enclosingClass();
|
||||
return enclosingClass == null ? null : index.findType(enclosingClass.toString());
|
||||
return enclosingClass == null ? this : index.findType(enclosingClass.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -37,4 +39,28 @@ public class BootProjectUtil {
|
||||
return name.endsWith(".jar") && name.startsWith("spring-boot");
|
||||
}
|
||||
|
||||
public static Path javaHomeFromLibJar(Path libJar) {
|
||||
for (Path home = libJar; home.getParent() != null; home = home.getParent()) {
|
||||
if (Files.exists(home.resolve("release")) || Files.exists(home.resolve("release.txt"))) {
|
||||
return home;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Path jreSources(Path libJar) {
|
||||
Path home = javaHomeFromLibJar(libJar);
|
||||
if (home != null) {
|
||||
Path sources = home.resolve("src.zip");
|
||||
if (Files.exists(sources)) {
|
||||
return sources;
|
||||
}
|
||||
sources = home.resolve("lib/src.zip");
|
||||
if (Files.exists(sources)) {
|
||||
return sources;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Set;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.model.Resource;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.springframework.ide.vscode.commons.java.BootProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.ClasspathData;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
@@ -86,6 +87,7 @@ public class MavenProjectClasspath implements IClasspath {
|
||||
if (javaVersion == null) {
|
||||
javaVersion = "8";
|
||||
}
|
||||
cpe.setSourceContainerUrl(BootProjectUtil.jreSources(path).toUri().toURL());
|
||||
cpe.setJavadocContainerUrl(new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/"));
|
||||
cpe.setSystem(true);
|
||||
entries.add(cpe);
|
||||
|
||||
@@ -21,7 +21,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerInitializer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.DiagnosticSeverityProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DefinitionHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(LanguageServerProperties.class)
|
||||
@@ -45,5 +47,14 @@ public class LanguageServerAutoConf {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Bean SimpleTextDocumentService documents(SimpleLanguageServer ls) {
|
||||
return ls.getTextDocumentService();
|
||||
}
|
||||
|
||||
@ConditionalOnBean(DefinitionHandler.class)
|
||||
@Bean
|
||||
InitializingBean registerDefintionHandler(SimpleTextDocumentService documents,
|
||||
DefinitionHandler definitionHandler) {
|
||||
return () -> documents.onDefinition(definitionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@@ -720,10 +721,28 @@ public class Editor {
|
||||
return "Editor(\n"+getText()+"\n)";
|
||||
}
|
||||
|
||||
public void assertLinkTargets(String hoverOver, Set<Location> expectedLocations) throws Exception {
|
||||
int pos = getRawText().indexOf(hoverOver);
|
||||
if (pos>=0) {
|
||||
pos += hoverOver.length() / 2;
|
||||
}
|
||||
assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0);
|
||||
|
||||
TextDocumentPositionParams params = new TextDocumentPositionParams(new TextDocumentIdentifier(getUri()), doc.toPosition(pos));
|
||||
List<? extends Location> definitions = harness.getDefinitions(params);
|
||||
|
||||
assertEquals(ImmutableSet.copyOf(expectedLocations), ImmutableSet.copyOf(definitions));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void assertLinkTargets(String hoverOver, String... expecteds) {
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
// Editor editor = this;
|
||||
// int pos = editor.middleOf(hoverOver);
|
||||
// int pos = getRawText().indexOf(hoverOver);
|
||||
// if (pos>=0) {
|
||||
// pos += hoverOver.length();
|
||||
// }
|
||||
// return harness.getHover(doc, doc.toPosition(pos));
|
||||
// assertTrue("Not found in editor: '"+hoverOver+"'", pos>=0);
|
||||
//
|
||||
// List<IJavaElement> targets = getLinkTargets(editor, pos);
|
||||
|
||||
@@ -14,7 +14,15 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.ide.vscode.boot.java.links.DefaultJavaElementLocationProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.JdtJavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.LogRedirect;
|
||||
|
||||
@SpringBootApplication
|
||||
@@ -34,4 +42,22 @@ public class BootLanguagServerBootApp {
|
||||
@Bean BootLanguageServerParams serverParams(SimpleLanguageServer server) {
|
||||
return BootLanguageServerParams.createDefault(server);
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass("org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness")
|
||||
@Bean SourceLinks sourceLinks(CompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.createSourceLinks(cuCache);
|
||||
}
|
||||
|
||||
@Bean CompilationUnitCache cuCache(BootLanguageServerParams params, SimpleTextDocumentService documents) {
|
||||
return new CompilationUnitCache(params.projectFinder, documents, params.projectObserver);
|
||||
}
|
||||
|
||||
@Bean JavaDocumentUriProvider javaDocumentUriProvider() {
|
||||
return new JdtJavaDocumentUriProvider();
|
||||
}
|
||||
|
||||
@Bean JavaElementLocationProvider javaElementLocationProvider(CompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
|
||||
return new DefaultJavaElementLocationProvider(cuCache, javaDocUriProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
@@ -32,6 +34,8 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
|
||||
@Autowired SimpleLanguageServer server;
|
||||
@Autowired BootLanguageServerParams params;
|
||||
@Autowired SourceLinks sourceLinks;
|
||||
@Autowired CompilationUnitCache cuCache;
|
||||
|
||||
private CompositeLanguageServerComponents components;
|
||||
private VscodeCompletionEngineAdapter completionEngineAdapter;
|
||||
@@ -55,7 +59,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
// 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, (ignore) -> params));
|
||||
builder.add(new BootJavaLanguageServerComponents(server, (ignore) -> params));
|
||||
builder.add(new BootJavaLanguageServerComponents(server, params, sourceLinks, cuCache));
|
||||
components = builder.build(server);
|
||||
params.projectObserver.addListener(reconcileOpenDocuments(server, components));
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
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.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.properties.hover.PropertiesDefinitionCalculator;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DefinitionHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PropertiesJavaDefinitionHandler implements DefinitionHandler {
|
||||
|
||||
@Autowired
|
||||
private SimpleTextDocumentService documents;
|
||||
|
||||
@Autowired
|
||||
private JavaElementLocationProvider javaDocumentLocationProvider;
|
||||
|
||||
@Autowired
|
||||
private BootLanguageServerParams params;
|
||||
|
||||
@Override
|
||||
public List<Location> handle(TextDocumentPositionParams position) {
|
||||
try {
|
||||
TextDocument doc = documents.get(position);
|
||||
TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(doc);
|
||||
FuzzyMap<PropertyInfo> index = params.indexProvider.getIndex(doc);
|
||||
int offset;
|
||||
offset = doc.toOffset(position.getPosition());
|
||||
return new PropertiesDefinitionCalculator(javaDocumentLocationProvider, index, typeUtil, doc, offset).calculate();
|
||||
} catch (BadLocationException e) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.ActiveProfilesProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.BeanInjectedIntoHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHoverProvider;
|
||||
@@ -70,7 +71,6 @@ import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserve
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.CodeLensHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LSFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
@@ -108,15 +108,15 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
private CodeLensHandler codeLensHandler;
|
||||
private DocumentHighlightHandler highlightsEngine;
|
||||
|
||||
public BootJavaLanguageServerComponents(SimpleLanguageServer server, LSFactory<BootLanguageServerParams> _params) {
|
||||
public BootJavaLanguageServerComponents(SimpleLanguageServer server, BootLanguageServerParams serverParams, SourceLinks sourceLinks, CompilationUnitCache cuCache) {
|
||||
this.server = server;
|
||||
this.serverParams = _params.create(server);
|
||||
this.serverParams = serverParams;
|
||||
|
||||
this.config = new BootJavaConfig();
|
||||
|
||||
projectFinder = serverParams.projectFinder;
|
||||
projectObserver = serverParams.projectObserver;
|
||||
cuCache = new CompilationUnitCache(projectFinder, server.getTextDocumentService(), projectObserver);
|
||||
this.cuCache = cuCache;
|
||||
|
||||
propertyIndexProvider = serverParams.indexProvider;
|
||||
adHocPropertyIndexProvider = serverParams.adHocIndexProvider;
|
||||
@@ -146,7 +146,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
// documents.onCodeLens(codeLensHandler::createCodeLenses);
|
||||
// documents.onCodeLensResolve(codeLensHandler::resolveCodeLens);
|
||||
|
||||
hoverProvider = createHoverHandler(projectFinder, serverParams.runningAppProvider);
|
||||
hoverProvider = createHoverHandler(projectFinder, serverParams.runningAppProvider, sourceLinks);
|
||||
liveHoverWatchdog = new SpringLiveHoverWatchdog(server, hoverProvider, serverParams.runningAppProvider,
|
||||
projectFinder, projectObserver, serverParams.watchDogInterval);
|
||||
documents.onDidChangeContent(params -> {
|
||||
@@ -174,7 +174,14 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
// }
|
||||
});
|
||||
|
||||
liveChangeDetectionWatchdog = new SpringLiveChangeDetectionWatchdog(this, server, serverParams.projectObserver, serverParams.runningAppProvider, projectFinder, serverParams.watchDogInterval);
|
||||
liveChangeDetectionWatchdog = new SpringLiveChangeDetectionWatchdog(
|
||||
this,
|
||||
server,
|
||||
serverParams.projectObserver,
|
||||
serverParams.runningAppProvider,
|
||||
projectFinder,
|
||||
serverParams.watchDogInterval,
|
||||
sourceLinks);
|
||||
|
||||
codeLensHandler = createCodeLensEngine();
|
||||
documents.onCodeLens(codeLensHandler);
|
||||
@@ -293,14 +300,14 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
}
|
||||
|
||||
protected BootJavaHoverProvider createHoverHandler(JavaProjectFinder javaProjectFinder,
|
||||
RunningAppProvider runningAppProvider) {
|
||||
RunningAppProvider runningAppProvider, SourceLinks sourceLinks) {
|
||||
AnnotationHierarchyAwareLookup<HoverProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
|
||||
ValueHoverProvider valueHoverProvider = new ValueHoverProvider();
|
||||
RequestMappingHoverProvider requestMappingHoverProvider = new RequestMappingHoverProvider();
|
||||
AutowiredHoverProvider autowiredHoverProvider = new AutowiredHoverProvider(this);
|
||||
ComponentInjectionsHoverProvider componentInjectionsHoverProvider = new ComponentInjectionsHoverProvider(this);
|
||||
BeanInjectedIntoHoverProvider beanInjectedIntoHoverProvider = new BeanInjectedIntoHoverProvider(this);
|
||||
AutowiredHoverProvider autowiredHoverProvider = new AutowiredHoverProvider(sourceLinks);
|
||||
ComponentInjectionsHoverProvider componentInjectionsHoverProvider = new ComponentInjectionsHoverProvider(sourceLinks);
|
||||
BeanInjectedIntoHoverProvider beanInjectedIntoHoverProvider = new BeanInjectedIntoHoverProvider(sourceLinks);
|
||||
ConditionalsLiveHoverProvider conditionalsLiveHoverProvider = new ConditionalsLiveHoverProvider();
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, valueHoverProvider);
|
||||
|
||||
@@ -32,10 +32,8 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
@@ -65,11 +63,11 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
|
||||
private static final int MAX_INLINE_BEANS_STRING_LENGTH = 60;
|
||||
private static final String INLINE_BEANS_STRING_SEPARATOR = " ";
|
||||
private SourceLinks sourceLinks;
|
||||
|
||||
private BootJavaLanguageServerComponents server;
|
||||
public AutowiredHoverProvider(SourceLinks sourceLinks) {
|
||||
this.sourceLinks = sourceLinks;
|
||||
|
||||
public AutowiredHoverProvider(BootJavaLanguageServerComponents server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,7 +137,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
} else {
|
||||
hover.append(" \n \n");
|
||||
}
|
||||
createHoverContentForBeans(server, project, hover, autowiredBeans);
|
||||
createHoverContentForBeans(sourceLinks, project, hover, autowiredBeans);
|
||||
hover.append("Bean id: `");
|
||||
hover.append(definedBean.getId());
|
||||
hover.append("` \n");
|
||||
@@ -154,14 +152,13 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void createHoverContentForBeans(BootJavaLanguageServerComponents server, IJavaProject project, StringBuilder hover,
|
||||
public static void createHoverContentForBeans(SourceLinks sourceLinks, IJavaProject project, StringBuilder hover,
|
||||
List<LiveBean> autowiredBeans) {
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
hover.append("**");
|
||||
hover.append(LiveHoverUtils.createBeansTitleMarkdown(sourceLinks, project, autowiredBeans, BEANS_PREFIX_MARDOWN, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR));
|
||||
hover.append("**\n");
|
||||
hover.append(autowiredBeans.stream()
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(server, b, " ", project))
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(sourceLinks, b, " ", project))
|
||||
.collect(Collectors.joining("\n")));
|
||||
hover.append("\n \n");
|
||||
}
|
||||
|
||||
@@ -11,51 +11,41 @@
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
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.javadoc.TypeUrlProviderFromContainerUrl;
|
||||
import org.springframework.ide.vscode.commons.util.text.Region;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
/**
|
||||
* Base logic for {@link SourceLinks} independent of any client
|
||||
*
|
||||
* Base logic for {@link SourceLinks} independent of any client
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
|
||||
private static Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class));
|
||||
|
||||
private BootJavaLanguageServerComponents server;
|
||||
|
||||
protected AbstractSourceLinks(BootJavaLanguageServerComponents server) {
|
||||
this.server = server;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractSourceLinks.class);
|
||||
|
||||
private CompilationUnitCache cuCache;
|
||||
|
||||
protected AbstractSourceLinks(CompilationUnitCache cuCache) {
|
||||
this.cuCache = cuCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,7 +55,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
File file = classpathResource.get();
|
||||
if (file.isDirectory()) {
|
||||
return javaSourceLinkUrl(project, fqName, file);
|
||||
} else if (file.getName().endsWith(JAR)) {
|
||||
} else {
|
||||
return jarSourceLinkUrl(project, fqName, file);
|
||||
}
|
||||
}
|
||||
@@ -81,123 +71,56 @@ public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, File containerFolder) {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
return IClasspathUtil.getSourceFolders(classpath)
|
||||
.map(sourceFolder -> {
|
||||
try {
|
||||
return sourceFolder.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
LOG.get().warn("Failed to convert source folder " + sourceFolder + "to URI." + fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.map(url -> {
|
||||
try {
|
||||
return TypeUrlProviderFromContainerUrl.SOURCE_FOLDER_URL_SUPPLIER.url(url, fqName);
|
||||
} catch (Exception e) {
|
||||
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.map(url -> {
|
||||
try {
|
||||
return Paths.get(url.toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
LOG.get().warn("Failed to convert URL " + url + " to path." + fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(sourcePath -> sourcePath != null && Files.exists(sourcePath))
|
||||
.findFirst()
|
||||
return SourceLinks.sourceFromSourceFolder(fqName, classpath)
|
||||
.map(sourcePath -> javaSourceLinkUrl(project, sourcePath, fqName));
|
||||
}
|
||||
|
||||
private String javaSourceLinkUrl(IJavaProject project, Path sourcePath, String fqName) {
|
||||
Optional<String> linkOptional = sourceLinkForResourcePath(sourcePath);
|
||||
if (linkOptional.isPresent()) {
|
||||
Optional<String> positionLink = findCUForJavaSourceFile(sourcePath).map(cu -> positionLink(cu, fqName));
|
||||
Optional<String> positionLink = findCU(project, sourcePath.toUri()).map(cu -> positionLink(cu, fqName));
|
||||
return positionLink.isPresent() ? linkOptional.get() + positionLink.get() : linkOptional.get();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
abstract protected String positionLink(CompilationUnit cu, String fqName);
|
||||
|
||||
private Optional<CompilationUnit> findCUForJavaSourceFile(Path resourcePath) {
|
||||
Optional<CompilationUnit> cu = findCUfromCache(resourcePath.toUri().toString());
|
||||
if (cu == null) {
|
||||
try {
|
||||
char[] bytes = new String(Files.readAllBytes(resourcePath), Charset.defaultCharset()).toCharArray();
|
||||
String uri = resourcePath.toUri().toString();
|
||||
String unitName = resourcePath.getFileName().toString();
|
||||
cu = Optional.ofNullable(CompilationUnitCache.parse(bytes, uri, unitName, new String[0]));
|
||||
} catch (Exception e) {
|
||||
LOG.get().warn("Failed to create CompilationUnit from " + resourcePath, e);
|
||||
cu = Optional.empty();
|
||||
}
|
||||
}
|
||||
return cu;
|
||||
|
||||
private Optional<CompilationUnit> findCU(IJavaProject project, URI uri) {
|
||||
return cuCache == null ? Optional.empty() : cuCache.withCompilationUnit(project, uri, compilationUnit -> Optional.ofNullable(compilationUnit));
|
||||
}
|
||||
|
||||
private Optional<CompilationUnit> findCUfromCache(String uri) {
|
||||
Optional<CompilationUnit> cu = null;
|
||||
if (server != null && server.getCompilationUnitCache() != null) {
|
||||
TextDocument doc = server.getTextDocumentService().get(uri);
|
||||
if (doc != null) {
|
||||
cu = server.getCompilationUnitCache().withCompilationUnit(doc, compilationUnit -> compilationUnit == null ? null : Optional.of(compilationUnit));
|
||||
}
|
||||
}
|
||||
return cu;
|
||||
}
|
||||
|
||||
abstract protected Optional<String> jarUrl(IJavaProject project, String fqName, File jarFile);
|
||||
|
||||
|
||||
abstract protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile);
|
||||
|
||||
private Optional<String> jarSourceLinkUrl(IJavaProject project, String fqName, File jarFile) {
|
||||
return jarUrl(project, fqName, jarFile).map(sourceUrl -> {
|
||||
Optional<String> positionLink = findCUForFQNameFromJar(project, jarFile, sourceUrl, fqName).map(cu -> positionLink(cu, fqName));
|
||||
return jarLinkUrl(project, fqName, jarFile).map(sourceUrl -> {
|
||||
Optional<String> positionLink = findCUForFQNameFromJar(project, jarFile, fqName).map(cu -> positionLink(cu, fqName));
|
||||
return positionLink.isPresent() ? sourceUrl + positionLink.get() : sourceUrl;
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, File jarFile, String clientSourceUri, String fqName) {
|
||||
Optional<CompilationUnit> cu = findCUfromCache(clientSourceUri);
|
||||
if (cu == null) {
|
||||
cu = project.sourceContainer(jarFile)
|
||||
.map(url -> {
|
||||
try {
|
||||
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(url, fqName);
|
||||
} catch (Exception e) {
|
||||
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.map(sourceUrl -> {
|
||||
InputStream openStream = null;
|
||||
try {
|
||||
openStream = sourceUrl.openStream();
|
||||
char[] bytes = IOUtils.toCharArray(openStream);
|
||||
String uri = sourceUrl.toURI().toString();
|
||||
String unitName = fqName;
|
||||
return CompilationUnitCache.parse(bytes, uri, unitName, new String[0]);
|
||||
} catch (Exception e) {
|
||||
LOG.get().warn("Failed to create CompilationUnit from " + sourceUrl, e);
|
||||
return null;
|
||||
} finally {
|
||||
if (openStream != null) {
|
||||
try {
|
||||
openStream.close();
|
||||
} catch (IOException e) {
|
||||
LOG.get().error("Failed to close stream from " + sourceUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return cu;
|
||||
|
||||
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, File jarFile, String fqName) {
|
||||
return project.sourceContainer(jarFile).map(url -> {
|
||||
try {
|
||||
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(url, fqName);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to determine source URL from url={} fqName={}", url, fqName, e);
|
||||
return null;
|
||||
}
|
||||
}).map(sourceUrl -> {
|
||||
try {
|
||||
return sourceUrl.toURI();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}).map(sourcePath -> findCU(project, sourcePath).orElse(null));
|
||||
}
|
||||
|
||||
|
||||
protected Region findTypeRegion(CompilationUnit cu, String fqName) {
|
||||
if (cu == null) {
|
||||
return null;
|
||||
@@ -209,7 +132,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
if (packageName.equals(cu.getPackage().getName().getFullyQualifiedName())) {
|
||||
Stack<String> visitedType = new Stack<>();
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
|
||||
private boolean visitDeclaration(AbstractTypeDeclaration node) {
|
||||
visitedType.push(node.getName().getIdentifier());
|
||||
if (values[1] < 0) {
|
||||
@@ -231,6 +154,17 @@ public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
return visitDeclaration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
return visitDeclaration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(EnumDeclaration node) {
|
||||
visitedType.pop();
|
||||
super.endVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(AnnotationTypeDeclaration node) {
|
||||
visitedType.pop();
|
||||
@@ -247,5 +181,5 @@ public abstract class AbstractSourceLinks implements SourceLinks {
|
||||
}
|
||||
return values[1] < 0 ? null : new Region(values[0], values[1]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.Optional;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.Region;
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.google.common.base.Suppliers;
|
||||
|
||||
/**
|
||||
* Source links for Atom client
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
@@ -36,8 +36,8 @@ public class AtomSourceLinks extends AbstractSourceLinks {
|
||||
|
||||
private static Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class));
|
||||
|
||||
public AtomSourceLinks(BootJavaLanguageServerComponents server) {
|
||||
super(server);
|
||||
public AtomSourceLinks(CompilationUnitCache cuCache) {
|
||||
super(cuCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +69,7 @@ public class AtomSourceLinks extends AbstractSourceLinks {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<String> jarUrl(IJavaProject project, String fqName, File jarFile) {
|
||||
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile) {
|
||||
// JAR URLs are not supported yet
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IField;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IMember;
|
||||
import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
|
||||
public class DefaultJavaElementLocationProvider implements JavaElementLocationProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DefaultJavaElementLocationProvider.class);
|
||||
|
||||
private CompilationUnitCache cuCache;
|
||||
private JavaDocumentUriProvider javaDocUriProvider;
|
||||
|
||||
public DefaultJavaElementLocationProvider(CompilationUnitCache cuCache, JavaDocumentUriProvider javaDocUriProvider) {
|
||||
this.cuCache = cuCache;
|
||||
this.javaDocUriProvider = javaDocUriProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location findLocation(IJavaProject project, IMember member) {
|
||||
Location loc = new Location();
|
||||
String fqName = member.getDeclaringType().getFullyQualifiedName();
|
||||
URI docUri = javaDocUriProvider.docUri(project, fqName);
|
||||
if (docUri != null) {
|
||||
loc.setUri(docUri.toString());
|
||||
Optional<URL> url = SourceLinks.source(project, fqName);
|
||||
if (url.isPresent()) {
|
||||
String memberBindingKey = member.getBindingKey();
|
||||
|
||||
try {
|
||||
URI uri = url.get().toURI();
|
||||
Range r = cuCache.withCompilationUnit(project, uri, (cu) -> {
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
private Range nameRange(SimpleName nameNode) {
|
||||
int startOffset = nameNode.getStartPosition();
|
||||
int endOffset = nameNode.getLength() + startOffset;
|
||||
|
||||
// Line -1 because for CU lines are starting from 1
|
||||
return new Range(
|
||||
new Position(cu.getLineNumber(startOffset) - 1, cu.getColumnNumber(startOffset)),
|
||||
new Position(cu.getLineNumber(endOffset) - 1, cu.getColumnNumber(endOffset)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
if (member instanceof IMethod) {
|
||||
String bindingKey = node.resolveBinding().getKey();
|
||||
if (matchMethodBindingKeys(memberBindingKey, bindingKey)) {
|
||||
range.set(nameRange(node.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumConstantDeclaration node) {
|
||||
if (member instanceof IField) {
|
||||
String bindingKey = node.resolveVariable().getKey();
|
||||
if (memberBindingKey.equals(bindingKey)) {
|
||||
range.set(nameRange(node.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
if (member instanceof IType) {
|
||||
String bindingKey = node.resolveBinding().getKey();
|
||||
if (memberBindingKey.equals(bindingKey)) {
|
||||
range.set(nameRange(node.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
if (member instanceof IType) {
|
||||
String bindingKey = node.resolveBinding().getKey();
|
||||
if (memberBindingKey.equals(bindingKey)) {
|
||||
range.set(nameRange(node.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
return range.get();
|
||||
});
|
||||
if (r == null) {
|
||||
throw new IllegalStateException("Couldn't find " + member);
|
||||
}
|
||||
loc.setRange(r);
|
||||
} catch (Throwable t) {
|
||||
log.error("", t);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
private static boolean matchMethodBindingKeys(String key1, String key2) {
|
||||
return removeReturnTypeFromMethodKeyBinding(key1).equals(removeReturnTypeFromMethodKeyBinding(key2));
|
||||
}
|
||||
|
||||
private static String removeReturnTypeFromMethodKeyBinding(String key) {
|
||||
int idx = key.lastIndexOf(')');
|
||||
return idx >= 0 ? key.substring(0, idx + 1) : key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface JavaDocumentUriProvider {
|
||||
|
||||
URI docUri(IJavaProject project, String fqName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IMember;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface JavaElementLocationProvider {
|
||||
|
||||
Location findLocation(IJavaProject project, IMember member);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
public class JdtJavaDocumentUriProvider implements JavaDocumentUriProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JdtJavaDocumentUriProvider.class);
|
||||
|
||||
@Override
|
||||
public URI docUri(IJavaProject project, String fqName) {
|
||||
return uri(project, fqName);
|
||||
}
|
||||
|
||||
public static URI uri(IJavaProject project, String fqName) {
|
||||
Optional<File> classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
|
||||
if (classpathResource.isPresent()) {
|
||||
File file = classpathResource.get();
|
||||
if (file.isDirectory()) {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
return SourceLinks.sourceFromSourceFolder(fqName, classpath).map(path -> path.toUri()).orElse(null);
|
||||
} else {
|
||||
try {
|
||||
int lastDotIndex = fqName.lastIndexOf('.');
|
||||
String packageName = fqName.substring(0, lastDotIndex);
|
||||
String typeName = fqName.substring(lastDotIndex + 1);
|
||||
String jarFileName = file.getName();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("jdt://contents/");
|
||||
sb.append(jarFileName);
|
||||
sb.append("/");
|
||||
sb.append(packageName);
|
||||
sb.append("/");
|
||||
sb.append(typeName);
|
||||
sb.append(SourceLinks.CLASS);
|
||||
sb.append("?");
|
||||
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("=");
|
||||
query.append(project.getElementName());
|
||||
query.append("/");
|
||||
String convertedPath = file.toString().replace(File.separator, "\\/");
|
||||
query.append(convertedPath);
|
||||
query.append("<");
|
||||
query.append(packageName);
|
||||
query.append("(");
|
||||
query.append(typeName);
|
||||
query.append(SourceLinks.CLASS);
|
||||
|
||||
sb.append(URLEncoder.encode(query.toString(), "UTF8"));
|
||||
|
||||
return URI.create(sb.toString());
|
||||
} catch (Throwable t) {
|
||||
log.warn("Failed creating Java document URI for " + file + " type " + fqName + " in the context of project " + project.getElementName(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,54 +14,61 @@ 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.util.LspClient;
|
||||
|
||||
/**
|
||||
* Factory for creating {@link SourceLinks}
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public final class SourceLinkFactory {
|
||||
|
||||
private static final SourceLinks NO_SOURCE_LINKS = new SourceLinks() {
|
||||
|
||||
|
||||
public static final SourceLinks NO_SOURCE_LINKS = new SourceLinks() {
|
||||
|
||||
@Override
|
||||
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<String> sourceLinkForResourcePath(Path path) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates {@link SourceLinks} for specific server based on client type
|
||||
* @param server the boot LS
|
||||
* @return appropriate source links object
|
||||
*/
|
||||
public static SourceLinks createSourceLinks(BootJavaLanguageServerComponents server) {
|
||||
public static SourceLinks createSourceLinks(CompilationUnitCache cuCache) {
|
||||
switch (LspClient.currentClient()) {
|
||||
case VSCODE:
|
||||
case THEIA:
|
||||
return new VSCodeSourceLinks(server);
|
||||
case THEIA:
|
||||
return new VSCodeSourceLinks(cuCache);
|
||||
case ECLIPSE:
|
||||
return new EclipseSourceLinks();
|
||||
case ATOM:
|
||||
return new AtomSourceLinks(server);
|
||||
return new AtomSourceLinks(cuCache);
|
||||
default:
|
||||
return NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static SourceLinks createSourceLinks(BootJavaLanguageServerComponents server) {
|
||||
return server == null
|
||||
? createSourceLinks((CompilationUnitCache)null)
|
||||
: createSourceLinks(server.getCompilationUnitCache());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,25 +10,97 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.javadoc.TypeUrlProviderFromContainerUrl;
|
||||
|
||||
/**
|
||||
* Instance is able to provide client specific URL links to navigate to a
|
||||
* specific file on the client given various types of data such as fully
|
||||
* qualified java type name or classpath resource or just some file resource
|
||||
* given by its path.
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public interface SourceLinks {
|
||||
|
||||
|
||||
static final Logger log = LoggerFactory.getLogger(SourceLinks.class);
|
||||
|
||||
static final String JAR = ".jar";
|
||||
static final String CLASS = ".class";
|
||||
|
||||
public static Optional<Path> sourceFromSourceFolder(String fqName, IClasspath classpath) {
|
||||
return IClasspathUtil.getSourceFolders(classpath)
|
||||
.map(sourceFolder -> {
|
||||
try {
|
||||
return sourceFolder.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
log.warn("Failed to convert source folder {} to URI {}", sourceFolder, fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.map(url -> {
|
||||
try {
|
||||
return TypeUrlProviderFromContainerUrl.SOURCE_FOLDER_URL_SUPPLIER.url(url, fqName);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to determine source URL from url={} fqName=", url, fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.map(url -> {
|
||||
try {
|
||||
return Paths.get(url.toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
log.warn("Failed to convert URL {} to path. {}", url, fqName, e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(sourcePath -> sourcePath != null && Files.exists(sourcePath))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public static Optional<URL> source(IJavaProject project, String fqName) {
|
||||
Optional<File> classpathResourceContainer = project.findClasspathResourceContainer(fqName);
|
||||
// Try to find in a source JAR
|
||||
Optional<URL> url = classpathResourceContainer
|
||||
.flatMap(file -> project.sourceContainer(file))
|
||||
.map(file -> {
|
||||
try {
|
||||
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(file, fqName);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!url.isPresent()) {
|
||||
// Try Source folder
|
||||
url = classpathResourceContainer
|
||||
.flatMap(file -> sourceFromSourceFolder(fqName, project.getClasspath()).map(p -> {
|
||||
try {
|
||||
return p.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates link to source file defining the type passed with it's fully qualified name
|
||||
* @param project Java project in the context of which source file link is calculated
|
||||
@@ -44,12 +116,12 @@ public interface SourceLinks {
|
||||
* @return the link URL optional
|
||||
*/
|
||||
Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path);
|
||||
|
||||
|
||||
/**
|
||||
* Creates link to a file specified by it's path
|
||||
* Creates link to a file specified by it's path
|
||||
* @param path the resource path
|
||||
* @return the link URL optional
|
||||
*/
|
||||
Optional<String> sourceLinkForResourcePath(Path path);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,32 +11,24 @@
|
||||
package org.springframework.ide.vscode.boot.java.links;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.Region;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
/**
|
||||
* VSCode specific source links implementation
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class VSCodeSourceLinks extends AbstractSourceLinks {
|
||||
|
||||
private static Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(AbstractSourceLinks.class));
|
||||
|
||||
public VSCodeSourceLinks(BootJavaLanguageServerComponents server) {
|
||||
super(server);
|
||||
public VSCodeSourceLinks(CompilationUnitCache cuCache) {
|
||||
super(cuCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,41 +55,8 @@ public class VSCodeSourceLinks extends AbstractSourceLinks {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<String> jarUrl(IJavaProject project, String fqName, File jarFile) {
|
||||
try {
|
||||
int lastDotIndex = fqName.lastIndexOf('.');
|
||||
String packageName = fqName.substring(0, lastDotIndex);
|
||||
String typeName = fqName.substring(lastDotIndex + 1);
|
||||
String jarFileName = jarFile.getName();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("jdt://contents/");
|
||||
sb.append(jarFileName);
|
||||
sb.append("/");
|
||||
sb.append(packageName);
|
||||
sb.append("/");
|
||||
sb.append(typeName);
|
||||
sb.append(CLASS);
|
||||
sb.append("?");
|
||||
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("=");
|
||||
query.append(project.getElementName());
|
||||
query.append("/");
|
||||
String convertedPath = jarFile.toString().replace(File.separator, "\\/");
|
||||
query.append(convertedPath);
|
||||
query.append("<");
|
||||
query.append(packageName);
|
||||
query.append("(");
|
||||
query.append(typeName);
|
||||
query.append(CLASS);
|
||||
|
||||
sb.append(URLEncoder.encode(query.toString(), "UTF8"));
|
||||
|
||||
return Optional.of(sb.toString());
|
||||
} catch (Throwable t) {
|
||||
LOG.get().warn("Failed creating source URI for jar " + jarFile + " type " + fqName + " in the context of project " + project.getElementName(), t);
|
||||
}
|
||||
return Optional.empty();
|
||||
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile) {
|
||||
return Optional.ofNullable(JdtJavaDocumentUriProvider.uri(project, fqName)).map(uri -> uri.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@ import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
@@ -51,10 +49,10 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
private static final int MAX_INLINE_BEANS_STRING_LENGTH = 60;
|
||||
private static final String INLINE_BEANS_STRING_SEPARATOR = " ";
|
||||
|
||||
protected BootJavaLanguageServerComponents server;
|
||||
private SourceLinks sourceLinks;
|
||||
|
||||
public AbstractInjectedIntoHoverProvider(BootJavaLanguageServerComponents server) {
|
||||
this.server = server;
|
||||
public AbstractInjectedIntoHoverProvider(SourceLinks sourceLinks) {
|
||||
this.sourceLinks = sourceLinks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,18 +147,17 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
}
|
||||
|
||||
if (!injectedBeans.isEmpty()) {
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
hover.append("**");
|
||||
hover.append(LiveHoverUtils.createBeansTitleMarkdown(sourceLinks, project, injectedBeans, BEANS_PREFIX_MARKDOWN, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR));
|
||||
hover.append("**\n");
|
||||
hover.append(injectedBeans.stream()
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(server, b, " ", project))
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(sourceLinks, b, " ", project))
|
||||
.collect(Collectors.joining("\n")));
|
||||
hover.append("\n \n");
|
||||
}
|
||||
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, astNode);
|
||||
if (!wiredBeans.isEmpty()) {
|
||||
AutowiredHoverProvider.createHoverContentForBeans(server, project, hover, wiredBeans);
|
||||
AutowiredHoverProvider.createHoverContentForBeans(sourceLinks, project, hover, wiredBeans);
|
||||
}
|
||||
|
||||
hover.append("Bean id: `");
|
||||
|
||||
@@ -17,8 +17,8 @@ import java.util.Optional;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
@@ -27,8 +27,8 @@ import org.springframework.ide.vscode.commons.util.Optionals;
|
||||
|
||||
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||
|
||||
public BeanInjectedIntoHoverProvider(BootJavaLanguageServerComponents server) {
|
||||
super(server);
|
||||
public BeanInjectedIntoHoverProvider(SourceLinks sourceLinks) {
|
||||
super(sourceLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
@@ -44,8 +44,8 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
private static Logger LOG = LoggerFactory.getLogger(ComponentInjectionsHoverProvider.class);
|
||||
|
||||
public ComponentInjectionsHoverProvider(BootJavaLanguageServerComponents server) {
|
||||
super(server);
|
||||
public ComponentInjectionsHoverProvider(SourceLinks sourceLinks) {
|
||||
super(sourceLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,8 +20,6 @@ import java.util.stream.Collectors;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
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.java.utils.SpringResource;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
@@ -47,7 +45,7 @@ public class LiveHoverUtils {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String showBeanWithResource(BootJavaLanguageServerComponents server, LiveBean bean, String indentStr, IJavaProject project) {
|
||||
public static String showBeanWithResource(SourceLinks sourceLinks, LiveBean bean, String indentStr, IJavaProject project) {
|
||||
String newline = " \n"+indentStr; //Note: the double space before newline makes markdown see it as a real line break
|
||||
|
||||
if (bean == CANT_MATCH_PROPER_BEAN) {
|
||||
@@ -59,7 +57,6 @@ public class LiveHoverUtils {
|
||||
buf.append('`');
|
||||
buf.append(bean.getId());
|
||||
buf.append('`');
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
if (type != null) {
|
||||
// Try creating a URL link to open source for the type
|
||||
buf.append(newline);
|
||||
@@ -126,33 +123,6 @@ public class LiveHoverUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String showBeanIdAndTypeInline(BootJavaLanguageServerComponents server, IJavaProject project, LiveBean bean) {
|
||||
String id = bean.getId();
|
||||
String type = bean.getType(true);
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
String displayType = type;
|
||||
if (type != null) {
|
||||
int lastDotIdx = type.lastIndexOf('.');
|
||||
if (lastDotIdx >= 0 && lastDotIdx < type.length() - 1) {
|
||||
displayType = "`" + type.substring(lastDotIdx + 1) + "`";
|
||||
}
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
if (url.isPresent()) {
|
||||
displayType = Renderables.link(displayType, url.get()).toMarkdown();
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('`');
|
||||
sb.append(id);
|
||||
sb.append('`');
|
||||
if (displayType != null) {
|
||||
sb.append(' ');
|
||||
sb.append(displayType);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String showResource(SourceLinks sourceLinks, String resource, IJavaProject project) {
|
||||
return new SpringResource(sourceLinks, resource, project).toMarkdown();
|
||||
}
|
||||
|
||||
@@ -22,23 +22,27 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
public final class CompilationUnitCache {
|
||||
public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompilationUnitCache.class);
|
||||
|
||||
private static final long CU_ACCESS_EXPIRATION = 1;
|
||||
private JavaProjectFinder projectFinder;
|
||||
@@ -46,13 +50,15 @@ public final class CompilationUnitCache {
|
||||
private Cache<URI, CompilationUnit> uriToCu;
|
||||
private Cache<IJavaProject, Set<URI>> projectToDocs;
|
||||
private ProjectObserver.Listener projectListener;
|
||||
private SimpleTextDocumentService documents;
|
||||
|
||||
private ReadLock readLock;
|
||||
private WriteLock writeLock;
|
||||
|
||||
public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleTextDocumentService documentService, ProjectObserver projectObserver) {
|
||||
public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleTextDocumentService documents, ProjectObserver projectObserver) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.projectObserver = projectObserver;
|
||||
this.documents = documents;
|
||||
projectListener = ProjectObserver.onAny(this::invalidateProject);
|
||||
|
||||
// PT 154618835 - Avoid retaining the CU in the cache as it consumes memory if it hasn't been
|
||||
@@ -66,9 +72,9 @@ public final class CompilationUnitCache {
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
|
||||
if (documentService != null) {
|
||||
documentService.onDidChangeContent(doc -> invalidateCuForJavaFile(doc.getDocument().getId().getUri()));
|
||||
documentService.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
|
||||
if (documents != null) {
|
||||
documents.onDidChangeContent(doc -> invalidateCuForJavaFile(doc.getDocument().getId().getUri()));
|
||||
documents.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
|
||||
}
|
||||
|
||||
if (this.projectObserver != null) {
|
||||
@@ -90,10 +96,14 @@ public final class CompilationUnitCache {
|
||||
* not pass of AST nodes to helper functions that work aynchronously or store AST nodes or ITypeBindings
|
||||
* for later use. The JDT ASTs are not thread safe!
|
||||
*/
|
||||
@Deprecated
|
||||
public <T> T withCompilationUnit(TextDocument document, Function<CompilationUnit, T> requestor) {
|
||||
URI uri = URI.create(document.getUri());
|
||||
IJavaProject project = projectFinder.find(document.getId()).orElse(null);
|
||||
URI uri = URI.create(document.getUri());
|
||||
return withCompilationUnit(project, uri, requestor);
|
||||
}
|
||||
|
||||
public <T> T withCompilationUnit(IJavaProject project, URI uri, Function<CompilationUnit, T> requestor) {
|
||||
if (project != null) {
|
||||
|
||||
readLock.lock();
|
||||
@@ -101,15 +111,15 @@ public final class CompilationUnitCache {
|
||||
|
||||
try {
|
||||
cu = uriToCu.get(uri, () -> {
|
||||
CompilationUnit cUnit = parse(document, project);
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
|
||||
CompilationUnit cUnit = parse(uri.toString(), fetchContent(uri).toCharArray(), project);
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
|
||||
return cUnit;
|
||||
});
|
||||
if (cu != null) {
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
logger.error("", e);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
@@ -121,7 +131,7 @@ public final class CompilationUnitCache {
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.log(e);
|
||||
logger.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +139,7 @@ public final class CompilationUnitCache {
|
||||
return requestor.apply(null);
|
||||
}
|
||||
|
||||
|
||||
private void invalidateCuForJavaFile(String uriStr) {
|
||||
URI uri = URI.create(uriStr);
|
||||
writeLock.lock();
|
||||
@@ -140,13 +151,19 @@ public final class CompilationUnitCache {
|
||||
}
|
||||
|
||||
public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
|
||||
String[] classpathEntries = getClasspathEntries(document, project);
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
String docURI = document.getUri();
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
char[] source = document.get(0, document.getLength()).toCharArray();
|
||||
return parse(source, docURI, unitName, classpathEntries);
|
||||
}
|
||||
|
||||
|
||||
public static CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception {
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
String unitName = uri.substring(uri.lastIndexOf("/"));
|
||||
return parse(source, uri, unitName, classpathEntries);
|
||||
}
|
||||
|
||||
public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS10);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
@@ -168,7 +185,7 @@ public final class CompilationUnitCache {
|
||||
return cu;
|
||||
}
|
||||
|
||||
private static String[] getClasspathEntries(TextDocument document, IJavaProject project) throws Exception {
|
||||
private static String[] getClasspathEntries(IJavaProject project) throws Exception {
|
||||
if (project == null) {
|
||||
return new String[0];
|
||||
} else {
|
||||
@@ -192,4 +209,16 @@ public final class CompilationUnitCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fetchContent(URI uri) throws Exception {
|
||||
if (documents != null) {
|
||||
TextDocument document = documents.get(uri.toString());
|
||||
if (document != null) {
|
||||
return document.get(0, document.getLength());
|
||||
}
|
||||
}
|
||||
return IOUtils.toString(uri);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DocumentContentProvider {
|
||||
|
||||
String fetchContent(URI uri) throws Exception;
|
||||
|
||||
}
|
||||
@@ -35,7 +35,6 @@ import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppMatcher;
|
||||
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.links.VSCodeSourceLinks;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
@@ -72,7 +71,8 @@ public class SpringLiveChangeDetectionWatchdog {
|
||||
ProjectObserver projectObserver,
|
||||
RunningAppProvider runningAppProvider,
|
||||
JavaProjectFinder projectFinder,
|
||||
Duration pollingInterval
|
||||
Duration pollingInterval,
|
||||
SourceLinks sourceLinks
|
||||
) {
|
||||
this.observedProjects = new HashSet<>();
|
||||
|
||||
@@ -82,7 +82,7 @@ public class SpringLiveChangeDetectionWatchdog {
|
||||
this.POLLING_INTERVAL_MILLISECONDS = pollingInterval == null ? DEFAULT_INTERVAL.toMillis() : pollingInterval.toMillis();
|
||||
|
||||
this.changeHistory = new ChangeDetectionHistory();
|
||||
this.sourceLinks = new VSCodeSourceLinks(bootJavaLanguageServerComponents);
|
||||
this.sourceLinks = sourceLinks;
|
||||
|
||||
if (projectObserver != null) {
|
||||
projectObserver.addListener(new Listener() {
|
||||
|
||||
@@ -15,6 +15,7 @@ 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;
|
||||
@@ -120,10 +121,10 @@ public class StsValueHint {
|
||||
public Renderable getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
|
||||
private static Renderable javaDocSnippet(IJavaProject project, IJavaElement je) {
|
||||
return Renderables.lazy(() -> {
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(null);
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null);
|
||||
return PropertyDocUtils.documentJavaElement(sourceLinks, project, je);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import javax.inject.Provider;
|
||||
|
||||
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;
|
||||
@@ -657,7 +658,7 @@ public class TypeUtil {
|
||||
|
||||
//TODO: handle type parameters.
|
||||
if (typeFromIndex != null) {
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(null);
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null);
|
||||
IJavaProject project = getJavaProject();
|
||||
ArrayList<TypedProperty> properties = new ArrayList<>();
|
||||
getGetterMethods(typeFromIndex).forEach(m -> {
|
||||
|
||||
@@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.metadata.util;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaElement;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
@@ -27,15 +26,15 @@ import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* Boot properties documentation info utils
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class PropertyDocUtils {
|
||||
|
||||
|
||||
/**
|
||||
* Generates documentation for boot property coming from java element
|
||||
*
|
||||
*
|
||||
* @param sourceLinks
|
||||
* @param project
|
||||
* @param je
|
||||
@@ -48,10 +47,10 @@ public class PropertyDocUtils {
|
||||
renderableBuilder.add(Renderables.paragraph(javadoc == null ? Renderables.NO_DESCRIPTION: javadoc.getRenderable()));
|
||||
return Renderables.concat(renderableBuilder.build());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates documentation for the value of some Java type. Includes signature, javadoc, link to container type.
|
||||
*
|
||||
*
|
||||
* @param sourceLinks
|
||||
* @param project
|
||||
* @param je
|
||||
@@ -66,7 +65,7 @@ public class PropertyDocUtils {
|
||||
IType containingType = je instanceof IType ? (IType) je : ((IMember)je).getDeclaringType();
|
||||
if (je != null) {
|
||||
String type = containingType.getFullyQualifiedName();
|
||||
Optional<String> url = SourceLinkFactory.createSourceLinks(null).sourceLinkUrlForFQName(project, type);
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
renderableBuilder.add(Renderables.lineBreak());
|
||||
if (url.isPresent()) {
|
||||
renderableBuilder.add(Renderables.link(type, url.get()));
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.properties.hover;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo.PropertySource;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IMember;
|
||||
import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Key;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Node;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Value;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class PropertiesDefinitionCalculator {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PropertiesDefinitionCalculator.class);
|
||||
|
||||
final private PropertyFinder propertyFinder;
|
||||
final private IJavaProject project;
|
||||
final private JavaElementLocationProvider javaElementLocationProvider;
|
||||
|
||||
public PropertiesDefinitionCalculator(JavaElementLocationProvider javaElementLocationProvider, FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, IDocument doc, int offset) {
|
||||
this.javaElementLocationProvider = javaElementLocationProvider;
|
||||
this.propertyFinder = new PropertyFinder(index, typeUtil, doc, offset);
|
||||
this.project = typeUtil.getJavaProject();
|
||||
}
|
||||
|
||||
public List<Location> calculate() {
|
||||
Node node = propertyFinder.findNode();
|
||||
if (node instanceof Key) {
|
||||
Collection<IMember> propertyJavaElements = getPropertyJavaElements(((Key) node).decode());
|
||||
return getPropertyDefintion(propertyJavaElements);
|
||||
} else if (node instanceof Value) {
|
||||
Value value = (Value) node;
|
||||
Key key = value.getParent().getKey();
|
||||
|
||||
String javaTypeFqName = getPropertyJavaTypeFqName(key.decode());
|
||||
|
||||
if (javaTypeFqName != null) {
|
||||
|
||||
// Class reference value link
|
||||
if ("java.lang.Class".equals(javaTypeFqName)) {
|
||||
IType javaType = project.findType(value.decode());
|
||||
if (javaType != null) {
|
||||
Location location = findLocation(javaType);
|
||||
if (location != null) {
|
||||
return ImmutableList.of(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IType javaType = project.findType(javaTypeFqName);
|
||||
if (javaType != null) {
|
||||
// Enum value link
|
||||
if (javaType.isEnum()) {
|
||||
String enumValue = StringUtil.hyphensToUpperCase(StringUtil.camelCaseToHyphens(value.decode()));
|
||||
ImmutableList.Builder<Location> list = ImmutableList.builder();
|
||||
javaType.getFields().forEach(field -> {
|
||||
if (field.getElementName().equals(enumValue)) {
|
||||
Location location = findLocation(field);
|
||||
if (location != null) {
|
||||
list.add(location);
|
||||
}
|
||||
}
|
||||
});
|
||||
return list.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
private List<Location> getPropertyDefintion(Collection<IMember> propertyJavaElements) {
|
||||
return propertyJavaElements.stream().map(this::findLocation).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Location findLocation(IMember element) {
|
||||
return javaElementLocationProvider.findLocation(project, element);
|
||||
}
|
||||
|
||||
private String getPropertyJavaTypeFqName(String propertyKey) {
|
||||
PropertyInfo best = propertyFinder.findBestHoverMatch(propertyKey);
|
||||
if (best != null) {
|
||||
String type = best.getType();
|
||||
// Trim down generic type if present
|
||||
int idx = type == null ? -1 : type.indexOf('<');
|
||||
return idx < 0 ? type : type.substring(0, idx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<IMember> getPropertyJavaElements(String propertyKey) {
|
||||
PropertyInfo best = propertyFinder.findBestHoverMatch(propertyKey);
|
||||
if (best != null) {
|
||||
List<PropertySource> sources = best.getSources();
|
||||
if (sources != null) {
|
||||
ImmutableList.Builder<IMember> elements = ImmutableList.builder();
|
||||
for (PropertySource source : sources) {
|
||||
String typeName = source.getSourceType();
|
||||
if (typeName!=null) {
|
||||
IType type = project.findType(typeName);
|
||||
IMethod method = null;
|
||||
if (type!=null) {
|
||||
String methodSig = source.getSourceMethod();
|
||||
if (methodSig!=null) {
|
||||
method = getMethod(type, methodSig);
|
||||
} else {
|
||||
method = getSetter(type, best);
|
||||
}
|
||||
}
|
||||
if (method!=null) {
|
||||
elements.add(method);
|
||||
} else if (type!=null) {
|
||||
elements.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return elements.build();
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
private IMethod getMethod(IType type, String methodSig) {
|
||||
String name = getMethodName(methodSig);
|
||||
//TODO: This code assumes 0 arguments, which is the case currently for all
|
||||
// 'real' data in spring jars.
|
||||
IMethod m = type.getMethod(name, Stream.empty());
|
||||
if (m!=null) {
|
||||
return m;
|
||||
}
|
||||
//try find a method with the same name.
|
||||
return type.getMethods()
|
||||
.filter(meth -> name.equals(meth.getElementName()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static String getMethodName(String methodSig) {
|
||||
String name;
|
||||
int nameEnd = methodSig.indexOf('(');
|
||||
if (nameEnd>=0) {
|
||||
name = methodSig.substring(0, nameEnd);
|
||||
int space = name.lastIndexOf(' ');
|
||||
if (space >= 0) {
|
||||
name = name.substring(space + 1);
|
||||
}
|
||||
} else {
|
||||
name = methodSig;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find corresponding setter method for a given property.
|
||||
* @return setter method, or null if not found.
|
||||
*/
|
||||
private IMethod getSetter(IType type, PropertyInfo propertyInfo) {
|
||||
try {
|
||||
String propName = propertyInfo.getName();
|
||||
String setterName = "set"
|
||||
+Character.toUpperCase(propName.charAt(0))
|
||||
+toCamelCase(propName.substring(1));
|
||||
String sloppySetterName = setterName.toLowerCase();
|
||||
|
||||
IMethod sloppyMatch = null;
|
||||
for (IMethod m : type.getMethods().collect(Collectors.toList())) {
|
||||
String mname = m.getElementName();
|
||||
if (setterName.equals(mname)) {
|
||||
//found 'exact' name match... done
|
||||
return m;
|
||||
} else if (mname.toLowerCase().equals(sloppySetterName)) {
|
||||
sloppyMatch = m;
|
||||
}
|
||||
}
|
||||
return sloppyMatch;
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hyphened name to camel case name. It is
|
||||
* safe to call this on an already camel-cased name.
|
||||
*/
|
||||
private String toCamelCase(String name) {
|
||||
if (name.isEmpty()) {
|
||||
return name;
|
||||
} else {
|
||||
StringBuilder camel = new StringBuilder();
|
||||
char[] chars = name.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c=='-') {
|
||||
i++;
|
||||
if (i<chars.length) {
|
||||
camel.append(Character.toUpperCase(chars[i]));
|
||||
}
|
||||
} else {
|
||||
camel.append(chars[i]);
|
||||
}
|
||||
}
|
||||
return camel.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016-2017 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -24,20 +24,15 @@ import java.util.Optional;
|
||||
|
||||
import org.springframework.ide.vscode.boot.common.InformationTemplates;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex;
|
||||
import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.Type;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
|
||||
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Key;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Node;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Value;
|
||||
@@ -49,24 +44,15 @@ import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
class PropertiesHoverCalculator {
|
||||
|
||||
private FuzzyMap<PropertyInfo> index;
|
||||
private TypeUtil typeUtil;
|
||||
private IDocument doc;
|
||||
private int offset;
|
||||
private AntlrParser parser;
|
||||
|
||||
|
||||
private PropertyFinder propertyFinder;
|
||||
|
||||
PropertiesHoverCalculator(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, IDocument doc, int offset) {
|
||||
this.index = index;
|
||||
this.typeUtil = typeUtil;
|
||||
this.doc = doc;
|
||||
this.offset = offset;
|
||||
this.parser = new AntlrParser();
|
||||
this.propertyFinder = new PropertyFinder(index, typeUtil, doc, offset);
|
||||
}
|
||||
|
||||
|
||||
Tuple2<Renderable, IRegion> calculate() {
|
||||
ParseResults parseResults = parser.parse(doc.get());
|
||||
Node node = parseResults.ast.findNode(offset);
|
||||
Node node = propertyFinder.findNode();
|
||||
if (node instanceof Value) {
|
||||
return getValueHover((Value)node);
|
||||
} else if (node instanceof Key) {
|
||||
@@ -74,35 +60,24 @@ class PropertiesHoverCalculator {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DocumentRegion createRegion(IDocument doc, Node value) {
|
||||
// Trim trailing spaces (there is no leading white space already)
|
||||
int length = value.getLength();
|
||||
try {
|
||||
length = doc.get(value.getOffset(), value.getLength()).length();
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
}
|
||||
return new DocumentRegion(doc, value.getOffset(), value.getOffset() + length);
|
||||
}
|
||||
|
||||
|
||||
private Tuple2<Renderable, IRegion> getPropertyHover(Key property) {
|
||||
PropertyInfo best = findBestHoverMatch(property.decode());
|
||||
PropertyInfo best = propertyFinder.findBestHoverMatch(property.decode());
|
||||
if (best == null) {
|
||||
return null;
|
||||
} else {
|
||||
Renderable renderable = InformationTemplates.createHover(best);
|
||||
DocumentRegion region = createRegion(doc, property);
|
||||
DocumentRegion region = propertyFinder.createRegion(property);
|
||||
return Tuples.of(renderable, region.asRegion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Tuple2<Renderable, IRegion> getValueHover(Value value) {
|
||||
DocumentRegion valueRegion = createRegion(doc, value).trimStart(SPACES).trimEnd(SPACES);
|
||||
if (valueRegion.getStart() <= offset && offset < valueRegion.getEnd()) {
|
||||
DocumentRegion valueRegion = propertyFinder.createRegion(value).trimStart(SPACES).trimEnd(SPACES);
|
||||
if (valueRegion.getStart() <= propertyFinder.offset && propertyFinder.offset < valueRegion.getEnd()) {
|
||||
String valueString = valueRegion.toString();
|
||||
String propertyName = value.getParent().getKey().decode();
|
||||
Type type = getValueType(index, typeUtil, propertyName);
|
||||
Type type = getValueType(propertyFinder.index, propertyFinder.typeUtil, propertyName);
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
//It is useful to provide content assist for the values in the list when entering a list
|
||||
type = TypeUtil.getDomainType(type);
|
||||
@@ -110,14 +85,14 @@ class PropertiesHoverCalculator {
|
||||
if (TypeUtil.isClass(type)) {
|
||||
//Special case. We want to provide hoverinfos more liberally than what's suggested for completions (i.e. even class names
|
||||
//that are not suggested by the hints because they do not meet subtyping constraints should be hoverable and linkable!
|
||||
StsValueHint hint = StsValueHint.className(valueString, typeUtil);
|
||||
StsValueHint hint = StsValueHint.className(valueString, propertyFinder.typeUtil);
|
||||
if (hint!=null) {
|
||||
return Tuples.of(createRenderable(hint), valueRegion.asRegion());
|
||||
}
|
||||
}
|
||||
//Hack: pretend to invoke content-assist at the end of the value text. This should provide hints applicable to that value
|
||||
// then show hoverinfo based on that. That way we can avoid duplication a lot of similar logic to compute hoverinfos and hyperlinks.
|
||||
Collection<StsValueHint> hints = getValueHints(index, typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
Collection<StsValueHint> hints = getValueHints(propertyFinder.index, propertyFinder.typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
if (hints!=null) {
|
||||
Optional<StsValueHint> hint = hints.stream().filter(h -> valueString.equals(h.getValue())).findFirst();
|
||||
if (hint.isPresent()) {
|
||||
@@ -127,7 +102,7 @@ class PropertiesHoverCalculator {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private Renderable createRenderable(StsValueHint hint) {
|
||||
Renderable description = hint.getDescription();
|
||||
try {
|
||||
@@ -151,36 +126,4 @@ class PropertiesHoverCalculator {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search known properties for the best 'match' to show as hover data.
|
||||
*/
|
||||
private PropertyInfo findBestHoverMatch(String propName) {
|
||||
PropertyInfo propertyInfo = index.get(propName);
|
||||
if (propertyInfo == null) {
|
||||
propertyInfo = SpringPropertyIndex.findLongestValidProperty(index, propName);
|
||||
}
|
||||
return propertyInfo;
|
||||
// //TODO: optimize, should be able to use index's treemap to find this without iterating all entries.
|
||||
// PropertyInfo best = null;
|
||||
// int bestCommonPrefixLen = 0; //We try to pick property with longest common prefix
|
||||
// int bestExtraLen = Integer.MAX_VALUE;
|
||||
// for (PropertyInfo candidate : index) {
|
||||
// int commonPrefixLen = StringUtil.commonPrefixLength(propName, candidate.getId());
|
||||
// int extraLen = candidate.getId().length()-commonPrefixLen;
|
||||
// if (commonPrefixLen==propName.length() && extraLen==0) {
|
||||
// //exact match found, can stop searching for better matches
|
||||
// return candidate;
|
||||
// }
|
||||
// //candidate is better if...
|
||||
// if (commonPrefixLen>bestCommonPrefixLen // it has a longer common prefix
|
||||
// || commonPrefixLen==bestCommonPrefixLen && extraLen<bestExtraLen //or same common prefix but fewer extra chars
|
||||
// ) {
|
||||
// bestCommonPrefixLen = commonPrefixLen;
|
||||
// bestExtraLen = extraLen;
|
||||
// best = candidate;
|
||||
// }
|
||||
// }
|
||||
// return best;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.properties.hover;
|
||||
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
|
||||
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
|
||||
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Node;
|
||||
|
||||
class PropertyFinder {
|
||||
|
||||
final FuzzyMap<PropertyInfo> index;
|
||||
final TypeUtil typeUtil;
|
||||
final IDocument doc;
|
||||
final int offset;
|
||||
final AntlrParser parser;
|
||||
|
||||
PropertyFinder(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, IDocument doc, int offset) {
|
||||
this.index = index;
|
||||
this.typeUtil = typeUtil;
|
||||
this.doc = doc;
|
||||
this.offset = offset;
|
||||
this.parser = new AntlrParser();
|
||||
}
|
||||
|
||||
Node findNode() {
|
||||
ParseResults parseResults = parser.parse(doc.get());
|
||||
return parseResults.ast.findNode(offset);
|
||||
}
|
||||
|
||||
DocumentRegion createRegion(Node value) {
|
||||
// Trim trailing spaces (there is no leading white space already)
|
||||
int length = value.getLength();
|
||||
try {
|
||||
length = doc.get(value.getOffset(), value.getLength()).length();
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
}
|
||||
return new DocumentRegion(doc, value.getOffset(), value.getOffset() + length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search known properties for the best 'match' to show as hover data.
|
||||
*/
|
||||
PropertyInfo findBestHoverMatch(String propName) {
|
||||
PropertyInfo propertyInfo = index.get(propName);
|
||||
if (propertyInfo == null) {
|
||||
propertyInfo = SpringPropertyIndex.findLongestValidProperty(index, propName);
|
||||
}
|
||||
return propertyInfo;
|
||||
// //TODO: optimize, should be able to use index's treemap to find this without iterating all entries.
|
||||
// PropertyInfo best = null;
|
||||
// int bestCommonPrefixLen = 0; //We try to pick property with longest common prefix
|
||||
// int bestExtraLen = Integer.MAX_VALUE;
|
||||
// for (PropertyInfo candidate : index) {
|
||||
// int commonPrefixLen = StringUtil.commonPrefixLength(propName, candidate.getId());
|
||||
// int extraLen = candidate.getId().length()-commonPrefixLen;
|
||||
// if (commonPrefixLen==propName.length() && extraLen==0) {
|
||||
// //exact match found, can stop searching for better matches
|
||||
// return candidate;
|
||||
// }
|
||||
// //candidate is better if...
|
||||
// if (commonPrefixLen>bestCommonPrefixLen // it has a longer common prefix
|
||||
// || commonPrefixLen==bestCommonPrefixLen && extraLen<bestExtraLen //or same common prefix but fewer extra chars
|
||||
// ) {
|
||||
// bestCommonPrefixLen = commonPrefixLen;
|
||||
// bestExtraLen = extraLen;
|
||||
// best = candidate;
|
||||
// }
|
||||
// }
|
||||
// return best;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.springframework.ide.vscode.boot.common.InformationTemplates;
|
||||
import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory;
|
||||
import org.springframework.ide.vscode.boot.common.RelaxedNameConfig;
|
||||
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.IndexNavigator;
|
||||
@@ -551,7 +552,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
if (jes != null) {
|
||||
for (IJavaElement je : jes) {
|
||||
if (je instanceof IMember) {
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(null);
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks((BootJavaLanguageServerComponents)null);
|
||||
IJavaProject project = typeUtil.getJavaProject();
|
||||
return PropertyDocUtils.documentJavaElement(sourceLinks, project, je);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -24,7 +23,6 @@ import org.springframework.ide.vscode.boot.app.BootLanguagServerBootApp;
|
||||
import org.springframework.ide.vscode.languageserver.starter.LanguageServerAutoConf;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target(TYPE)
|
||||
|
||||
@@ -6,6 +6,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.boot.app.BootLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
@@ -47,4 +49,9 @@ public class HoverTestConf {
|
||||
@Bean JavaProjectFinder projectFinder(BootLanguageServerParams serverParams) {
|
||||
return serverParams.projectFinder;
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks() {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.boot.app.BootLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider;
|
||||
@@ -56,4 +59,9 @@ import org.springframework.ide.vscode.project.harness.MockRunningAppProvider;
|
||||
@Bean JavaProjectFinder projectFinder(BootLanguageServerParams serverParams) {
|
||||
return serverParams.projectFinder;
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(CompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import org.springframework.ide.vscode.boot.app.BootLanguageServerInitializer;
|
||||
import org.springframework.ide.vscode.boot.app.BootLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
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.java.utils.SpringIndexer;
|
||||
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -38,4 +40,8 @@ import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
@Bean DefaultSpringPropertyIndexProvider indexProvider(BootLanguageServerParams serverParams) {
|
||||
return (DefaultSpringPropertyIndexProvider) serverParams.indexProvider;
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks() {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.boot.java.autowired.test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -26,11 +25,9 @@ import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServerWrapper;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.MockRunningAppProvider;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
@@ -33,8 +33,12 @@ import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -94,6 +98,10 @@ public class CompilationUnitCacheTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, CompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.javadoc.JavaDocProviders;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenBuilder;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
@@ -55,11 +56,11 @@ public class VSCodeSourceLinksTest {
|
||||
@Test
|
||||
public void testJavaSourceUrl() throws Exception {
|
||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
|
||||
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(null, null, null)).sourceLinkUrlForFQName(project, "com.example.EmptyBoot15WebAppApplication");
|
||||
assertTrue(url.isPresent());
|
||||
Path projectPath = Paths.get(project.pom().getParent());
|
||||
URI uri = URI.create(url.get());
|
||||
|
||||
|
||||
// Use File to get rid of the fragment parts of the URL. The URL may have fragments that indicate line and column numbers
|
||||
uri = new File(uri.getPath()).toURI();
|
||||
|
||||
@@ -72,7 +73,7 @@ public class VSCodeSourceLinksTest {
|
||||
@Test
|
||||
public void testJarUrl() throws Exception {
|
||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "org.springframework.boot.autoconfigure.SpringBootApplication");
|
||||
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(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);
|
||||
@@ -83,7 +84,7 @@ public class VSCodeSourceLinksTest {
|
||||
@Test
|
||||
public void testJarUrlInnerType() throws Exception {
|
||||
MavenJavaProject project = mavenProjectsCache.get("empty-boot-15-web-app");
|
||||
Optional<String> url = new VSCodeSourceLinks(null).sourceLinkUrlForFQName(project, "org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback");
|
||||
Optional<String> url = new VSCodeSourceLinks(new CompilationUnitCache(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);
|
||||
|
||||
@@ -29,11 +29,15 @@ import org.springframework.ide.vscode.boot.app.BootLanguageServerParams;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
|
||||
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.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
@@ -90,6 +94,11 @@ public class ValueCompletionTest {
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, CompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
|
||||
@@ -16,14 +16,30 @@ import static org.springframework.ide.vscode.boot.properties.reconcile.Applicati
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.ClasspathTestUtil.getOutputFolder;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.junit.Before;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -31,22 +47,28 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ide.vscode.boot.app.BootLanguageServerInitializer;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.PropertyEditorTestConf;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.AbstractPropsEditorTest;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.StyledStringMatcher;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.metadata.CachingValueProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertiesLoader;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness.ProjectCustomizer;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
/**
|
||||
@@ -59,6 +81,15 @@ import com.google.common.io.Files;
|
||||
@Import(PropertyEditorTestConf.class)
|
||||
public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
@Autowired
|
||||
CompilationUnitCache cuCache;
|
||||
|
||||
@Autowired
|
||||
SimpleTextDocumentService docService;
|
||||
|
||||
@Autowired
|
||||
JavaDocumentUriProvider javaDocumentUriProvider;
|
||||
|
||||
@Configuration static class TestConf {
|
||||
@Bean LanguageId defaultLanguageId() {
|
||||
return LanguageId.BOOT_PROPERTIES;
|
||||
@@ -275,7 +306,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
assertContains("\"name\": \"foo.counter\"", Files.toString(metadataFile.toFile(), Charset.forName("UTF8")));
|
||||
}
|
||||
|
||||
@Ignore @Test public void testHyperlinkTargets() throws Exception {
|
||||
@Test public void testHyperlinkTargets() throws Exception {
|
||||
System.out.println(">>> testHyperlinkTargets");
|
||||
IJavaProject p = createPredefinedMavenProject("tricky-getters-boot-1.3.1-app");
|
||||
useProject(p);
|
||||
@@ -286,20 +317,260 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
"flyway.init-sqls=a,b,c\n"
|
||||
);
|
||||
|
||||
editor.assertLinkTargets("server",
|
||||
"org.springframework.boot.autoconfigure.web.ServerProperties.setPort(Integer)"
|
||||
assertLinkTargets(editor, "server", p,
|
||||
method("org.springframework.boot.autoconfigure.web.ServerProperties", "setPort", "java.lang.Integer"));
|
||||
|
||||
assertLinkTargets(editor, "data", p,
|
||||
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "hikariDataSource"),
|
||||
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "tomcatDataSource"),
|
||||
method("org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata", "dbcpDataSource")
|
||||
);
|
||||
editor.assertLinkTargets("data",
|
||||
"org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata.hikariDataSource()",
|
||||
"org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata.tomcatDataSource()",
|
||||
"org.springframework.boot.autoconfigure.jdbc.DataSourceConfigMetadata.dbcpDataSource()"
|
||||
);
|
||||
editor.assertLinkTargets("flyway",
|
||||
"org.springframework.boot.autoconfigure.flyway.FlywayProperties.setInitSqls(List<String>)");
|
||||
|
||||
assertLinkTargets(editor, "flyway", p, method("org.springframework.boot.autoconfigure.flyway.FlywayProperties", "setInitSqls", "java.util.List"));
|
||||
System.out.println("<<< testHyperlinkTargets");
|
||||
}
|
||||
|
||||
@Ignore @Test public void testHyperlinkTargetsLoggingLevel() throws Exception {
|
||||
void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, JavaMethod... methods) throws Exception {
|
||||
Set<Location> expectedLocations = Arrays.stream(methods).map(method -> {
|
||||
try {
|
||||
return getLocation(project, method);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
|
||||
editor.assertLinkTargets(hoverOver, expectedLocations);
|
||||
}
|
||||
|
||||
void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, String typeFqName) throws Exception {
|
||||
|
||||
Location expectedLocation = getLocation(project, typeFqName);
|
||||
|
||||
System.out.println("Expected Location: " + expectedLocation);
|
||||
|
||||
editor.assertLinkTargets(hoverOver, ImmutableSet.of(expectedLocation));
|
||||
}
|
||||
|
||||
void assertLinkTargets(Editor editor, String hoverOver, IJavaProject project, JavaField field) throws Exception {
|
||||
|
||||
Location expectedLocation = getLocation(project, field);
|
||||
|
||||
System.out.println("Expected Location: " + expectedLocation);
|
||||
|
||||
editor.assertLinkTargets(hoverOver, ImmutableSet.of(expectedLocation));
|
||||
}
|
||||
|
||||
static private JavaMethod method(String fqClassName, String methodName, String... params) {
|
||||
return new JavaMethod(fqClassName, methodName, params);
|
||||
}
|
||||
|
||||
static private JavaField field(String fqClassName, String name) {
|
||||
return new JavaField(fqClassName, name);
|
||||
}
|
||||
|
||||
static class JavaMethod {
|
||||
public final String fqName;
|
||||
public final String methodName;
|
||||
public final String[] params;
|
||||
public JavaMethod(String fqClassName, String methodName, String... params) {
|
||||
this.fqName = fqClassName;
|
||||
this.methodName = methodName;
|
||||
this.params = params;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JavaMethod [fqName=" + fqName + ", methodName=" + methodName + ", params=" + Arrays.toString(params)
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
|
||||
static class JavaField {
|
||||
public final String fqName;
|
||||
public final String fieldName;
|
||||
public JavaField(String fqName, String fieldName) {
|
||||
super();
|
||||
this.fqName = fqName;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JavaField [fqName=" + fqName + ", fieldName=" + fieldName + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private Location getLocation(IJavaProject project, String fqName) throws Exception {
|
||||
Location loc = new Location();
|
||||
Optional<URL> sourceUrl = SourceLinks.source(project, fqName);
|
||||
if (sourceUrl.isPresent()) {
|
||||
|
||||
URI docUri = javaDocumentUriProvider.docUri(project, fqName);
|
||||
loc.setUri(docUri.toString());
|
||||
|
||||
String typeName = fqName.substring(fqName.lastIndexOf('.') + 1);
|
||||
URI sourceUri = sourceUrl.get().toURI();
|
||||
Range r = cuCache.withCompilationUnit(project, sourceUri, (cu) -> {
|
||||
try {
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
private boolean proceessTypeNode(TextDocument doc, String typeName,
|
||||
AtomicReference<Range> range, AbstractTypeDeclaration node) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(typeName)) {
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
return false;
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
return proceessTypeNode(doc, typeName, range, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
return proceessTypeNode(doc, typeName, range, node);
|
||||
}
|
||||
|
||||
});
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
if (r == null) {
|
||||
throw new IllegalStateException("Couldn't find " + fqName);
|
||||
}
|
||||
loc.setRange(r);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
private Location getLocation(IJavaProject project, JavaMethod method) throws Exception {
|
||||
Location loc = new Location();
|
||||
Optional<URL> sourceUrl = SourceLinks.source(project, method.fqName);
|
||||
if (sourceUrl.isPresent()) {
|
||||
|
||||
URI docUri = javaDocumentUriProvider.docUri(project, method.fqName);
|
||||
loc.setUri(docUri.toString());
|
||||
|
||||
URI sourceUri = sourceUrl.get().toURI();
|
||||
Range r = cuCache.withCompilationUnit(project, sourceUri, (cu) -> {
|
||||
try {
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(method.methodName)) {
|
||||
if (node.parameters().size() != method.params.length) {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
for (Object _p : node.parameters()) {
|
||||
if (_p instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration p = (SingleVariableDeclaration) _p;
|
||||
String fqName = p.getType().resolveBinding().getErasure().getQualifiedName();
|
||||
if (!fqName.equals(method.params[i++])) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
if (r == null) {
|
||||
throw new IllegalStateException("Couldn't find " + method);
|
||||
}
|
||||
loc.setRange(r);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
private Location getLocation(IJavaProject project, JavaField field) throws Exception {
|
||||
Location loc = new Location();
|
||||
|
||||
Optional<URL> sourceUrl = SourceLinks.source(project, field.fqName);
|
||||
if (sourceUrl.isPresent()) {
|
||||
|
||||
URI sourceUri = sourceUrl.get().toURI();
|
||||
|
||||
URI docUri = javaDocumentUriProvider.docUri(project, field.fqName);
|
||||
loc.setUri(docUri.toString());
|
||||
|
||||
Range r = cuCache.withCompilationUnit(project, sourceUri, (cu) -> {
|
||||
try {
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
boolean foundType = false;
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumConstantDeclaration node) {
|
||||
if (foundType) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(field.fieldName)) {
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
if (node.getName().getIdentifier()
|
||||
.equals(field.fqName.substring(field.fqName.lastIndexOf('.') + 1))) {
|
||||
foundType = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
if (r == null) {
|
||||
throw new IllegalStateException("Couldn't find " + field);
|
||||
}
|
||||
loc.setRange(r);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Test public void testHyperlinkTargetsLoggingLevel() throws Exception {
|
||||
System.out.println(">>> testHyperlinkTargetsLoggingLevel");
|
||||
IJavaProject p = createPredefinedMavenProject("tricky-getters-boot-1.3.1-app");
|
||||
|
||||
@@ -308,9 +579,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
Editor editor = newEditor(
|
||||
"logging.level.com.acme=INFO\n"
|
||||
);
|
||||
editor.assertLinkTargets("level",
|
||||
"org.springframework.boot.logging.LoggingApplicationListener"
|
||||
);
|
||||
|
||||
assertLinkTargets(editor, "level", p, "org.springframework.boot.logging.LoggingApplicationListener");
|
||||
System.out.println("<<< testHyperlinkTargetsLoggingLevel");
|
||||
}
|
||||
|
||||
@@ -1422,16 +1692,17 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Ignore @Test public void testClassReferenceInValueLink() throws Exception {
|
||||
@Test public void testClassReferenceInValueLink() throws Exception {
|
||||
Editor editor;
|
||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-with-mongo"));
|
||||
MavenJavaProject project = createPredefinedMavenProject("empty-boot-1.3.0-with-mongo");
|
||||
useProject(project);
|
||||
|
||||
editor = newEditor(
|
||||
"#stuff\n" +
|
||||
"spring.data.mongodb.field-naming-strategy=org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy\n" +
|
||||
"#more stuff"
|
||||
);
|
||||
editor.assertLinkTargets("org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy");
|
||||
assertLinkTargets(editor, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy", project, "org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy");
|
||||
|
||||
//Linking should also work for types that aren't valid based on the constraints
|
||||
editor = newEditor(
|
||||
@@ -1439,7 +1710,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
"spring.data.mongodb.field-naming-strategy=java.lang.String\n" +
|
||||
"#more stuff"
|
||||
);
|
||||
editor.assertLinkTargets("java.lang.String", "java.lang.String");
|
||||
assertLinkTargets(editor, "java.lang.String", project, "java.lang.String");
|
||||
}
|
||||
|
||||
@Test public void testCommaListReconcile() throws Exception {
|
||||
@@ -1601,9 +1872,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
editor.assertHoverContains("red", "Hot and delicious");
|
||||
}
|
||||
|
||||
|
||||
@Ignore @Test public void testEnumInValueLink() throws Exception {
|
||||
useProject(createPredefinedMavenProject("enums-boot-1.3.2-app"));
|
||||
@Test public void testEnumInValueLink() throws Exception {
|
||||
MavenJavaProject project = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||
useProject(project);
|
||||
data("my.background", "demo.Color", null, "Color to use as default background.");
|
||||
|
||||
Editor editor;
|
||||
@@ -1611,12 +1882,25 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
editor = newEditor(
|
||||
"my.background: RED"
|
||||
);
|
||||
editor.assertLinkTargets("RED", "demo.Color.RED");
|
||||
assertLinkTargets(editor, "RED", project, field("demo.Color", "RED"));
|
||||
|
||||
editor = newEditor(
|
||||
"my.background=red"
|
||||
);
|
||||
editor.assertLinkTargets("red", "demo.Color.RED");
|
||||
assertLinkTargets(editor, "red", project, field("demo.Color", "RED"));
|
||||
}
|
||||
|
||||
@Test public void testEnumInPojoField() throws Exception {
|
||||
MavenJavaProject project = createPredefinedMavenProject("enum-def-nav");
|
||||
useProject(project);
|
||||
|
||||
Editor editor;
|
||||
|
||||
editor = newEditor(
|
||||
"my.screen.background=green"
|
||||
);
|
||||
assertLinkTargets(editor, "background", project, method("com.example.demo.MyProperties$Screen", "getScreen"));
|
||||
assertLinkTargets(editor, "green", project, field("com.example.demo.Color", "GREEN"));
|
||||
}
|
||||
|
||||
@Test public void testNoHoverForUnrecognizedProperty() throws Exception {
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
||||
286
headless-services/spring-boot-language-server/src/test/resources/test-projects/enum-def-nav/mvnw
vendored
Executable file
286
headless-services/spring-boot-language-server/src/test/resources/test-projects/enum-def-nav/mvnw
vendored
Executable file
@@ -0,0 +1,286 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
161
headless-services/spring-boot-language-server/src/test/resources/test-projects/enum-def-nav/mvnw.cmd
vendored
Normal file
161
headless-services/spring-boot-language-server/src/test/resources/test-projects/enum-def-nav/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>enum-def-nav</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>enum-def-nav</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.0.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.demo;
|
||||
|
||||
public enum Color {
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class EnumDefNavApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(EnumDefNavApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.example.demo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("my")
|
||||
public class MyProperties {
|
||||
|
||||
public static class Screen {
|
||||
private Color foreground;
|
||||
private Color background;
|
||||
public Color getForeground() {
|
||||
return foreground;
|
||||
}
|
||||
public void setForeground(Color foreground) {
|
||||
this.foreground = foreground;
|
||||
}
|
||||
public Color getBackground() {
|
||||
return background;
|
||||
}
|
||||
public void setBackground(Color background) {
|
||||
this.background = background;
|
||||
}
|
||||
}
|
||||
|
||||
private Screen screen;
|
||||
private Screen[] screenArray;
|
||||
private List<Screen> screenList;
|
||||
private Map<Color, Screen> screenMap;
|
||||
|
||||
public Screen getScreen() {
|
||||
return screen;
|
||||
}
|
||||
|
||||
public void setScreen(Screen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
public Screen[] getScreenArray() {
|
||||
return screenArray;
|
||||
}
|
||||
|
||||
public void setScreenArray(Screen[] screenArray) {
|
||||
this.screenArray = screenArray;
|
||||
}
|
||||
|
||||
public List<Screen> getScreenList() {
|
||||
return screenList;
|
||||
}
|
||||
|
||||
public void setScreenList(List<Screen> screenList) {
|
||||
this.screenList = screenList;
|
||||
}
|
||||
|
||||
public Map<Color, Screen> getScreenMap() {
|
||||
return screenMap;
|
||||
}
|
||||
|
||||
public void setScreenMap(Map<Color, Screen> screenMap) {
|
||||
this.screenMap = screenMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.example.demo;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class EnumDefNavApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user