Class Reference content assist for boot application properties and yaml
This commit is contained in:
@@ -128,17 +128,17 @@ public abstract class CachingValueProvider implements ValueProviderStrategy {
|
||||
}
|
||||
}
|
||||
// debug("full search for: "+query);
|
||||
return getValuesAsycn(javaProject, query);
|
||||
return getValuesAsync(javaProject, query);
|
||||
}
|
||||
|
||||
protected abstract Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query);
|
||||
protected abstract Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query);
|
||||
|
||||
private Tuple2<String,String> key(IJavaProject javaProject, String query) {
|
||||
return Tuples.of(javaProject==null?null:javaProject.getElementName(), query);
|
||||
}
|
||||
|
||||
protected <K,V> Cache<K,V> createCache() {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).expireAfterAccess(1, TimeUnit.MINUTES).build();
|
||||
}
|
||||
|
||||
public static void restoreDefaults() {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.springframework.ide.vscode.application.properties.metadata;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||
import org.springframework.ide.vscode.commons.java.Flags;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public class ClassReferenceProvider extends CachingValueProvider {
|
||||
|
||||
/**
|
||||
* Default value for the 'concrete' parameter.
|
||||
*/
|
||||
private static final boolean DEFAULT_CONCRETE = true;
|
||||
|
||||
private static final ClassReferenceProvider UNTARGETTED_INSTANCE = new ClassReferenceProvider(null, DEFAULT_CONCRETE);
|
||||
|
||||
public static final Function<Map<String, Object>, ValueProviderStrategy> FACTORY = applyOn(
|
||||
1, TimeUnit.MINUTES,
|
||||
(params) -> {
|
||||
String target = getTarget(params);
|
||||
Boolean concrete = getConcrete(params);
|
||||
if (target!=null || concrete!=null) {
|
||||
if (concrete==null) {
|
||||
concrete = DEFAULT_CONCRETE;
|
||||
}
|
||||
return new ClassReferenceProvider(target, concrete);
|
||||
}
|
||||
return UNTARGETTED_INSTANCE;
|
||||
}
|
||||
);
|
||||
|
||||
public static <K,V> Function<K,V> applyOn(long duration, TimeUnit unit, Function<K,V> func) {
|
||||
Cache<K,V> cache = CacheBuilder.newBuilder().expireAfterAccess(duration, unit).expireAfterWrite(duration, unit).build();
|
||||
return (k) -> {
|
||||
try {
|
||||
return cache.get(k, () -> func.apply(k));
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String getTarget(Map<String, Object> params) {
|
||||
if (params!=null) {
|
||||
Object obj = params.get("target");
|
||||
if (obj instanceof String) {
|
||||
String target = (String) obj;
|
||||
if (StringUtil.hasText(target)) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isAbstract(IType type) {
|
||||
try {
|
||||
return type.isInterface() || Flags.isAbstract(type.getFlags());
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean getConcrete(Map<String, Object> params) {
|
||||
try {
|
||||
if (params!=null) {
|
||||
Object obj = params.get("concrete");
|
||||
if (obj instanceof String) {
|
||||
String concrete = (String) obj;
|
||||
return Boolean.valueOf(concrete);
|
||||
} else if (obj instanceof Boolean) {
|
||||
return (Boolean) obj;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional, fully qualified name of the 'target' type. Suggested hints should be a subtype of this type.
|
||||
*/
|
||||
private String target;
|
||||
|
||||
/**
|
||||
* Optional parameter, whether only concrete types should be suggested. Default value is true.
|
||||
*/
|
||||
private boolean concrete;
|
||||
|
||||
private ClassReferenceProvider(String target, boolean concrete) {
|
||||
this.target = target;
|
||||
this.concrete = concrete;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
|
||||
IType targetType = target == null || target.isEmpty() ? javaProject.findType("java.lang.Object") : javaProject.findType(target);
|
||||
if (targetType == null) {
|
||||
return Flux.empty();
|
||||
}
|
||||
Set<IType> allSubclasses = javaProject
|
||||
.allSubtypesOf(targetType)
|
||||
.filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t))
|
||||
.collect(Collectors.toSet())
|
||||
.block();
|
||||
if (allSubclasses.isEmpty()) {
|
||||
return Flux.empty();
|
||||
} else {
|
||||
return javaProject
|
||||
.fuzzySearchTypes(query, type -> allSubclasses.contains(type))
|
||||
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
|
||||
.flatMap(l -> Flux.fromIterable(l))
|
||||
.map(t -> StsValueHint.create(t.getT1()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class ResourceHintProvider implements ValueProviderStrategy {
|
||||
|
||||
private static class ClasspathHints extends CachingValueProvider {
|
||||
@Override
|
||||
protected Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query) {
|
||||
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
|
||||
return Flux.fromStream(javaProject.getClasspath().getClasspathResources().distinct().map(StsValueHint::create));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class ValueProviderRegistry {
|
||||
|
||||
protected void initializeDefaults(ValueProviderRegistry r) {
|
||||
// def("logger-name", LoggerNameProvider.FACTORY);
|
||||
// def("class-reference", ClassReferenceProvider.FACTORY);
|
||||
def("class-reference", ClassReferenceProvider.FACTORY);
|
||||
}
|
||||
|
||||
private Map<String, Function<Map<String, Object>, ValueProviderStrategy>> registry = new HashMap<>();
|
||||
|
||||
@@ -51,5 +51,11 @@
|
||||
<version>${roaster.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- Reactor -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>${reactor-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -4,11 +4,14 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
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.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -24,7 +27,9 @@ import org.springframework.ide.vscode.commons.java.IField;
|
||||
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject.TypeFilter;
|
||||
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
@@ -32,17 +37,13 @@ import com.google.common.base.Suppliers;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public class JandexIndex {
|
||||
|
||||
private static class Entry<K, V> {
|
||||
K key;
|
||||
V value;
|
||||
Entry(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface IndexFileFinder {
|
||||
File findIndexFile(File jarFile);
|
||||
@@ -77,10 +78,12 @@ public class JandexIndex {
|
||||
|
||||
};
|
||||
|
||||
private Supplier<List<Entry<File, IndexView>>> index;
|
||||
private Map<File, Supplier<Optional<IndexView>>> index;
|
||||
|
||||
private JavadocProviderFactory javadocProviderFactory;
|
||||
|
||||
private Map<File, Supplier<List<Tuple2<String, IType>>>> knownTypes;
|
||||
|
||||
private Cache<File, IJavadocProvider> javadocProvidersCache = CacheBuilder.newBuilder().build();
|
||||
|
||||
private JandexIndex[] baseIndex;
|
||||
@@ -93,26 +96,25 @@ public class JandexIndex {
|
||||
return javadocProviderFactory;
|
||||
}
|
||||
|
||||
public JandexIndex(Stream<Path> classpathEntries, IndexFileFinder indexFileFinder, JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) {
|
||||
public JandexIndex(Collection<File> classpathEntries, IndexFileFinder indexFileFinder, JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) {
|
||||
this.baseIndex = baseIndex;
|
||||
index = Suppliers.memoize(() -> buildIndex(classpathEntries, indexFileFinder).collect(Collectors.toList()));
|
||||
this.index = new ConcurrentHashMap<>();
|
||||
this.knownTypes = new HashMap<>();
|
||||
this.javadocProviderFactory = javadocProviderFactory;
|
||||
classpathEntries.forEach(file -> {
|
||||
index.put(file, Suppliers.memoize(() -> createIndex(file, indexFileFinder)));
|
||||
knownTypes.put(file, Suppliers.memoize(() -> getKnownTypesStream(file).collect(Collectors.toList())));
|
||||
});
|
||||
}
|
||||
|
||||
private Stream<Entry<File, IndexView>> buildIndex(Stream<Path> classpathEntries, IndexFileFinder indexFileFinder) {
|
||||
return classpathEntries
|
||||
.map(entry -> entry.toFile())
|
||||
.map(file -> {
|
||||
Optional<IndexView> index = Optional.empty();
|
||||
if (file.isFile() && file.getName().endsWith(".jar")) {
|
||||
index = indexJar(file, indexFileFinder);
|
||||
} else if (file.isDirectory()) {
|
||||
index = indexFolder(file);
|
||||
}
|
||||
return new Entry<>(file, index);
|
||||
})
|
||||
.filter(e -> e.value.isPresent())
|
||||
.map(e -> new Entry<>(e.key, e.value.get()));
|
||||
private Optional<IndexView> createIndex(File file, IndexFileFinder indexFileFinder) {
|
||||
if (file.isFile() && file.getName().endsWith(".jar")) {
|
||||
return indexJar(file, indexFileFinder);
|
||||
} else if (file.isDirectory()) {
|
||||
return indexFolder(file);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<IndexView> indexFolder(File folder) {
|
||||
@@ -181,7 +183,7 @@ public class JandexIndex {
|
||||
public IType findType(String fqName) {
|
||||
return getClassByName(DotName.createSimple(fqName));
|
||||
}
|
||||
|
||||
|
||||
IType getClassByName(DotName fqName) {
|
||||
// First look for type in the base index array
|
||||
return (baseIndex == null ? Stream.<IType>empty()
|
||||
@@ -191,24 +193,71 @@ public class JandexIndex {
|
||||
.filter(type -> type != null)
|
||||
.findFirst()
|
||||
// If not found look at indices owned by this JandexIndex instance
|
||||
.orElseGet(() -> index.get().stream()
|
||||
.map(e -> new Entry<>(e.key, e.value.getClassByName(fqName)))
|
||||
.filter(e -> e.value != null)
|
||||
.orElseGet(() -> streamOfIndices()
|
||||
.map(e -> Tuples.of(e.getT1(), e.getT2().getClassByName(fqName)))
|
||||
.filter(e -> e.getT2() != null)
|
||||
.map(e -> createType(e))
|
||||
.findFirst()
|
||||
.orElse(null));
|
||||
|
||||
}
|
||||
|
||||
private IType createType(Entry<File, ClassInfo> match) {
|
||||
File classpathResource = match.key;
|
||||
private IType createType(Tuple2<File, ClassInfo> match) {
|
||||
File classpathResource = match.getT1();
|
||||
IJavadocProvider javadocProvider = null;
|
||||
try {
|
||||
javadocProvider = javadocProvidersCache.get(match.key, () -> javadocProviderFactory == null ? ABSENT_JAVADOC_PROVIDER : javadocProviderFactory.createJavadocProvider(classpathResource));
|
||||
javadocProvider = javadocProvidersCache.get(classpathResource, () -> javadocProviderFactory == null ? ABSENT_JAVADOC_PROVIDER : javadocProviderFactory.createJavadocProvider(classpathResource));
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Wrappers.wrap(this, match.value, javadocProvider);
|
||||
return Wrappers.wrap(this, match.getT2(), javadocProvider);
|
||||
}
|
||||
|
||||
|
||||
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<Tuple2<String, IType>> 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(), createType(Tuples.of(file, info))));
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, TypeFilter typeFilter) {
|
||||
Flux<Tuple2<IType, Double>> flux = Flux.fromIterable(knownTypes.values())
|
||||
.publishOn(Schedulers.parallel())
|
||||
.flatMap(s -> Flux.fromIterable(s.get()))
|
||||
.filter(t -> typeFilter == null || typeFilter.accept(t.getT2()))
|
||||
.map(t -> Tuples.of(t.getT2(), FuzzyMatcher.matchScore(searchTerm, t.getT1())))
|
||||
.filter(t -> t.getT2() != 0.0);
|
||||
if (baseIndex == null) {
|
||||
return flux;
|
||||
} else {
|
||||
return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm, typeFilter)));
|
||||
}
|
||||
}
|
||||
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
DotName name = DotName.createSimple(type.getFullyQualifiedName());
|
||||
Flux<IType> flux = Flux.fromIterable(index.keySet())
|
||||
.publishOn(Schedulers.parallel())
|
||||
.flatMap(file -> {
|
||||
Optional<IndexView> optional = index.get(file).get();
|
||||
if (optional.isPresent()) {
|
||||
return Flux.fromIterable(type.isInterface() ? optional.get().getAllKnownImplementors(name) : optional.get().getAllKnownSubclasses(name))
|
||||
.publishOn(Schedulers.parallel())
|
||||
.map(info -> createType(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(type)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.Type;
|
||||
@@ -57,7 +58,8 @@ class TypeImpl implements IType {
|
||||
@Override
|
||||
public Stream<IAnnotation> getAnnotations() {
|
||||
// TODO: check correctness!
|
||||
return info.annotations().get(info.name()).stream().map(a -> Wrappers.wrap(a, javadocProvider));
|
||||
List<AnnotationInstance> annotations = info.annotations().get(info.name());
|
||||
return annotations == null ? Stream.empty() : annotations.stream().map(a -> Wrappers.wrap(a, javadocProvider));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,13 +119,13 @@ class TypeImpl implements IType {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return info.toString().hashCode();
|
||||
return info.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof TypeImpl) {
|
||||
return info.toString().equals(((TypeImpl)obj).info.toString());
|
||||
return info.equals(((TypeImpl)obj).info);
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
public interface IJavaProject extends IJavaElement {
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface TypeFilter {
|
||||
boolean accept(IType type);
|
||||
}
|
||||
|
||||
IType findType(String fqName);
|
||||
|
||||
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, TypeFilter typeFilter);
|
||||
|
||||
Flux<IType> allSubtypesOf(IType type);
|
||||
|
||||
IClasspath getClasspath();
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class MavenCore {
|
||||
|
||||
private Supplier<JandexIndex> javaCoreIndex = Suppliers.memoize(() -> {
|
||||
try {
|
||||
return new JandexIndex(getJreLibs(), jarFile -> findIndexFile(jarFile), (classpathResource) -> {
|
||||
return new JandexIndex(getJreLibs().map(path -> path.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), (classpathResource) -> {
|
||||
try {
|
||||
String javaVersion = getJavaRuntimeMinorVersion();
|
||||
if (javaVersion == null) {
|
||||
@@ -283,7 +283,14 @@ public class MavenCore {
|
||||
private File findIndexFile(File jarFile) {
|
||||
String suffix = null;
|
||||
try {
|
||||
if (jarFile.toString().startsWith(getJavaHome())) {
|
||||
String javaHome = getJavaHome();
|
||||
if (javaHome != null) {
|
||||
int index = javaHome.lastIndexOf('/');
|
||||
if (index != -1) {
|
||||
javaHome = javaHome.substring(0, index);
|
||||
}
|
||||
}
|
||||
if (jarFile.toString().startsWith(javaHome)) {
|
||||
suffix = getJavaRuntimeVersion();
|
||||
}
|
||||
} catch (MavenException e) {
|
||||
|
||||
@@ -15,12 +15,14 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Wrapper for Maven Core project
|
||||
*
|
||||
@@ -60,12 +62,22 @@ public class MavenJavaProject implements IJavaProject {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, TypeFilter typeFilter) {
|
||||
return classpath.fuzzySearchType(searchTerm, typeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
return classpath.allSubtypesOf(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenProjectClasspath getClasspath() {
|
||||
return classpath;
|
||||
}
|
||||
|
||||
public Path getOutputFolder() {
|
||||
return Paths.get(new File(mavenProject.getBuild().getOutputDirectory()).toURI());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
@@ -25,6 +26,7 @@ import org.springframework.ide.vscode.commons.jandex.JandexIndex;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject.TypeFilter;
|
||||
import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.java.roaster.RoasterJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider;
|
||||
@@ -36,6 +38,9 @@ import org.springframework.ide.vscode.commons.util.Log;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Classpath for a maven project
|
||||
*
|
||||
@@ -70,7 +75,7 @@ public class MavenProjectClasspath implements IClasspath {
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return new JandexIndex(classpathEntries, jarFile -> findIndexFile(jarFile), classpathResource -> {
|
||||
return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> {
|
||||
switch (providerType) {
|
||||
case JAVA_PARSER:
|
||||
return createParserJavadocProvider(classpathResource);
|
||||
@@ -95,6 +100,14 @@ public class MavenProjectClasspath implements IClasspath {
|
||||
return javaIndex.get().findType(fqName);
|
||||
}
|
||||
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchType(String searchTerm, TypeFilter typeFilter) {
|
||||
return javaIndex.get().fuzzySearchTypes(searchTerm, typeFilter);
|
||||
}
|
||||
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
return javaIndex.get().allSubtypesOf(type);
|
||||
}
|
||||
|
||||
private File findIndexFile(File jarFile) {
|
||||
return new File(maven.getIndexFolder().toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx");
|
||||
}
|
||||
@@ -219,5 +232,4 @@ public class MavenProjectClasspath implements IClasspath {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Java project that contains classpath text file
|
||||
*
|
||||
@@ -55,6 +58,16 @@ public class JavaProjectWithClasspathFile implements IJavaProject {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, TypeFilter typeFilter) {
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
return classpath;
|
||||
@@ -90,5 +103,4 @@ public class JavaProjectWithClasspathFile implements IJavaProject {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -3,15 +3,18 @@ package org.springframework.ide.vscode.commons.maven;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.commons.java.Flags;
|
||||
import org.springframework.ide.vscode.commons.java.IField;
|
||||
import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IPrimitiveType;
|
||||
@@ -26,6 +29,8 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
public class JavaIndexTest {
|
||||
|
||||
private static LoadingCache<String, Path> projectsCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Path>() {
|
||||
@@ -62,6 +67,26 @@ public class JavaIndexTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fuzzySearchNoFilter() throws Exception {
|
||||
List<Tuple2<IType, Double>> results = MavenCore.getInstance().getJavaIndexForJreLibs()
|
||||
.fuzzySearchTypes("util.Map", null)
|
||||
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
|
||||
.block();
|
||||
assertTrue(results.size() > 10);
|
||||
assertEquals("java.util.Map", results.get(0).getT1().getFullyQualifiedName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fuzzySearchWithFilter() throws Exception {
|
||||
List<Tuple2<IType, Double>> results = MavenCore.getInstance().getJavaIndexForJreLibs()
|
||||
.fuzzySearchTypes("util.Map", (type) -> Flags.isPrivate(type.getFlags()))
|
||||
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
|
||||
.block();
|
||||
assertTrue(results.size() > 10);
|
||||
assertEquals("java.util.EnumMap$KeySet", results.get(0).getT1().getFullyQualifiedName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findClassInJar() throws Exception {
|
||||
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
|
||||
|
||||
3
vscode-extensions/commons/commons-maven/src/test/resources/.gitignore
vendored
Normal file
3
vscode-extensions/commons/commons-maven/src/test/resources/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
**/classpath.txt
|
||||
**/bin/**
|
||||
**/*.log.*
|
||||
@@ -1331,7 +1331,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore @Test public void testClassReferenceCompletion() throws Exception {
|
||||
@Test public void testClassReferenceCompletion() throws Exception {
|
||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||
|
||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-with-mongo"));
|
||||
|
||||
@@ -3247,7 +3247,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Ignore @Test public void testClassReferenceCompletion() throws Exception {
|
||||
@Test public void testClassReferenceCompletion() throws Exception {
|
||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||
|
||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-with-mongo"));
|
||||
|
||||
Reference in New Issue
Block a user