Merge branch 'master' of github.com:spring-projects/sts4

This commit is contained in:
Kris De Volder
2018-12-06 15:29:21 -08:00
30 changed files with 557 additions and 407 deletions

View File

@@ -22,7 +22,7 @@ import org.gradle.tooling.model.eclipse.EclipseProject;
import org.gradle.tooling.model.eclipse.EclipseProjectDependency;
import org.gradle.tooling.model.eclipse.EclipseSourceDirectory;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.languageserver.java.JavaUtils;
import org.springframework.ide.vscode.commons.java.JavaUtils;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;

View File

@@ -11,32 +11,21 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.JarIndexer;
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.IJavaModuleData;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
@@ -71,212 +60,106 @@ public class BasicJandexIndex {
return folder;
}
private Map<File, Supplier<Optional<IndexView>>> index;
private ImmutableList<ModuleJandexIndex> modules;
private Map<File, Supplier<List<Tuple3<String, File, ClassInfo>>>> knownTypes;
private Map<File, Supplier<List<String>>> knownPackages;
private BasicJandexIndex[] baseIndex;
BasicJandexIndex(Collection<File> classpathEntries, IndexFileFinder indexFileFinder,
BasicJandexIndex... baseIndex) {
this.baseIndex = baseIndex;
this.index = new ConcurrentHashMap<>();
this.knownTypes = new HashMap<>();
this.knownPackages = new HashMap<>();
classpathEntries.forEach(file -> {
index.put(file, /*Suppliers.synchronizedSupplier(*/Suppliers.memoize(() -> createIndex(file, indexFileFinder))/*)*/);
knownTypes.put(file, Suppliers.memoize(() -> getKnownTypesStream(file).collect(Collectors.toList())));
knownPackages.put(file, Suppliers.memoize(() -> getKnownPackages(file).collect(Collectors.toList())));
});
}
private Optional<IndexView> createIndex(File file, IndexFileFinder indexFileFinder) {
if (file != null && file.isFile() && file.getName().endsWith(".jar")) {
return indexJar(file, indexFileFinder);
} else if (file != null && file.isDirectory()) {
return indexFolder(file);
} else {
return Optional.empty();
BasicJandexIndex(IClasspath classpath, IndexFileFinder indexFileFinder) {
ImmutableList.Builder<ModuleJandexIndex> builder = ImmutableList.builder();
try {
classpath.getClasspathEntries().forEach(cpe -> {
File binaryLocation = IClasspathUtil.binaryLocation(cpe);
builder.addAll(IndexRoutines.fromCPE(cpe, indexFileFinder.findIndexFile(binaryLocation)));
});
} catch (Exception e) {
log.error("", e);
}
this.modules = builder.build();
}
private static Optional<IndexView> indexFolder(File folder) {
Indexer indexer = new Indexer();
for (Iterator<File> itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder)
.iterator(); itr.hasNext();) {
File file = itr.next();
if (file.isFile() && file.getName().endsWith(".class")) {
try {
final InputStream stream = new FileInputStream(file);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
log.error("Failed to index file " + file, e);
Tuple2<IJavaModuleData, ClassInfo> getClassByName(DotName fqName) {
for (ModuleJandexIndex m : modules) {
IndexView indexView = m.getIndex().get();
if (indexView != null) {
ClassInfo info = indexView.getClassByName(fqName);
if (info != null) {
return Tuples.of(m, info);
}
}
}
return Optional.of(indexer.complete());
return null;
}
private static Optional<IndexView> indexJar(File file, IndexFileFinder indexFileFinder) {
File indexFile = indexFileFinder.findIndexFile(file);
if (indexFile != null) {
try {
if (!indexFile.getParentFile().exists()) {
indexFile.getParentFile().mkdirs();
public IJavaModuleData findClasspathResourceForType(String fqName) {
Tuple2<IJavaModuleData, ClassInfo> match = getClassByName(DotName.createSimple(fqName));
return match == null ? null : match.getT1();
}
private Collection<String> getKnownPackages(ModuleJandexIndex module) {
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
IndexView indexView = module.getIndex().get();
if (indexView != null) {
indexView.getKnownClasses();
Collection<ClassInfo> knownClasses = indexView.getKnownClasses();
if (knownClasses != null) {
for (ClassInfo info : knownClasses) {
String name = info.name().toString();
String pkg = name.substring(0, name.lastIndexOf('.'));
builder.add(pkg);
}
if (indexFile.createNewFile()) {
try {
return Optional.of(JarIndexer.createJarIndex(file, new Indexer(), indexFile, false, false,
false, System.out, System.err).getIndex());
} catch (IOException e) {
log.error("Failed to index '" + file + "'", e);
}
} else {
try {
return Optional.of(new IndexReader(new FileInputStream(indexFile)).read());
} catch (IOException e) {
log.error("Failed to read index file '" + indexFile + "'. Creating new index file.", e);
if (indexFile.delete()) {
return indexJar(file, indexFileFinder);
} else {
log.error("Failed to read index file '" + indexFile);
}
}
}
} catch (IOException e) {
log.error("Unable to create index file '" + indexFile + "'", e);
}
} else {
try {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), false)
.getIndex());
} catch (IOException e) {
log.error("Failed to index '" + file + "'", e);
}
}
return Optional.empty();
return builder.build();
}
Tuple2<File, ClassInfo> getClassByName(DotName fqName) {
// First look for type in the base index array
return (baseIndex == null ? Stream.<Tuple2<File, ClassInfo>>empty()
: Arrays.stream(
baseIndex)
.filter(
jandexIndex -> jandexIndex != null)
.map(jandexIndex -> jandexIndex.getClassByName(fqName))).filter(type -> type != null)
.findFirst()
// If not found look at indices owned by this
// JandexIndex instance
.orElseGet(() -> streamOfIndices()
.map(e -> Tuples.of(e.getT1(), Optional.ofNullable(e.getT2().getClassByName(fqName))))
.filter(t -> t.getT2().isPresent())
.map(e -> Tuples.of(e.getT1(), e.getT2().get())).findFirst()
.orElse(null));
}
private Optional<Tuple2<File, ClassInfo>> findMatch(DotName fqName) {
return (baseIndex == null ? Stream.<Optional<Tuple2<File, ClassInfo>>>empty()
: Arrays.stream(
baseIndex)
.filter(
jandexIndex -> jandexIndex != null)
.map(jandexIndex -> jandexIndex.findMatch(fqName))).filter(o -> o.isPresent())
.findFirst()
// If not found look at indices owned by this
// JandexIndex instance
.orElseGet(() -> streamOfIndices()
.map(e -> {
IndexView view = e.getT2();
ClassInfo info = view.getClassByName(fqName);
return Tuples.of(e.getT1(), Optional.ofNullable(info));
// return Tuples.of(e.getT1(), Optional.ofNullable(e.getT2().getClassByName(fqName)));
})
.filter(t -> t.getT2().isPresent())
.map(e -> Tuples.of(e.getT1(), e.getT2().get())).findFirst());
}
public Optional<File> findClasspathResourceForType(String fqName) {
Optional<Tuple2<File, ClassInfo>> match = findMatch(DotName.createSimple(fqName));
return Optional.ofNullable(match.isPresent() ? match.get().getT1() : null);
}
private Stream<Tuple2<File, IndexView>> streamOfIndices() {
return index.entrySet().parallelStream().map(e -> Tuples.of(e.getKey(), e.getValue().get()))
.filter(t -> t.getT2().isPresent()).map(t -> Tuples.of(t.getT1(), t.getT2().get()));
}
private Stream<Tuple3<String, File, ClassInfo>> getKnownTypesStream(File file) {
Optional<IndexView> indexView = index.get(file).get();
if (indexView.isPresent()) {
return indexView.get().getKnownClasses().parallelStream()
.map(info -> Tuples.of(info.name().toString(), file, info));
private List<Tuple2<IJavaModuleData, ClassInfo>> getKnownTypeTuples(ModuleJandexIndex module) {
ImmutableList.Builder<Tuple2<IJavaModuleData, ClassInfo>> builder = ImmutableList.builder();
IndexView indexView = module.getIndex().get();
if (indexView != null) {
Collection<ClassInfo> knownClasses = indexView.getKnownClasses();
if (knownClasses != null) {
for (ClassInfo info : knownClasses) {
builder.add(Tuples.of(module, info));
}
}
}
return Stream.empty();
return builder.build();
}
private final Stream<String> getKnownPackages(File file) {
Optional<IndexView> indexView = index.get(file).get();
if (indexView.isPresent()) {
return indexView.get().getKnownClasses().parallelStream().map(info -> {
String name = info.name().toString();
return name.substring(0, name.lastIndexOf('.'));
}).distinct();
private List<Tuple2<IJavaModuleData, ClassInfo>> getAllKnownSubclasses(ModuleJandexIndex module, DotName name, boolean isInterface) {
ImmutableList.Builder<Tuple2<IJavaModuleData, ClassInfo>> builder = ImmutableList.builder();
IndexView indexView = module.getIndex().get();
if (indexView != null) {
Collection<ClassInfo> subTypes = isInterface ? indexView.getAllKnownImplementors(name) : indexView.getAllKnownSubclasses(name);
if (subTypes != null) {
for (ClassInfo info : subTypes) {
builder.add(Tuples.of(module, info));
}
}
}
return Stream.empty();
return builder.build();
}
Flux<Tuple3<File, ClassInfo, Double>> fuzzySearchTypes(String searchTerm) {
Flux<Tuple3<File, ClassInfo, Double>> flux = Flux.fromIterable(knownTypes.values()).publishOn(Schedulers.parallel())
.flatMap(s -> Flux.fromIterable(s.get()))
.map(t -> Tuples.of(t.getT2(), t.getT3(), FuzzyMatcher.matchScore(searchTerm, t.getT1())))
.filter(t -> t.getT3() != 0.0);
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux,
Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm)));
}
Flux<Tuple3<IJavaModuleData, ClassInfo, Double>> fuzzySearchTypes(String searchTerm) {
Flux<Tuple3<IJavaModuleData, ClassInfo, Double>> flux = Flux.fromIterable(modules).publishOn(Schedulers.parallel())
.flatMap(m -> Flux.fromIterable(getKnownTypeTuples(m)))
.map(t -> Tuples.of(t.getT1(), t.getT2(), FuzzyMatcher.matchScore(searchTerm, t.getT2().name().toString())))
.filter(t -> t.getT3() != 0.0);
return flux;
}
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm) {
Flux<Tuple2<String, Double>> flux = Flux.fromIterable(knownPackages.values()).publishOn(Schedulers.parallel())
.flatMap(s -> Flux.fromIterable(s.get()))
.map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg))).filter(t -> t.getT2() != 0.0);
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchPackages(searchTerm)));
}
Flux<Tuple2<String, Double>> flux = Flux.fromIterable(modules).publishOn(Schedulers.parallel())
.flatMap(m -> Flux.fromIterable(getKnownPackages(m)))
.map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg)))
.filter(t -> t.getT2() != 0.0);
return flux;
}
Flux<Tuple2<File, ClassInfo>> allSubtypesOf(DotName name, boolean isInterface) {
Flux<Tuple2<File, ClassInfo>> flux = Flux.fromIterable(index.keySet()).publishOn(Schedulers.parallel()).flatMap(file -> {
Optional<IndexView> optional = index.get(file).get();
if (optional.isPresent()) {
return Flux
.fromIterable(isInterface ? optional.get().getAllKnownImplementors(name)
: optional.get().getAllKnownSubclasses(name))
.publishOn(Schedulers.parallel()).map(info -> Tuples.of(file, info));
} else {
return Flux.empty();
}
});
if (baseIndex == null) {
return flux;
} else {
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.allSubtypesOf(name, isInterface)));
}
Flux<Tuple2<IJavaModuleData, ClassInfo>> allSubtypesOf(DotName name, boolean isInterface) {
Flux<Tuple2<IJavaModuleData, ClassInfo>> flux = Flux.fromIterable(modules).publishOn(Schedulers.parallel())
.flatMap(module -> Flux.fromIterable(getAllKnownSubclasses(module, name, isInterface)));
return flux;
}
}

View File

@@ -0,0 +1,223 @@
/*******************************************************************************
* 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.commons.jandex;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Iterator;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.IndexWriter;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.JarIndexer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
public class IndexRoutines {
private static final Logger log = LoggerFactory.getLogger(IndexRoutines.class);
private static final URI JRT_URI = URI.create("jrt:/");
static ImmutableList<ModuleJandexIndex> fromClasspathBinaryEntry(File file, File indexFile) {
ImmutableList.Builder<ModuleJandexIndex> builder = ImmutableList.builder();
if (file != null) {
if (file.isFile()) {
if (file.getName().endsWith("jrt-fs.jar")) {
builder.addAll(IndexRoutines.fromJrtFs(file, indexFile));
} else if (file.getName().endsWith(".jar")) {
builder.add(IndexRoutines.fromJar(file, indexFile));
}
} else if (file.isDirectory()) {
builder.add(IndexRoutines.fromFolder(file));
}
}
return builder.build();
}
static ImmutableList<ModuleJandexIndex> fromCPE(CPE cpe, File indexFile) {
File binaryLocation = IClasspathUtil.binaryLocation(cpe);
if (cpe.isSystem()) {
return JandexSystemLibsIndex.getInstance().index(binaryLocation.toPath());
} else {
return IndexRoutines.fromClasspathBinaryEntry(binaryLocation, indexFile);
}
}
private static ModuleJandexIndex fromJar(File file, File indexFile) {
return new ModuleJandexIndex(file, null, Suppliers.memoize(() -> indexJar(file, indexFile)));
}
private static ModuleJandexIndex fromFolder(File folder) {
return new ModuleJandexIndex(folder, null, Suppliers.memoize(() -> indexFolder(folder)));
}
private static ModuleJandexIndex fromModule(File container, Path modulePath, File indexFolder) {
String module = modulePath.getFileName().toString();
File indexFile = new File(indexFolder, module + ".jdx");
return new ModuleJandexIndex(container, module, Suppliers.memoize(() -> indexModule(modulePath, indexFile)));
}
private static ImmutableList<ModuleJandexIndex> fromJrtFs(File jrtFsJar, File indexFolder) {
// little hack for backwards compatibility
if (indexFolder.isFile()) {
indexFolder.delete();
}
ImmutableList.Builder<ModuleJandexIndex> builder = ImmutableList.builder();
String javaVersion = System.getProperty("java.version"); //$NON-NLS-1$
FileSystem fs = null;
Path jdkHome = jrtFsJar.toPath().getParent().getParent();
try {
if (javaVersion != null && javaVersion.startsWith("1.8")) { //$NON-NLS-1$
URLClassLoader loader = new URLClassLoader(new URL[] { jrtFsJar.toURI().toURL() });
HashMap<String, ?> env = new HashMap<>();
fs = FileSystems.newFileSystem(JRT_URI, env, loader);
} else {
HashMap<String, String> env = new HashMap<>();
env.put("java.home", jdkHome.toString()); //$NON-NLS-1$
fs = FileSystems.newFileSystem(JRT_URI, env);
}
if (fs != null) {
Files.list(fs.getPath("/modules")).filter(Files::isDirectory).forEach(path -> builder.add(fromModule(jrtFsJar, path, indexFolder)));
// builder.add(fromModule(jrtFsJar, fs.getPath("modules", "java.base"), indexFolder));
}
} catch (IOException e) {
log.error("", e);
}
return builder.build();
}
private static IndexView indexModule(Path modulePath, File indexFile) {
return createOrLoadIndex(indexFile, () -> createModuleIndex(modulePath, indexFile));
}
private static IndexView createModuleIndex(Path modulePath, File indexFile) {
FileOutputStream out = null;
try {
out = new FileOutputStream(indexFile);
Indexer indexer = new Indexer();
Files.walk(modulePath).forEach(entry -> {
if (entry.getFileName().toString().endsWith(".class")) {
try {
final InputStream stream = Files.newInputStream(entry);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
log.debug("", e);
}
}
});
IndexWriter writer = new IndexWriter(out);
Index index = indexer.complete();
writer.write(index);
return index;
} catch (IOException e) {
log.error("", e);
} finally {
if (out != null) {
try {
out.close();
} catch (Exception ignore) {
}
}
}
return null;
}
private static IndexView indexFolder(File folder) {
Indexer indexer = new Indexer();
for (Iterator<File> itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder)
.iterator(); itr.hasNext();) {
File file = itr.next();
if (file.isFile() && file.getName().endsWith(".class")) {
try {
final InputStream stream = new FileInputStream(file);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
log.error("Failed to index file " + file, e);
}
}
}
return indexer.complete();
}
private static IndexView indexJar(File file, File indexFile) {
return createOrLoadIndex(indexFile, () -> createJarIndex(indexFile, file));
}
private static IndexView createJarIndex(File indexFile, File jarFile) {
try {
return JarIndexer.createJarIndex(jarFile, new Indexer(), indexFile, false, false,
false, System.out, System.err).getIndex();
} catch (Exception e) {
log.error("Failed to index '" + jarFile + "'", e);
return null;
}
}
private static IndexView createOrLoadIndex(File indexFile, Supplier<IndexView> indexCreator) {
if (indexFile != null) {
if (!indexFile.getParentFile().exists()) {
indexFile.getParentFile().mkdirs();
}
if (!indexFile.exists()) {
return indexCreator.get();
} else {
try {
return new IndexReader(new FileInputStream(indexFile)).read();
} catch (IOException e) {
log.error("Failed to read index file '" + indexFile + "'. Creating new index file.", e);
if (indexFile.delete()) {
return createOrLoadIndex(indexFile, indexCreator);
} else {
log.error("Failed to read index file '" + indexFile);
}
}
}
}
return null;
}
}

View File

@@ -15,7 +15,6 @@ import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -31,6 +30,7 @@ import org.springframework.ide.vscode.commons.jandex.JandexIndex.JavadocProvider
import org.springframework.ide.vscode.commons.java.ClasspathIndex;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
@@ -77,13 +77,7 @@ public final class JandexClasspath implements ClasspathIndex {
protected JandexIndex createIndex() {
log.info("Creating JandexIndex for "+classpath.getName());
attachFolderListeners();
Collection<File> classpathEntries = ImmutableList.of();
try {
classpathEntries = IClasspathUtil.getBinaryRoots(classpath, (cpe) -> !cpe.isSystem());
} catch (Exception e) {
log.error("Cannot obtain binary root from classpath entries for " + classpath.getName(), e);
}
return new JandexIndex(classpathEntries, jarFile -> findIndexFile(jarFile), javadocProviderFactory, getBaseIndices());
return new JandexIndex(classpath, jarFile -> findIndexFile(jarFile), javadocProviderFactory);
}
private Disposable.Composite subscriptions = Disposables.composite();
@@ -115,10 +109,6 @@ public final class JandexClasspath implements ClasspathIndex {
return cpe == null ? Optional.empty() : Optional.ofNullable(cpe.getSourceContainerUrl());
}
protected BasicJandexIndex[] getBaseIndices() {
return JandexSystemLibsIndex.getInstance().fromJars(IClasspathUtil.getBinaryRoots(classpath, CPE::isSystem));
}
@Override
public IType findType(String fqName) {
return javaIndex.get().findType(fqName);
@@ -152,7 +142,7 @@ public final class JandexClasspath implements ClasspathIndex {
}
@Override
public Optional<File> findClasspathResourceContainer(String fqName) {
public IJavaModuleData findClasspathResourceContainer(String fqName) {
return javaIndex.get().findClasspathResourceForType(fqName);
}

View File

@@ -12,7 +12,6 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
@@ -20,6 +19,8 @@ import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.IType;
@@ -51,21 +52,22 @@ public class JandexIndex extends BasicJandexIndex {
return javadocProviderFactory;
}
public JandexIndex(Collection<File> classpathEntries, IndexFileFinder indexFileFinder,
JavadocProviderFactory javadocProviderFactory, BasicJandexIndex... baseIndex) {
super(classpathEntries, indexFileFinder, baseIndex);
public JandexIndex(IClasspath classpath, IndexFileFinder indexFileFinder,
JavadocProviderFactory javadocProviderFactory) {
super(classpath, indexFileFinder);
this.javadocProviderFactory = javadocProviderFactory;
}
public IType findType(String fqName) {
return createType(getClassByName(DotName.createSimple(fqName)));
Tuple2<IJavaModuleData, ClassInfo> result = getClassByName(DotName.createSimple(fqName));
return result == null ? null : createType(result);
}
private IType createType(Tuple2<File, ClassInfo> match) {
private IType createType(Tuple2<IJavaModuleData, ClassInfo> match) {
if (match == null) {
return null;
}
File classpathResource = match.getT1();
File classpathResource = match.getT1().getContainer();
IJavadocProvider javadocProvider = null;
try {
javadocProvider = javadocProvidersCache.get(classpathResource, () -> {

View File

@@ -11,29 +11,22 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.io.IOException;
import java.nio.channels.IllegalSelectorException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.io.BaseEncoding;
/**
@@ -44,67 +37,34 @@ import com.google.common.io.BaseEncoding;
*/
public class JandexSystemLibsIndex {
private static final String DEFAULT_JAVA_VERSION = "1.8.0";
private static final Pattern JAVA_VERSION_PATTERN = Pattern.compile("^java version \"(.*)\"$");
// private static final String DEFAULT_JAVA_VERSION = "1.8.0";
//
// private static final Pattern JAVA_VERSION_PATTERN = Pattern.compile("^java version \"(.*)\"$");
public static final Logger log = LoggerFactory.getLogger(JandexSystemLibsIndex.class);
private static final Supplier<JandexSystemLibsIndex> INSTANCE = Suppliers.memoize(() -> new JandexSystemLibsIndex());
private Cache<Path, BasicJandexIndex> cache;
private LoadingCache<Path, ImmutableList<ModuleJandexIndex>> indexCache;
private JandexSystemLibsIndex() {
this.cache = CacheBuilder.newBuilder().build(new CacheLoader<Path, BasicJandexIndex>() {
this.indexCache = CacheBuilder.newBuilder().build(new CacheLoader<Path, ImmutableList<ModuleJandexIndex>>() {
@Override
public BasicJandexIndex load(Path key) throws Exception {
return createIndex(key);
public ImmutableList<ModuleJandexIndex> load(Path path) throws Exception {
File file = path.toFile();
return IndexRoutines.fromClasspathBinaryEntry(file, findIndexFile(path));
}
});
}
/**
* Retrieves or lazily creates Jandex Index for a folder containing system lib jars
* @param path the path containing jars
* @return Jandex Index of the jars contained in the folder
*/
public BasicJandexIndex index(Path path) {
try {
return cache.get(path, () -> createIndex(path));
} catch (ExecutionException e) {
log.error("Failed to detrmine Jandex index for " + path, e);
return null;
}
}
/**
* Retrieves Jandex Indexes appropriate for systm lib jars. One Jandex Index may contain all sys lib jars.
* @param jars system lib jars
* @return Jandex Indexs for jars
*/
public BasicJandexIndex[] fromJars(Collection<File> jars) {
return jars.stream().map(jar -> jar.toPath().getParent()).distinct().map(folder -> index(folder)).filter(Objects::nonNull).toArray(BasicJandexIndex[]::new);
}
public static JandexSystemLibsIndex getInstance() {
return INSTANCE.get();
}
private BasicJandexIndex createIndex(Path path) {
List<File> jars = Collections.emptyList();
try {
jars = Files.list(path).filter(p -> p.getFileName().toString().endsWith(".jar") && Files.isRegularFile(p)).map(p -> p.toFile()).collect(Collectors.toList());
} catch (IOException e) {
// Shouldn't happen - there should at least be one jar file
log.error("Cannot list files in folder " + path, e);
}
return new BasicJandexIndex(jars, jarFile -> findIndexFile(jarFile));
}
private File findIndexFile(File jarFile) {
return Paths.get(System.getProperty("user.home"), ".sts4-jandex", folderNameforPath(jarFile.getParentFile().toString()), jarFile.getName() + ".jdx").toFile();
private File findIndexFile(Path path) {
return Paths.get(System.getProperty("user.home"), ".sts4-jandex", folderNameforPath(path.getParent().toString()), path.getFileName() + ".jdx").toFile();
}
private static String folderNameforPath(String path) {
@@ -120,6 +80,15 @@ public class JandexSystemLibsIndex {
}
}
public ImmutableList<ModuleJandexIndex> index(Path path) {
try {
return indexCache.get(path);
} catch (ExecutionException e) {
log.error("", e);
return null;
}
}
// private static String getJavaVersion(Path path) {
// // Find valid /bin folder
// for (; path != null && !(Files.isDirectory(path.resolve("bin")) && Files.isReadable(path.resolve("bin"))); path = path.getParent());

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* 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.commons.jandex;
import java.io.File;
import org.jboss.jandex.IndexView;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import com.google.common.base.Supplier;
class ModuleJandexIndex implements IJavaModuleData {
private Supplier<IndexView> index;
private File container;
private String module;
public ModuleJandexIndex(File container, String module, Supplier<IndexView> index) {
this.container = container;
this.module = module;
this.index = index;
}
public Supplier<IndexView> getIndex() {
return index;
}
@Override
public File getContainer() {
return container;
}
@Override
public String getModule() {
return module;
}
@Override
public String toString() {
return "ModuleJandexIndex [container=" + container + ", module=" + module + "]";
}
}

View File

@@ -11,7 +11,6 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -25,6 +24,7 @@ import org.jboss.jandex.Type;
import org.springframework.ide.vscode.commons.java.Flags;
import org.springframework.ide.vscode.commons.java.IAnnotation;
import org.springframework.ide.vscode.commons.java.IField;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaType;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.IMethod;
@@ -36,9 +36,9 @@ class TypeImpl implements IType {
private ClassInfo info;
private JandexIndex index;
private IJavadocProvider javadocProvider;
private File classpathContainer;
private IJavaModuleData classpathContainer;
TypeImpl(JandexIndex index, File classpathContainer, ClassInfo info, IJavadocProvider javadocProvider) {
TypeImpl(JandexIndex index, IJavaModuleData classpathContainer, ClassInfo info, IJavadocProvider javadocProvider) {
this.info = info;
this.index = index;
this.classpathContainer = classpathContainer;
@@ -154,7 +154,7 @@ class TypeImpl implements IType {
}
@Override
public File classpathContainer() {
public IJavaModuleData classpathContainer() {
return classpathContainer;
}

View File

@@ -13,8 +13,6 @@ package org.springframework.ide.vscode.commons.jandex;
import static org.springframework.ide.vscode.commons.util.Assert.isNotNull;
import java.io.File;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
@@ -26,6 +24,7 @@ import org.jboss.jandex.Type;
import org.jboss.jandex.Type.Kind;
import org.springframework.ide.vscode.commons.java.IAnnotation;
import org.springframework.ide.vscode.commons.java.IField;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaType;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.IMemberValuePair;
@@ -36,11 +35,11 @@ import org.springframework.ide.vscode.commons.java.IVoidType;
public class Wrappers {
public static IType wrap(JandexIndex index, File classpathContainer, ClassInfo info, IJavadocProvider javadocProvider) {
public static IType wrap(JandexIndex index, IJavaModuleData moduleContainer, ClassInfo info, IJavadocProvider javadocProvider) {
if (info == null) {
return null;
}
return new TypeImpl(index, classpathContainer, info, javadocProvider);
return new TypeImpl(index, moduleContainer, info, javadocProvider);
}
public static IField wrap(IType declaringType, FieldInfo field, IJavadocProvider javadocProvider) {

View File

@@ -11,8 +11,6 @@
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;
@@ -38,38 +36,4 @@ public class BootProjectUtil {
String name = cpe.getName();
return name.endsWith(".jar") && name.startsWith("spring-boot");
}
public static Path javaHomeFromLibJar(Path libJar) {
Path root = libJar.getRoot();
for (Path home = libJar; !root.equals(home.getParent()); home = home.getParent()) {
Path bin = home.resolve("bin");
Path lib = home.resolve("lib");
Path include = home.resolve("include");
Path man = home.resolve("man");
if (Files.isDirectory(bin) && Files.isDirectory(lib) && Files.isDirectory(include) && Files.isDirectory(man)) {
return home;
}
}
return null;
}
public static Path jreSources(Path libJar) {
Path home = javaHomeFromLibJar(libJar);
if (home != null) {
Path sources = sourceZip(home);
if (sources == null) {
sources = sourceZip(home.resolve("lib"));
}
return sources;
}
return null;
}
private static Path sourceZip(Path containerFolder) {
Path sourcesZip = containerFolder.resolve("src.zip");
if (Files.exists(sourcesZip)) {
return sourcesZip;
}
return null;
}
}

View File

@@ -28,7 +28,7 @@ public interface ClasspathIndex extends Disposable {
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
Flux<IType> allSubtypesOf(IType type);
Flux<IType> allSuperTypesOf(IType type);
Optional<File> findClasspathResourceContainer(String fqName);
IJavaModuleData findClasspathResourceContainer(String fqName);
//Maybe the stuff below is another interface? Something that provides operations
// on classpaths?

View File

@@ -68,7 +68,7 @@ public class IClasspathUtil {
return Objects.equals(canonicalFile, classpathEntryFile);
}
private static File binaryLocation(CPE cpe) {
public static File binaryLocation(CPE cpe) {
switch (cpe.getKind()) {
case Classpath.ENTRY_KIND_BINARY:
return canonicalFile(cpe.getPath());

View File

@@ -10,15 +10,13 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.io.File;
public interface IField extends IMember {
boolean isEnumConstant();
IJavaType type();
@Override
default File classpathContainer() {
default IJavaModuleData classpathContainer() {
return getDeclaringType().classpathContainer();
}

View File

@@ -0,0 +1,21 @@
/*******************************************************************************
* 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.commons.java;
import java.io.File;
public interface IJavaModuleData {
File getContainer();
String getModule();
}

View File

@@ -57,7 +57,7 @@ public interface IJavaProject {
return getIndex().getClasspathResources();
}
default Optional<File> findClasspathResourceContainer(String fqName) {
default IJavaModuleData findClasspathResourceContainer(String fqName) {
return getIndex().findClasspathResourceContainer(fqName);
}

View File

@@ -11,8 +11,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.io.File;
public interface IMember extends IJavaElement, IAnnotatable {
/**
@@ -45,7 +43,7 @@ public interface IMember extends IJavaElement, IAnnotatable {
*/
IType getDeclaringType();
File classpathContainer();
IJavaModuleData classpathContainer();
String signature();

View File

@@ -12,7 +12,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.io.File;
import java.util.stream.Stream;
public interface IMethod extends IMember {
@@ -68,7 +67,7 @@ public interface IMethod extends IMember {
boolean isConstructor();
@Override
default File classpathContainer() {
default IJavaModuleData classpathContainer() {
return getDeclaringType().classpathContainer();
}

View File

@@ -8,7 +8,7 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.java;
package org.springframework.ide.vscode.commons.java;
import java.io.File;
import java.nio.file.Files;
@@ -82,8 +82,45 @@ public class JavaUtils {
return null;
}
} else {
return tokenized[0];
String version = tokenized[0];
int idx = version.indexOf('+');
return idx >= 0 ? version.substring(0, idx) : version;
}
}
public static Path javaHomeFromLibJar(Path libJar) {
Path root = libJar.getRoot();
for (Path home = libJar; !root.equals(home.getParent()); home = home.getParent()) {
Path bin = home.resolve("bin");
Path lib = home.resolve("lib");
Path include = home.resolve("include");
Path man = home.resolve("man");
Path legal = home.resolve("legal");
if (Files.isDirectory(bin) && Files.isDirectory(lib) && Files.isDirectory(include) && (Files.isDirectory(man) || Files.isDirectory(legal))) {
return home;
}
}
return null;
}
public static Path jreSources(Path libJar) {
Path home = javaHomeFromLibJar(libJar);
if (home != null) {
Path sources = JavaUtils.sourceZip(home);
if (sources == null) {
sources = JavaUtils.sourceZip(home.resolve("lib"));
}
return sources;
}
return null;
}
private static Path sourceZip(Path containerFolder) {
Path sourcesZip = containerFolder.resolve("src.zip");
if (Files.exists(sourcesZip)) {
return sourcesZip;
}
return null;
}
}

View File

@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.commons.javadoc;
import java.net.URL;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
public class JavaDocProviders {
@@ -26,7 +25,7 @@ public class JavaDocProviders {
? TypeUrlProviderFromContainerUrl.JAR_JAVADOC_URL_PROVIDER
: TypeUrlProviderFromContainerUrl.JAVADOC_FOLDER_URL_SUPPLIER;
return new HtmlJavadocProvider(
type -> urlProvider.url(classpathEntry.getJavadocContainerUrl(), type.getFullyQualifiedName())
type -> urlProvider.url(classpathEntry.getJavadocContainerUrl(), type.getFullyQualifiedName(), type.classpathContainer().getModule())
);
}
return null;

View File

@@ -16,29 +16,34 @@ import java.nio.file.Paths;
@FunctionalInterface
public interface TypeUrlProviderFromContainerUrl {
static String extractTopLevelType(String fqName) {
int innerTypeIdx = fqName.indexOf('$');
return innerTypeIdx > 0 ? fqName.substring(0, innerTypeIdx) : fqName;
}
public static final TypeUrlProviderFromContainerUrl JAR_SOURCE_URL_PROVIDER = (jarSourceUrl, fqName) -> {
public static final TypeUrlProviderFromContainerUrl JAR_SOURCE_URL_PROVIDER = (jarSourceUrl, fqName, module) -> {
StringBuilder urlStr = new StringBuilder();
urlStr.append("jar:");
urlStr.append(jarSourceUrl);
urlStr.append("!");
urlStr.append('/');
if (module != null) {
urlStr.append(module);
urlStr.append('/');
}
urlStr.append(extractTopLevelType(fqName).replaceAll("\\.", "/"));
urlStr.append(".java");
return new URL(urlStr.toString());
};
public static final TypeUrlProviderFromContainerUrl SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
public static final TypeUrlProviderFromContainerUrl SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName, module) -> {
// Unclear how to deal with modules and source folders at the moment hence module is ignored
return Paths.get(sourceContainerUrl.toURI()).resolve(extractTopLevelType(fqName).replaceAll("\\.", "/") + ".java").toUri().toURL();
};
public static final TypeUrlProviderFromContainerUrl JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, fqName) -> {
public static final TypeUrlProviderFromContainerUrl JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, fqName, module) -> {
StringBuilder urlStr = new StringBuilder();
urlStr.append("jar:");
urlStr.append(javadocContainerUrl);
@@ -50,8 +55,8 @@ public interface TypeUrlProviderFromContainerUrl {
return new URL(urlStr.toString());
};
public static final TypeUrlProviderFromContainerUrl JAVADOC_FOLDER_URL_SUPPLIER = (javadocContainerUrl, fqName) -> {
public static final TypeUrlProviderFromContainerUrl JAVADOC_FOLDER_URL_SUPPLIER = (javadocContainerUrl, fqName, module) -> {
String urlStr = javadocContainerUrl.toString();
StringBuilder sb = new StringBuilder(urlStr);
if (!urlStr.endsWith("/")) {
@@ -61,7 +66,7 @@ public interface TypeUrlProviderFromContainerUrl {
sb.append(fqName.replaceAll("\\.", "/").replaceAll("\\$", ".") + ".html");
return new URL(sb.toString());
};
URL url(URL containerUrl, String fqName) throws Exception;
URL url(URL containerUrl, String fqName, String module) throws Exception;
}

View File

@@ -54,7 +54,7 @@ import org.eclipse.aether.util.graph.visitor.CloningDependencyVisitor;
import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.languageserver.java.JavaUtils;
import org.springframework.ide.vscode.commons.java.JavaUtils;
/**
* Maven Core functionality

View File

@@ -22,9 +22,9 @@ 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.java.JavaUtils;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.maven.MavenException;
@@ -92,7 +92,7 @@ public class MavenProjectClasspath implements IClasspath {
cpe.setSystem(true);
entries.add(cpe);
// Add at the end, not critical if throws exception, but the CPE needs to be around regardless if the below throws
Path sources = BootProjectUtil.jreSources(path);
Path sources = JavaUtils.jreSources(path);
if (sources != null) {
cpe.setSourceContainerUrl(sources.toUri().toURL());
}

View File

@@ -20,6 +20,7 @@ import java.nio.file.Paths;
import java.util.stream.Stream;
import org.junit.Assume;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.ide.vscode.commons.java.IField;
import org.springframework.ide.vscode.commons.java.IMethod;
@@ -33,6 +34,8 @@ import org.springframework.ide.vscode.commons.util.FileObserver;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@Ignore
//@EnabledOnJre(JAVA_8)
public class HtmlJavadocTest {
private static FileObserver fileObserver = new BasicFileObserver();

View File

@@ -17,20 +17,19 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.ide.vscode.languageserver.testharness.ClasspathTestUtil.getOutputFolder;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import org.springframework.ide.vscode.commons.java.Flags;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IMethod;
import org.springframework.ide.vscode.commons.java.IPrimitiveType;
import org.springframework.ide.vscode.commons.java.IType;
@@ -103,6 +102,15 @@ public class JavaIndexTest {
assertNotNull(type);
}
// @Test
// public void findStringStripMethodinJDK() throws Exception {
// MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
// IType type = project.findType("java.lang.String");
// assertNotNull(type);
// IMethod method = type.getMethod("strip", Stream.empty());
// assertNotNull(method);
// }
@Test
public void findClassInOutputFolder() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
@@ -154,18 +162,18 @@ public class JavaIndexTest {
@Test
public void testFindJarResource() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
Optional<File> jar = project.findClasspathResourceContainer("org.springframework.boot.autoconfigure.SpringBootApplication");
assertTrue(jar.isPresent());
assertEquals("spring-boot-autoconfigure-1.4.1.RELEASE.jar", jar.get().getName());
IJavaModuleData module = project.findClasspathResourceContainer("org.springframework.boot.autoconfigure.SpringBootApplication");
assertNotNull(module);
assertEquals("spring-boot-autoconfigure-1.4.1.RELEASE.jar", module.getContainer().getName());
}
@Test
public void testFindJavaResource() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
Optional<File> file = project.findClasspathResourceContainer("hello.GreetingController");
assertTrue(file.isPresent());
assertTrue(file.get().exists());
assertEquals(getOutputFolder(project).toString(), file.get().toString());
IJavaModuleData module = project.findClasspathResourceContainer("hello.GreetingController");
assertNotNull(module);
assertTrue(module.getContainer().exists());
assertEquals(getOutputFolder(project).toString(), module.getContainer().toString());
}
@Test

View File

@@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
import org.springframework.ide.vscode.commons.util.text.Region;
@@ -50,13 +51,13 @@ public abstract class AbstractSourceLinks implements SourceLinks {
@Override
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
Optional<File> classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
if (classpathResource.isPresent()) {
File file = classpathResource.get();
IJavaModuleData classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
if (classpathResource != null) {
File file = classpathResource.getContainer();
if (file.isDirectory()) {
return javaSourceLinkUrl(project, fqName, file);
return javaSourceLinkUrl(project, fqName, classpathResource);
} else {
return jarSourceLinkUrl(project, fqName, file);
return jarSourceLinkUrl(project, fqName, classpathResource);
}
}
return Optional.empty();
@@ -74,7 +75,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
private Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, File containerFolder) {
private Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, IJavaModuleData folderModuleData) {
IClasspath classpath = project.getClasspath();
return SourceLinks.sourceFromSourceFolder(fqName, classpath)
.map(sourcePath -> javaSourceLinkUrl(project, sourcePath, fqName));
@@ -95,19 +96,19 @@ public abstract class AbstractSourceLinks implements SourceLinks {
return cuCache == null ? Optional.empty() : cuCache.withCompilationUnit(project, uri, compilationUnit -> Optional.ofNullable(compilationUnit));
}
abstract protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile);
abstract protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, IJavaModuleData jarModuleData);
private Optional<String> jarSourceLinkUrl(IJavaProject project, String fqName, File jarFile) {
return jarLinkUrl(project, fqName, jarFile).map(sourceUrl -> {
Optional<String> positionLink = findCUForFQNameFromJar(project, jarFile, fqName).map(cu -> positionLink(cu, fqName));
private Optional<String> jarSourceLinkUrl(IJavaProject project, String fqName, IJavaModuleData jarModuleData) {
return jarLinkUrl(project, fqName, jarModuleData).map(sourceUrl -> {
Optional<String> positionLink = findCUForFQNameFromJar(project, jarModuleData, fqName).map(cu -> positionLink(cu, fqName));
return positionLink.isPresent() ? sourceUrl + positionLink.get() : sourceUrl;
});
}
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, File jarFile, String fqName) {
return project.sourceContainer(jarFile).map(url -> {
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, IJavaModuleData jarModuleData, String fqName) {
return project.sourceContainer(jarModuleData.getContainer()).map(url -> {
try {
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(url, fqName);
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(url, fqName, jarModuleData.getModule());
} catch (Exception e) {
log.warn("Failed to determine source URL from url={} fqName={}", url, fqName, e);
return null;

View File

@@ -10,7 +10,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.links;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Path;
@@ -20,6 +19,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.text.Region;
@@ -69,7 +69,7 @@ public class AtomSourceLinks extends AbstractSourceLinks {
}
@Override
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile) {
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, IJavaModuleData jarModuleData) {
// JAR URLs are not supported yet
return Optional.empty();
}

View File

@@ -13,11 +13,11 @@ 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.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
public class JdtJavaDocumentUriProvider implements JavaDocumentUriProvider {
@@ -30,9 +30,9 @@ public class JdtJavaDocumentUriProvider implements JavaDocumentUriProvider {
}
public static URI uri(IJavaProject project, String fqName) {
Optional<File> classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
if (classpathResource.isPresent()) {
File file = classpathResource.get();
IJavaModuleData classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
if (classpathResource != null) {
File file = classpathResource.getContainer();
if (file.isDirectory()) {
IClasspath classpath = project.getClasspath();
return SourceLinks.sourceFromSourceFolder(fqName, classpath).map(path -> path.toUri()).orElse(null);

View File

@@ -10,7 +10,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.links;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
@@ -23,6 +22,7 @@ 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.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
@@ -54,7 +54,7 @@ public interface SourceLinks {
})
.map(url -> {
try {
return TypeUrlProviderFromContainerUrl.SOURCE_FOLDER_URL_SUPPLIER.url(url, fqName);
return TypeUrlProviderFromContainerUrl.SOURCE_FOLDER_URL_SUPPLIER.url(url, fqName, /* module */ null);
} catch (Exception e) {
log.warn("Failed to determine source URL from url={} fqName=", url, fqName, e);
return null;
@@ -73,31 +73,30 @@ public interface SourceLinks {
}
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 -> {
IJavaModuleData classpathResourceContainer = project.findClasspathResourceContainer(fqName);
if (classpathResourceContainer != null) {
Optional<URL> url = project.sourceContainer(classpathResourceContainer.getContainer()).map(file -> {
try {
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(file, fqName, classpathResourceContainer.getModule());
} catch (Exception e) {
throw new IllegalStateException(e);
}
});
if (!url.isPresent()) {
// Try Source folder
url = sourceFromSourceFolder(fqName, project.getClasspath()).map(p -> {
try {
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(file, fqName);
} catch (Exception e) {
return p.toUri().toURL();
} catch (MalformedURLException 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;
}
return url;
return Optional.empty();
}

View File

@@ -10,12 +10,12 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.links;
import java.io.File;
import java.nio.file.Path;
import java.util.Optional;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.text.Region;
@@ -55,7 +55,7 @@ public class VSCodeSourceLinks extends AbstractSourceLinks {
}
@Override
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, File jarFile) {
protected Optional<String> jarLinkUrl(IJavaProject project, String fqName, IJavaModuleData jarModuleData) {
return Optional.ofNullable(JdtJavaDocumentUriProvider.uri(project, fqName)).map(uri -> uri.toString());
}

View File

@@ -39,19 +39,18 @@ import com.google.common.collect.ImmutableSet;
public class LoggerNameProviderTest {
private static final String[] JBOSS_RESULTS = {
"com.fasterxml.jackson.databind.jsonFormatVisitors", //1
// org.jboss is not really a package...
// "org.jboss", //2
"org.jboss.logging", //3
"org.jboss.logging.JBossLogManagerLogger", //4
"org.jboss.logging.JBossLogManagerProvider", //5
"org.jboss.logging.JBossLogRecord", //6
"org.springframework.instrument.classloading.jboss", //7
"org.springframework.instrument.classloading.jboss.JBossClassLoaderAdapter", //8
"org.springframework.instrument.classloading.jboss.JBossLoadTimeWeaver", //9
"org.springframework.instrument.classloading.jboss.JBossMCAdapter", //10
"org.springframework.instrument.classloading.jboss.JBossMCTranslatorAdapter", //11
"org.springframework.instrument.classloading.jboss.JBossModulesAdapter" //12
// "org.jboss", //1
"org.jboss.logging", //2
"org.jboss.logging.JBossLogManagerLogger", //3
"org.jboss.logging.JBossLogManagerProvider", //4
"org.jboss.logging.JBossLogRecord", //5
"org.springframework.instrument.classloading.jboss", //6
"org.springframework.instrument.classloading.jboss.JBossClassLoaderAdapter", //7
"org.springframework.instrument.classloading.jboss.JBossLoadTimeWeaver", //8
"org.springframework.instrument.classloading.jboss.JBossMCAdapter", //9
"org.springframework.instrument.classloading.jboss.JBossMCTranslatorAdapter", //10
"org.springframework.instrument.classloading.jboss.JBossModulesAdapter" //11
};
private ProjectsHarness projects = ProjectsHarness.INSTANCE;