PT #164474609: Light TypeDescriptorData and caching super, sub-types

This commit is contained in:
BoykoAlex
2019-03-08 11:26:00 -05:00
parent ee67cf914d
commit 91d9838fff
32 changed files with 5932 additions and 633 deletions

View File

@@ -1,12 +1,5 @@
{
"fqName": "java.util.Map",
"bindingKey": "Ljava/util/Map;",
"clazz": false,
"annotation": false,
"interfaze": true,
"enam": false,
"superClassName": "java.lang.Object",
"superInterfaceNames": [],
"fields": [],
"methods": [
{
@@ -713,6 +706,13 @@
"isOwn": false
}
},
"fqName": "java.util.Map",
"clazz": false,
"annotation": false,
"interfaze": true,
"enam": false,
"superClassName": "java.lang.Object",
"superInterfaceNames": [],
"flags": 1537,
"name": "Map",
"handleIdentifier": "\u003dtest-webflux-project/\\/Library\\/Java\\/JavaVirtualMachines\\/jdk1.8.0_151.jdk\\/Contents\\/Home\\/jre\\/lib\\/rt.jar\u003cjava.util(Map.class[Map",

View File

@@ -1,11 +1,5 @@
{
"fqName": "org.test.NestedRouter3",
"bindingKey": "Lorg/test/NestedRouter3;",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superInterfaceNames": [],
"fields": [],
"methods": [
{
@@ -62,6 +56,12 @@
"isOwn": true
}
},
"fqName": "org.test.NestedRouter3",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superInterfaceNames": [],
"flags": 1,
"name": "NestedRouter3",
"handleIdentifier": "\u003dtest-webflux-project/src\\/main\\/java\u003corg.test{NestedRouter3.java[NestedRouter3",

View File

@@ -1,11 +1,5 @@
{
"fqName": "org.test.Quote",
"bindingKey": "Lorg/test/Quote;",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superInterfaceNames": [],
"fields": [
{
"bindingKey": "Lorg/test/Quote;.MATH_CONTEXT",
@@ -267,6 +261,12 @@
"isOwn": true
}
},
"fqName": "org.test.Quote",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superInterfaceNames": [],
"flags": 1,
"name": "Quote",
"handleIdentifier": "\u003dtest-webflux-project/src\\/main\\/java\u003corg.test{Quote.java[Quote",

View File

@@ -1,12 +1,5 @@
{
"fqName": "org.springframework.boot.autoconfigure.web.ServerProperties",
"bindingKey": "Lorg/springframework/boot/autoconfigure/web/ServerProperties;",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superClassName": "java.lang.Object",
"superInterfaceNames": [],
"fields": [
{
"bindingKey": "Lorg/springframework/boot/autoconfigure/web/ServerProperties;.port",
@@ -625,6 +618,13 @@
"isOwn": false
}
},
"fqName": "org.springframework.boot.autoconfigure.web.ServerProperties",
"clazz": true,
"annotation": false,
"interfaze": false,
"enam": false,
"superClassName": "java.lang.Object",
"superInterfaceNames": [],
"flags": 1,
"name": "ServerProperties",
"handleIdentifier": "\u003dtest-webflux-project/\\/Users\\/aboyko\\/.m2\\/repository\\/org\\/springframework\\/boot\\/spring-boot-autoconfigure\\/2.0.0.RELEASE\\/spring-boot-autoconfigure-2.0.0.RELEASE.jar\u003corg.springframework.boot.autoconfigure.web(ServerProperties.class[ServerProperties",

View File

@@ -29,6 +29,7 @@ import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.ls.eclipse.commons.STS4LanguageClientImpl;
public class JavaLangugeClientTest {
@@ -87,32 +88,32 @@ public class JavaLangugeClientTest {
@Test
public void fuzzyFindTypesIncludingSysLibs() throws Exception {
List<String> data = client
List<TypeDescriptorData> data = client
.javaSearchTypes(new JavaSearchParams(project.getLocationURI().toString(), "util.Map", true, true))
.get(100, TimeUnit.SECONDS);
assertNotNull(data);
assertEquals(500, data.size());
List<String> closeMatches = data.stream().filter(t -> t.contains("util.Map")).collect(Collectors.toList());
List<String> closeMatches = data.stream().map(t -> t.getFqName()).filter(t -> t.contains("util.Map")).collect(Collectors.toList());
assertEquals(2, closeMatches.size());
assertNotNull(closeMatches.stream().filter(t -> "java.util.Map".equals(t)).findFirst().orElse(null));
}
@Test
public void fuzzyFindTypesExcludingSysLibs() throws Exception {
List<String> data = client
List<TypeDescriptorData> data = client
.javaSearchTypes(new JavaSearchParams(project.getLocationURI().toString(), "util.Map", true, false))
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
assertEquals(186, data.size());
// TestUtils.saveJsonData("search-util-map.json", data);
List<String> closeMatches = data.stream().filter(t -> t.contains("util.Map")).collect(Collectors.toList());
TestUtils.saveJsonData("search-util-map.json", data);
List<String> closeMatches = data.stream().map(t -> t.getFqName()).filter(t -> t.contains("util.Map")).collect(Collectors.toList());
assertEquals(1, closeMatches.size());
assertEquals("io.netty.util.Mapping", closeMatches.get(0));
}
@Test
public void fuzzyFindAllTypesExcludingSysLibs() throws Exception {
List<String> data = client
List<TypeDescriptorData> data = client
.javaSearchTypes(new JavaSearchParams(project.getLocationURI().toString(), "", true, false))
.get(1000, TimeUnit.SECONDS);
assertNotNull(data);
@@ -141,18 +142,28 @@ public class JavaLangugeClientTest {
@Test
public void map_Subtypes() throws Exception {
List<TypeData> data = client
.javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map"))
List<TypeDescriptorData> data = client
.javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", false))
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
assertTrue(data.size() > 200);
assertTrue(data.stream().filter(t -> "java.util.AbstractMap".equals(t.getFqName())).findFirst().isPresent());
}
@Test
public void map_Subtypes_with_Itself() throws Exception {
List<TypeDescriptorData> data = client
.javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", true))
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
assertTrue(data.size() > 200);
assertTrue(data.stream().filter(t -> "java.util.Map".equals(t.getFqName())).findFirst().isPresent());
}
@Test
public void arrayList_SuperTypes() throws Exception {
List<TypeData> data = client
.javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList"))
List<TypeDescriptorData> data = client
.javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", false))
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
Set<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
@@ -170,11 +181,33 @@ public class JavaLangugeClientTest {
assertEquals(expected, actual);
}
@Test
public void arrayList_SuperTypes_with_Itself() throws Exception {
List<TypeDescriptorData> data = client
.javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", true))
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
Set<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(
"java.util.ArrayList",
"java.util.List",
"java.util.RandomAccess",
"java.lang.Cloneable",
"java.io.Serializable",
"java.util.AbstractList",
"java.util.Collection",
"java.lang.Object",
"java.util.AbstractCollection",
"java.lang.Iterable"
));
assertEquals(expected, actual);
}
@Test
public void taskExecutorFactoryBean_SuperTypes() throws Exception {
List<TypeData> data = client
List<TypeDescriptorData> data = client
.javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "org.springframework.scheduling.config.TaskExecutorFactoryBean"))
.get(100000, TimeUnit.SECONDS);
.get(10, TimeUnit.SECONDS);
assertNotNull(data);
Set<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(

View File

@@ -72,6 +72,7 @@ import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.jdt.ls.commons.Logger;
import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathListenerHandler;
import org.springframework.tooling.jdt.ls.commons.java.JavaData;
@@ -126,7 +127,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
final private JavaData javaData = new JavaData(STS4LanguageClientImpl::label , Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
final private JavaFluxSearch javaFluxSearch = new JavaFluxSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
final private JavaFluxSearch javaFluxSearch = new JavaFluxSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
final private TypeHierarchy typeHierarchy = new TypeHierarchy(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
@@ -440,11 +441,10 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
}
@Override
public CompletableFuture<List<String>> javaSearchTypes(JavaSearchParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSearchTypes(JavaSearchParams params) {
return CompletableFuture.supplyAsync(() -> {
try {
List<String> types = javaFluxSearch.fuzzySearchTypes(params);
return types;
return javaFluxSearch.fuzzySearchTypes(params);
} catch (Exception e) {
LanguageServerCommonsActivator.logError(e, "Failed to search type with term '" + params.getTerm()
+ "' in project " + params.getProjectUri());
@@ -467,16 +467,16 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
}
@Override
public CompletableFuture<List<TypeData>> javaSubTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() ->
typeHierarchy.subTypes(params.getProjectUri() == null ? null : URI.create(params.getProjectUri()), params.getFqName()).collect(Collectors.toList())
typeHierarchy.subTypes(params).collect(Collectors.toList())
);
}
@Override
public CompletableFuture<List<TypeData>> javaSuperTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() ->
typeHierarchy.superTypes(params.getProjectUri() == null ? null : URI.create(params.getProjectUri()), params.getFqName()).collect(Collectors.toList())
typeHierarchy.superTypes(params).collect(Collectors.toList())
);
}

View File

@@ -17,6 +17,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,7 +37,6 @@ import reactor.core.Disposable;
import reactor.core.Disposables;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
/**
* Classpath with Jandex Java index for searching types
@@ -101,8 +101,8 @@ public final class JandexClasspath implements ClasspathIndex {
}
@Override
public Flux<Tuple2<String, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
return javaIndex.get().fuzzySearchTypes(searchTerm).map(m -> Tuples.of(m.getT2().name().toString(), m.getT3()));
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
return javaIndex.get().fuzzySearchITypes(searchTerm);
}
@Override
@@ -111,8 +111,13 @@ public final class JandexClasspath implements ClasspathIndex {
}
@Override
public Flux<IType> allSubtypesOf(IType type) {
return javaIndex.get().allSubtypesOf(type);
public Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType) {
IType type = javaIndex.get().findType(fqName);
if (type == null) {
return Flux.empty();
} else {
return Flux.concat(includeFocusType ? Flux.fromStream(Stream.of(type)) : Flux.empty(), javaIndex.get().allSubtypesOf(type));
}
}
private File findIndexFile(File jarFile) {
@@ -152,25 +157,25 @@ public final class JandexClasspath implements ClasspathIndex {
}
@Override
public Flux<IType> allSuperTypesOf(IType type) {
public Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType) {
Queue<String> queue = new LinkedList<>();
HashSet<String> visited = new HashSet<>();
updateQueue(queue, visited, type);
return Flux.generate(() -> queue, (state, sink) -> {
IType nextType = null;
while (nextType == null && state.peek() != null) {
queue.add(fqName);
visited.add(fqName);
Flux<IType> typesFlux = Flux.generate(() -> queue, (state, sink) -> {
if (state.peek() == null) {
sink.complete();
} else {
String typeName = state.poll();
nextType = findType(typeName);
IType nextType = findType(typeName);
if (nextType != null) {
sink.next(nextType);
updateQueue(state, visited, nextType);
}
}
if (state.peek() == null) {
sink.complete();
}
return state;
});
return includeFocusType ? typesFlux : typesFlux.skip(1);
}
}

View File

@@ -28,6 +28,7 @@ import com.google.common.cache.CacheBuilder;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
public class JandexIndex extends BasicJandexIndex {
@@ -81,6 +82,10 @@ public class JandexIndex extends BasicJandexIndex {
return Wrappers.wrap(this, match.getT1(), match.getT2(), javadocProvider);
}
Flux<Tuple2<IType, Double>> fuzzySearchITypes(String searchTerm) {
return fuzzySearchTypes(searchTerm).map(m -> Tuples.of(createType(Tuples.of(m.getT1(), m.getT2())), m.getT3()));
}
public Flux<IType> allSubtypesOf(IType type) {
DotName name = DotName.createSimple(type.getFullyQualifiedName());
return allSubtypesOf(name, type.isInterface()).map(match -> createType(match));

View File

@@ -17,10 +17,10 @@ import reactor.util.function.Tuple2;
public interface ClasspathIndex extends Disposable {
IType findType(String fqName);
Flux<Tuple2<String, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<IType> allSubtypesOf(IType type);
Flux<IType> allSuperTypesOf(IType type);
Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType);
Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType);
IJavaModuleData findClasspathResourceContainer(String fqName);
}

View File

@@ -127,4 +127,11 @@ public class JavaUtils {
return bindingKey == null ? null : bindingKey.substring(1, bindingKey.length() - 1).replace('/', '.');
}
public static String typeFqNametoBindingKey(String fqName) {
StringBuilder sb = new StringBuilder('L');
sb.append(fqName.replace('.', '/'));
sb.append(';');
return sb.toString();
}
}

View File

@@ -11,8 +11,11 @@
package org.springframework.ide.vscode.commons.jdtls;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -29,6 +32,7 @@ import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import com.google.common.base.Suppliers;
@@ -51,7 +55,9 @@ public class JdtLsIndex implements ClasspathIndex {
private final URI projectUri;
private final JdtLsJavadocProvider javadocProvider;
private Cache<String, Optional<IType>> cache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).build();
final private Cache<String, Optional<IType>> typeCache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).build();
final private Cache<JavaTypeHierarchyParams, CompletableFuture<List<IType>>> supertypesCache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).build();
final private Cache<JavaTypeHierarchyParams, CompletableFuture<List<IType>>> subtypesCache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).build();
public JdtLsIndex(STS4LanguageClient client, URI projectUri) {
this.client = client;
@@ -69,10 +75,16 @@ public class JdtLsIndex implements ClasspathIndex {
return Wrappers.wrap(data, Suppliers.memoize(() -> declaringTypeFqName == null ? null : findType(declaringTypeFqName)), javadocProvider);
}
private IType toTypeFromDescriptor(TypeDescriptorData data) {
String declaringTypeBindingKey = data.getDeclaringType();
String declaringTypeFqName = JavaUtils.typeBindingKeyToFqName(declaringTypeBindingKey);
return Wrappers.wrap(data, Suppliers.memoize(() -> findType(data.getFqName())), Suppliers.memoize(() -> declaringTypeFqName == null ? null : findType(declaringTypeFqName)), javadocProvider);
}
@Override
public IType findType(String fqName) {
try {
return cache.get(fqName, () -> {
return typeCache.get(fqName, () -> {
JavaDataParams params = new JavaDataParams(projectUri.toString(), "L" + fqName.replace('.', '/') + ";", false);
try {
TypeData data = client.javaType(params).get(500, TimeUnit.MILLISECONDS);
@@ -91,12 +103,12 @@ public class JdtLsIndex implements ClasspathIndex {
}
@Override
public Flux<Tuple2<String, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs) {
JavaSearchParams searchParams = new JavaSearchParams(projectUri.toString(), searchTerm, includeBinaries, includeSystemLibs, SEARCH_TIMEOUT);
return Mono.fromFuture(client.javaSearchTypes(searchParams))
.flatMapMany(results -> Flux.fromIterable(results).publishOn(Schedulers.parallel()))
.filter(Objects::nonNull)
.map(type -> Tuples.of(type, FuzzyMatcher.matchScore(searchTerm, type)))
.map(type -> Tuples.of(toTypeFromDescriptor(type), FuzzyMatcher.matchScore(searchTerm, type.getFqName())))
.filter(tuple -> tuple.getT2() != 0.0);
}
@@ -110,22 +122,42 @@ public class JdtLsIndex implements ClasspathIndex {
.filter(tuple -> tuple.getT2() != 0.0);
}
@Override
public Flux<IType> allSubtypesOf(IType type) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), type.getFullyQualifiedName());
return Mono.fromFuture(client.javaSubTypes(searchParams))
.flatMapMany(results -> Flux.fromIterable(results).publishOn(Schedulers.parallel()))
.filter(Objects::nonNull)
.map(this::toType);
private List<IType> convertTypeDescriptors(List<TypeDescriptorData> descriptors) {
List<IType> types = new ArrayList<>(descriptors.size());
for (TypeDescriptorData data : descriptors) {
if (data != null) {
types.add(toTypeFromDescriptor(data));
}
}
return types;
}
@Override
public Flux<IType> allSuperTypesOf(IType type) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), type.getFullyQualifiedName());
return Mono.fromFuture(client.javaSuperTypes(searchParams))
.flatMapMany(results -> Flux.fromIterable(results).publishOn(Schedulers.parallel()))
.filter(Objects::nonNull)
.map(this::toType);
public Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType);
try {
CompletableFuture<List<IType>> future = subtypesCache.get(searchParams, () -> client
.javaSubTypes(searchParams).handle((results, exception) -> convertTypeDescriptors(results)));
return Mono.fromFuture(future)
.flatMapMany(results -> Flux.fromIterable(results));
} catch (ExecutionException e) {
log.error("{}", e);
return Flux.empty();
}
}
@Override
public Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType);
try {
CompletableFuture<List<IType>> future = supertypesCache.get(searchParams, () -> client
.javaSuperTypes(searchParams).handle((results, exception) -> convertTypeDescriptors(results)));
return Mono.fromFuture(future)
.flatMapMany(results -> Flux.fromIterable(results));
} catch (ExecutionException e) {
log.error("{}", e);
return Flux.empty();
}
}
@Override

View File

@@ -32,12 +32,14 @@ import org.springframework.ide.vscode.commons.java.ITypeVariable;
import org.springframework.ide.vscode.commons.java.IUnresolvedTypeVariable;
import org.springframework.ide.vscode.commons.java.IVoidType;
import org.springframework.ide.vscode.commons.java.IWildcardType;
import org.springframework.ide.vscode.commons.java.JavaUtils;
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData.AnnotationData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData.FieldData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData.MethodData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import com.google.common.base.Supplier;
@@ -491,4 +493,111 @@ public class Wrappers {
};
}
public static IType wrap(TypeDescriptorData descriptor, Supplier<IType> lazyType, Supplier<IType> declaringTypeSupplier, IJavadocProvider javadocProvider) {
return new IType() {
@Override
public int getFlags() {
return descriptor.getFlags();
}
@Override
public IType getDeclaringType() {
return declaringTypeSupplier.get();
}
@Override
public IJavaModuleData classpathContainer() {
return lazyType.get().classpathContainer();
}
@Override
public String signature() {
return descriptor.getLabel();
}
@Override
public String getElementName() {
return descriptor.getName();
}
@Override
public IJavadoc getJavaDoc() {
return javadocProvider.getJavadoc(this);
}
@Override
public String getBindingKey() {
return JavaUtils.typeFqNametoBindingKey(getFullyQualifiedName());
}
@Override
public boolean exists() {
return true;
}
@Override
public Stream<IAnnotation> getAnnotations() {
return lazyType.get().getAnnotations();
}
@Override
public boolean isClass() {
return descriptor.isClass();
}
@Override
public boolean isEnum() {
return descriptor.isEnum();
}
@Override
public boolean isInterface() {
return descriptor.isInterface();
}
@Override
public boolean isAnnotation() {
return descriptor.isAnnotation();
}
@Override
public String getFullyQualifiedName() {
return descriptor.getFqName();
}
@Override
public IField getField(String name) {
return getFields().filter(f -> name.equals(f.getElementName())).findFirst().orElse(null);
}
@Override
public Stream<IField> getFields() {
return lazyType.get().getFields();
}
@Override
public IMethod getMethod(String name, Stream<IJavaType> parameters) {
return lazyType.get().getMethod(name, parameters);
}
@Override
public Stream<IMethod> getMethods() {
return lazyType.get().getMethods();
}
@Override
public String getSuperclassName() {
return descriptor.getSuperClassName();
}
@Override
public String[] getSuperInterfaceNames() {
return descriptor.getSuperInterfaceNames();
}
};
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.jdtls.JdtLsIndex;
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@@ -51,9 +52,9 @@ public class JdtLsIndexTest {
return gson.fromJson(new FileReader(jsonFile), TypeData.class);
}
private List<String> loadJsonSearchTypeResults(String fileName) throws Exception {
private List<TypeDescriptorData> loadJsonSearchTypeResults(String fileName) throws Exception {
File jsonFile = new File(JdtLsIndexTest.class.getResource("/java-data-json/" + fileName).toURI());
Type listType = new TypeToken<List<String>>(){}.getType();
Type listType = new TypeToken<List<TypeDescriptorData>>(){}.getType();
return gson.fromJson(new FileReader(jsonFile), listType);
}
@@ -138,9 +139,9 @@ public class JdtLsIndexTest {
}));
// Some valid URI necessary for URI#toString() to succeed
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
List<Tuple2<String, Double>> results = index.fuzzySearchTypes("util.Map", true, false).collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())).block();
String type = results.get(0).getT1();
assertEquals("io.netty.util.Mapping", type);
List<Tuple2<IType, Double>> results = index.fuzzySearchTypes("util.Map", true, false).collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())).block();
IType type = results.get(0).getT1();
assertEquals("io.netty.util.Mapping", type.getFullyQualifiedName());
}
@Test

View File

@@ -23,6 +23,7 @@ import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
/**
* Some 'custom' extensions to standard LSP {@link LanguageClient}.
@@ -59,15 +60,15 @@ public interface STS4LanguageClient extends LanguageClient {
CompletableFuture<Location> javaLocation(JavaDataParams params);
@JsonRequest("sts/javaSearchTypes")
CompletableFuture<List<String>> javaSearchTypes(JavaSearchParams params);
CompletableFuture<List<TypeDescriptorData>> javaSearchTypes(JavaSearchParams params);
@JsonRequest("sts/javaSearchPackages")
CompletableFuture<List<String>> javaSearchPackages(JavaSearchParams params);
@JsonRequest("sts/javaSubTypes")
CompletableFuture<List<TypeData>> javaSubTypes(JavaTypeHierarchyParams params);
CompletableFuture<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params);
@JsonRequest("sts/javaSuperTypes")
CompletableFuture<List<TypeData>> javaSuperTypes(JavaTypeHierarchyParams params);
CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params);
}

View File

@@ -14,11 +14,17 @@ public class JavaTypeHierarchyParams {
private String projectUri;
private String fqName;
private boolean includeFocusType;
public JavaTypeHierarchyParams(String projectUri, String fqName) {
public JavaTypeHierarchyParams(String projectUri, String fqName, boolean includeFocusType) {
super();
this.projectUri = projectUri;
this.fqName = fqName;
this.setIncludeFocusType(includeFocusType);
}
public JavaTypeHierarchyParams(String projectUri, String fqName) {
this(projectUri, fqName, false);
}
public String getProjectUri() {
@@ -36,5 +42,47 @@ public class JavaTypeHierarchyParams {
public void setFqName(String fqName) {
this.fqName = fqName;
}
public boolean isIncludeFocusType() {
return includeFocusType;
}
public void setIncludeFocusType(boolean includeFocusType) {
this.includeFocusType = includeFocusType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fqName == null) ? 0 : fqName.hashCode());
result = prime * result + (includeFocusType ? 1231 : 1237);
result = prime * result + ((projectUri == null) ? 0 : projectUri.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
JavaTypeHierarchyParams other = (JavaTypeHierarchyParams) obj;
if (fqName == null) {
if (other.fqName != null)
return false;
} else if (!fqName.equals(other.fqName))
return false;
if (includeFocusType != other.includeFocusType)
return false;
if (projectUri == null) {
if (other.projectUri != null)
return false;
} else if (!projectUri.equals(other.projectUri))
return false;
return true;
}
}

View File

@@ -10,36 +10,19 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.protocol.java;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.ide.vscode.commons.protocol.java.Classpath.CPE;
public class TypeData extends MemberData {
public class TypeData extends TypeDescriptorData {
private String fqName;
private String bindingKey;
private boolean clazz;
private boolean annotation;
private boolean interfaze;
private boolean enam;
private String superClassName;
private String[] superInterfaceNames;
private List<FieldData> fields;
private List<MethodData> methods;
private List<AnnotationData> annotations;
private ClasspathEntryData classpathEntry;
public String getFqName() {
return fqName;
}
public void setFqName(String fqName) {
this.fqName = fqName;
}
public List<FieldData> getFields() {
return fields;
}
@@ -72,54 +55,6 @@ public class TypeData extends MemberData {
this.classpathEntry = classpathContainer;
}
public boolean isClass() {
return clazz;
}
public void setClass(boolean clazz) {
this.clazz = clazz;
}
public boolean isAnnotation() {
return annotation;
}
public void setAnnotation(boolean annotation) {
this.annotation = annotation;
}
public boolean isInterface() {
return interfaze;
}
public void setInterface(boolean interfaze) {
this.interfaze = interfaze;
}
public boolean isEnum() {
return enam;
}
public void setEnum(boolean enam) {
this.enam = enam;
}
public String getSuperClassName() {
return superClassName;
}
public void setSuperClassName(String superClassName) {
this.superClassName = superClassName;
}
public String[] getSuperInterfaceNames() {
return superInterfaceNames;
}
public void setSuperInterfaceNames(String[] superInterfaceNames) {
this.superInterfaceNames = superInterfaceNames;
}
public List<AnnotationData> getAnnotations() {
return annotations;
}
@@ -129,23 +64,15 @@ public class TypeData extends MemberData {
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + (annotation ? 1231 : 1237);
result = prime * result + ((annotations == null) ? 0 : annotations.hashCode());
result = prime * result + ((bindingKey == null) ? 0 : bindingKey.hashCode());
result = prime * result + ((classpathEntry == null) ? 0 : classpathEntry.hashCode());
result = prime * result + (clazz ? 1231 : 1237);
result = prime * result + (enam ? 1231 : 1237);
result = prime * result + ((fields == null) ? 0 : fields.hashCode());
result = prime * result + ((fqName == null) ? 0 : fqName.hashCode());
result = prime * result + (interfaze ? 1231 : 1237);
result = prime * result + ((methods == null) ? 0 : methods.hashCode());
result = prime * result + ((superClassName == null) ? 0 : superClassName.hashCode());
result = prime * result + Arrays.hashCode(superInterfaceNames);
return result;
}
@@ -158,8 +85,6 @@ public class TypeData extends MemberData {
if (getClass() != obj.getClass())
return false;
TypeData other = (TypeData) obj;
if (annotation != other.annotation)
return false;
if (annotations == null) {
if (other.annotations != null)
return false;
@@ -175,37 +100,20 @@ public class TypeData extends MemberData {
return false;
} else if (!classpathEntry.equals(other.classpathEntry))
return false;
if (clazz != other.clazz)
return false;
if (enam != other.enam)
return false;
if (fields == null) {
if (other.fields != null)
return false;
} else if (!fields.equals(other.fields))
return false;
if (fqName == null) {
if (other.fqName != null)
return false;
} else if (!fqName.equals(other.fqName))
return false;
if (interfaze != other.interfaze)
return false;
if (methods == null) {
if (other.methods != null)
return false;
} else if (!methods.equals(other.methods))
return false;
if (superClassName == null) {
if (other.superClassName != null)
return false;
} else if (!superClassName.equals(other.superClassName))
return false;
if (!Arrays.equals(superInterfaceNames, other.superInterfaceNames))
return false;
return true;
}
public static class AnnotationData extends JavaElementData {
String fqName;

View File

@@ -0,0 +1,127 @@
/*******************************************************************************
* Copyright (c) 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.protocol.java;
import java.util.Arrays;
public class TypeDescriptorData extends MemberData {
private String fqName;
private boolean clazz;
private boolean annotation;
private boolean interfaze;
private boolean enam;
private String superClassName;
private String[] superInterfaceNames;
public String getFqName() {
return fqName;
}
public void setFqName(String fqName) {
this.fqName = fqName;
}
public boolean isClass() {
return clazz;
}
public void setClass(boolean clazz) {
this.clazz = clazz;
}
public boolean isAnnotation() {
return annotation;
}
public void setAnnotation(boolean annotation) {
this.annotation = annotation;
}
public boolean isInterface() {
return interfaze;
}
public void setInterface(boolean interfaze) {
this.interfaze = interfaze;
}
public boolean isEnum() {
return enam;
}
public void setEnum(boolean enam) {
this.enam = enam;
}
public String getSuperClassName() {
return superClassName;
}
public void setSuperClassName(String superClassName) {
this.superClassName = superClassName;
}
public String[] getSuperInterfaceNames() {
return superInterfaceNames;
}
public void setSuperInterfaceNames(String[] superInterfaceNames) {
this.superInterfaceNames = superInterfaceNames;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + (annotation ? 1231 : 1237);
result = prime * result + (clazz ? 1231 : 1237);
result = prime * result + (enam ? 1231 : 1237);
result = prime * result + ((fqName == null) ? 0 : fqName.hashCode());
result = prime * result + (interfaze ? 1231 : 1237);
result = prime * result + ((superClassName == null) ? 0 : superClassName.hashCode());
result = prime * result + Arrays.hashCode(superInterfaceNames);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
TypeDescriptorData other = (TypeDescriptorData) obj;
if (annotation != other.annotation)
return false;
if (clazz != other.clazz)
return false;
if (enam != other.enam)
return false;
if (fqName == null) {
if (other.fqName != null)
return false;
} else if (!fqName.equals(other.fqName))
return false;
if (interfaze != other.interfaze)
return false;
if (superClassName == null) {
if (other.superClassName != null)
return false;
} else if (!superClassName.equals(other.superClassName))
return false;
if (!Arrays.equals(superInterfaceNames, other.superInterfaceNames))
return false;
return true;
}
}

View File

@@ -61,12 +61,12 @@ public class JavaIndexTest {
@Test
public void fuzzySearchNoFilter() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
List<Tuple2<String, Double>> results = project.getIndex().fuzzySearchTypes("util.Map", true, true)
List<Tuple2<IType, Double>> results = project.getIndex().fuzzySearchTypes("util.Map", true, true)
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
.block();
assertTrue(results.size() > 10);
String type = results.get(0).getT1();
assertEquals("java.util.Map", type);
IType type = results.get(0).getT1();
assertEquals("java.util.Map", type.getFullyQualifiedName());
}
@Test
@@ -116,7 +116,6 @@ public class JavaIndexTest {
IType type = project.getIndex().findType("java.util.ArrayList");
assertNotNull(type);
IMethod m = type.getMethod("clear", Stream.empty());
System.out.println("Method clear: " + m.getBindingKey());
assertEquals("clear", m.getElementName());
assertEquals(IVoidType.DEFAULT, m.getReturnType());
assertEquals(0, m.parameters().count());
@@ -164,9 +163,7 @@ public class JavaIndexTest {
@Test
public void testFindAllSuperTypes() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getIndex().findType("java.util.ArrayList");
assertNotNull(type);
Set<String> actual = project.getIndex().allSuperTypesOf(type).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", false).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> expected = new HashSet<>(Arrays.asList(
"java.util.List",
"java.util.RandomAccess",
@@ -180,4 +177,23 @@ public class JavaIndexTest {
));
assertEquals(expected, actual);
}
@Test
public void testFindAllSuperTypesWithFocusType() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
Set<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> expected = new HashSet<>(Arrays.asList(
"java.util.ArrayList",
"java.util.List",
"java.util.RandomAccess",
"java.lang.Cloneable",
"java.io.Serializable",
"java.util.AbstractList",
"java.util.Collection",
"java.lang.Object",
"java.util.AbstractCollection",
"java.lang.Iterable"
));
assertEquals(expected, actual);
}
}

View File

@@ -113,6 +113,7 @@ import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.IOUtil;
import org.springframework.ide.vscode.commons.util.UriUtil;
@@ -362,7 +363,7 @@ public class LanguageServerHarness {
}
@Override
public CompletableFuture<List<String>> javaSearchTypes(JavaSearchParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSearchTypes(JavaSearchParams params) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
@@ -372,12 +373,12 @@ public class LanguageServerHarness {
}
@Override
public CompletableFuture<List<TypeData>> javaSubTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
@Override
public CompletableFuture<List<TypeData>> javaSuperTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.completedFuture(Collections.emptyList());
}

View File

@@ -43,6 +43,7 @@ import org.springframework.ide.vscode.commons.protocol.java.TypeData.AnnotationD
import org.springframework.ide.vscode.commons.protocol.java.TypeData.ClasspathEntryData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData.FieldData;
import org.springframework.ide.vscode.commons.protocol.java.TypeData.MethodData;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.jdt.ls.commons.Logger;
import org.springframework.tooling.jdt.ls.commons.classpath.ClasspathUtil;
import org.springframework.tooling.jdt.ls.commons.javadoc.JavadocUtils;
@@ -256,10 +257,29 @@ public class JavaData {
return data;
}
private void fillTypeData(IType type, TypeData data) {
fillMemberData(type, data);
public TypeDescriptorData createTypeDescriptorData(IType type) {
TypeDescriptorData data = new TypeDescriptorData();
fillTypeDescriptorData(type, data);
return data;
}
private void fillTypeDescriptorData(IType type, TypeDescriptorData data) {
fillMemberData(type, data);
data.setFqName(type.getFullyQualifiedName());
try {
data.setAnnotation(type.isAnnotation());
data.setClass(type.isClass());
data.setEnum(type.isEnum());
data.setInterface(type.isInterface());
data.setSuperClassName(type.getSuperclassName());
data.setSuperInterfaceNames(type.getSuperInterfaceNames());
} catch (JavaModelException e) {
logger.log(e);
}
}
private void fillTypeData(IType type, TypeData data) {
fillTypeDescriptorData(type, data);
data.setBindingKey(type.getKey());
@@ -276,12 +296,6 @@ public class JavaData {
for (IAnnotation annotation : type.getAnnotations()) {
annotationsBuilder.add(createAnnotationData(type, annotation));
}
data.setAnnotation(type.isAnnotation());
data.setClass(type.isClass());
data.setEnum(type.isEnum());
data.setInterface(type.isInterface());
data.setSuperClassName(type.getSuperclassName());
data.setSuperInterfaceNames(type.getSuperInterfaceNames());
} catch (JavaModelException e) {
logger.log(e);
}

View File

@@ -15,6 +15,7 @@ import java.util.List;
import org.eclipse.jdt.core.IJavaProject;
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.jdt.ls.commons.Logger;
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
@@ -27,12 +28,14 @@ import reactor.util.function.Tuples;
public class JavaFluxSearch {
final private Logger logger;
final private JavaData javaData;
final private Cache<Tuple2<Boolean, Boolean>, PackageFluxSearch> packageSearchCache = CacheBuilder.newBuilder().build();
final private Cache<Tuple2<Boolean, Boolean>, TypeFluxSearch> typeSearchCache = CacheBuilder.newBuilder().build();
public JavaFluxSearch(Logger logger) {
public JavaFluxSearch(Logger logger, JavaData javaData) {
super();
this.logger = logger;
this.javaData = javaData;
}
public List<String> fuzzySearchPackages(JavaSearchParams params) throws Exception {
@@ -44,11 +47,11 @@ public class JavaFluxSearch {
return fluxPackageSearch.searchWithLimits(javaProject, params.getTerm(), params.getTimeLimit());
}
public List<String> fuzzySearchTypes(JavaSearchParams params) throws Exception {
public List<TypeDescriptorData> fuzzySearchTypes(JavaSearchParams params) throws Exception {
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
TypeFluxSearch fluxTypeSearch = typeSearchCache.get(
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new TypeFluxSearch(logger, params.isIncludeBinaries(), params.isIncludeSystemLibs())
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new TypeFluxSearch(logger, javaData, params.isIncludeBinaries(), params.isIncludeSystemLibs())
);
return fluxTypeSearch.searchWithLimits(javaProject, params.getTerm(), params.getTimeLimit());
}

View File

@@ -17,18 +17,22 @@ import static org.springframework.tooling.jdt.ls.commons.java.SearchUtils.toWild
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.jdt.ls.commons.Logger;
import reactor.core.publisher.Flux;
public class TypeFluxSearch extends CachingFluxJavaSearch<String> {
public class TypeFluxSearch extends CachingFluxJavaSearch<TypeDescriptorData> {
public TypeFluxSearch(Logger logger, boolean includeBinaries, boolean includeSystemLibs) {
private JavaData javaData;
public TypeFluxSearch(Logger logger, JavaData javaData, boolean includeBinaries, boolean includeSystemLibs) {
super(logger, includeBinaries, includeSystemLibs);
this.javaData = javaData;
}
@Override
protected Flux<String> getValuesAsync(IJavaProject javaProject, String searchTerm) {
protected Flux<TypeDescriptorData> getValuesAsync(IJavaProject javaProject, String searchTerm) {
try {
return new FluxJdtSearch(logger)
.scope(searchScope(javaProject, includeBinaries, includeSystemLibs))
@@ -36,7 +40,7 @@ public class TypeFluxSearch extends CachingFluxJavaSearch<String> {
.search()
.map(match -> match.getElement())
.filter(o -> o instanceof IType)
.map(e -> ((IType) e).getFullyQualifiedName());
.map(e -> javaData.createTypeDescriptorData((IType) e));
} catch (Exception e) {
logger.log(e);
return Flux.empty();
@@ -44,8 +48,8 @@ public class TypeFluxSearch extends CachingFluxJavaSearch<String> {
}
@Override
protected String stringValue(String t) {
return t;
protected String stringValue(TypeDescriptorData t) {
return t.getFqName();
}
}

View File

@@ -11,14 +11,14 @@
package org.springframework.tooling.jdt.ls.commons.java;
import java.net.URI;
import java.util.Arrays;
import java.util.stream.Stream;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.springframework.ide.vscode.commons.protocol.java.TypeData;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
import org.springframework.tooling.jdt.ls.commons.Logger;
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
@@ -62,20 +62,26 @@ public class TypeHierarchy {
return null;
}
public Stream<TypeData> subTypes(URI projectUri, String fqName) {
ITypeHierarchy hierarchy = hierarchy(projectUri, fqName, false);
public Stream<TypeDescriptorData> subTypes(JavaTypeHierarchyParams params) {
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
ITypeHierarchy hierarchy = hierarchy(projectUri, params.getFqName(), false);
if (hierarchy != null) {
return Arrays.stream(hierarchy.getAllSubtypes(hierarchy.getType())).parallel().map(javaData::createTypeData);
IType focusType = hierarchy.getType();
return Stream.concat(params.isIncludeFocusType() ? Stream.of(focusType) : Stream.empty(), Stream.of(hierarchy.getAllSubtypes(focusType)))
.parallel()
.map(javaData::createTypeDescriptorData);
}
return Stream.of();
}
public Stream<TypeData> superTypes(URI projectUri, String fqName) {
ITypeHierarchy hierarchy = hierarchy(projectUri, fqName, true);
public Stream<TypeDescriptorData> superTypes(JavaTypeHierarchyParams params) {
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
ITypeHierarchy hierarchy = hierarchy(projectUri, params.getFqName(), true);
if (hierarchy != null) {
return Arrays.stream(hierarchy.getAllSupertypes(hierarchy.getType()))
IType focusType = hierarchy.getType();
return Stream.concat(params.isIncludeFocusType() ? Stream.of(focusType) : Stream.empty(), Stream.of(hierarchy.getAllSupertypes(focusType)))
.parallel()
.map(javaData::createTypeData);
.map(javaData::createTypeDescriptorData);
}
return Stream.of();
}

View File

@@ -10,28 +10,28 @@
*******************************************************************************/
package org.springframework.tooling.jdt.ls.extension;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
import com.google.gson.Gson;
@SuppressWarnings("restriction")
public class HierarchyHandler implements IDelegateCommandHandler {
private Gson gson = new Gson();
@SuppressWarnings("unchecked")
@Override
public Object executeCommand(String commandId, List<Object> arguments, IProgressMonitor monitor) throws Exception {
Map<String, Object> obj = (Map<String, Object>) arguments.get(0);
String projectUri = (String) obj.get("projectUri");
String fqName = (String) obj.get("fqName");
JavaTypeHierarchyParams params = gson.fromJson(gson.toJson(arguments.get(0)), JavaTypeHierarchyParams.class);
switch (commandId) {
case "sts.java.hierarchy.subtypes":
return JavaHelpers.HIERARCHY.get().subTypes(URI.create(projectUri), fqName).collect(Collectors.toList());
return JavaHelpers.HIERARCHY.get().subTypes(params).collect(Collectors.toList());
case "sts.java.hierarchy.supertypes":
return JavaHelpers.HIERARCHY.get().superTypes(URI.create(projectUri), fqName).collect(Collectors.toList());
return JavaHelpers.HIERARCHY.get().superTypes(params).collect(Collectors.toList());
default:
return null;
}

View File

@@ -26,7 +26,7 @@ public class JavaHelpers {
final public static Supplier<JavaData> DATA = Suppliers.memoize(() -> new JavaData(element -> HoverInfoProvider.computeSignature(element).getValue(), logger));
final public static Supplier<JavaFluxSearch> SEARCH = Suppliers.memoize(() -> new JavaFluxSearch(logger));
final public static Supplier<JavaFluxSearch> SEARCH = Suppliers.memoize(() -> new JavaFluxSearch(logger, DATA.get()));
final public static Supplier<TypeHierarchy> HIERARCHY = Suppliers.memoize(() -> new TypeHierarchy(logger, DATA.get()));

View File

@@ -242,9 +242,9 @@ public class AutowiredHoverProvider implements HoverProvider {
// Raw collections shouldn't match any beans
return type.getTypeArguments().length == 1 ? matchBeansByType(project, beans, type.getTypeArguments()[0].getQualifiedName(), false) : ImmutableList.of();
} else if (type.isArray() && type.getDimensions() == 1) {
return matchBeansByType(project, beans, type.getElementType().getErasure().getQualifiedName(), false);
return matchBeansByType(project, beans, type.getElementType().getErasure().getBinaryName(), false);
} else {
return matchBeansByType(project, beans, type.getErasure().getQualifiedName(), true);
return matchBeansByType(project, beans, type.getErasure().getBinaryName(), true);
}
}
@@ -269,16 +269,8 @@ public class AutowiredHoverProvider implements HoverProvider {
// Trim the generic parameters part if it's present
String liveBeanTypeFQName = idx < 0 ? rawLiveBeanFqName : rawLiveBeanFqName.substring(0, idx);
if (liveBeanTypeFQName != null) {
if (liveBeanTypeFQName.replace('$', '.').equals(bindingQualifiedName)) {
return true;
} else {
IType type = jp.getIndex().findType(liveBeanTypeFQName);
String fqTypeName = bindingQualifiedName;
if (type != null) {
return jp.getIndex().allSuperTypesOf(type).map(IType::getFullyQualifiedName)
.filter(fqn -> fqTypeName.equals(fqn.replace('$', '.'))).blockFirst() != null;
}
}
return jp.getIndex().allSuperTypesOf(liveBeanTypeFQName, true).map(IType::getFullyQualifiedName)
.filter(fqn -> bindingQualifiedName.equals(fqn)).blockFirst() != null;
}
return false;
}

View File

@@ -12,11 +12,9 @@
package org.springframework.ide.vscode.boot.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +31,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
/**
@@ -137,24 +136,17 @@ public class ClassReferenceProvider extends CachingValueProvider {
@Override
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
IType targetType = target == null || target.isEmpty() ? javaProject.getIndex().findType("java.lang.Object") : javaProject.getIndex().findType(target);
if (targetType == null) {
return Flux.empty();
}
Set<IType> allSubclasses = javaProject.getIndex()
.allSubtypesOf(targetType)
.filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t))
.collect(Collectors.toSet())
.block();
if (allSubclasses.isEmpty()) {
return Flux.empty();
Flux<Tuple2<IType, Double>> typesWithScoresFlux = Flux.empty();
if (target == null) {
typesWithScoresFlux = javaProject.getIndex().fuzzySearchTypes(query, true, false);
} else {
return Flux.fromIterable(allSubclasses)
.map(type -> Tuples.of(type, FuzzyMatcher.matchScore(query, type.getFullyQualifiedName())))
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
.flatMapIterable(l -> l)
.map(t -> StsValueHint.create(sourceLinks, javaProject, t.getT1()));
typesWithScoresFlux = javaProject.getIndex().allSubtypesOf(target, true)
.filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t))
.map(type -> Tuples.of(type, FuzzyMatcher.matchScore(query, type.getFullyQualifiedName())));
}
return typesWithScoresFlux.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
.flatMapIterable(l -> l).map(t -> StsValueHint.create(sourceLinks, javaProject, t.getT1()));
}
}

View File

@@ -22,7 +22,6 @@ import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
@@ -90,7 +89,7 @@ public class LoggerNameProvider implements ValueProviderStrategy {
.map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())),
javaProject.getIndex()
.fuzzySearchTypes(query, true, false)
.map(t -> Tuples.of(StsValueHint.create(sourceLinks, t.getT1(), javaProject, Suppliers.memoize(() -> javaProject.getIndex().findType(t.getT1()))), t.getT2()))
.map(t -> Tuples.of(StsValueHint.create(sourceLinks, javaProject, t.getT1()), t.getT2()))
)
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
.flatMapIterable(l -> l)

View File

@@ -53,9 +53,11 @@ interface JavaSearchParams {
term: string;
includeBinaries: boolean;
includeSystemLibs: boolean;
timeLimit: number
}
interface JavaTypeHierarchyParams {
projectUri?: string;
fqName: string;
includeFocusType: boolean;
}

View File

@@ -55,9 +55,11 @@ interface JavaSearchParams {
term: string;
includeBinaries: boolean;
includeSystemLibs: boolean;
timeLimit: number;
}
interface JavaTypeHierarchyParams {
projectUri?: string;
fqName: string;
includeFocusType: boolean;
}