From 3bddccd57fc05bf14912dc147ee7aa40d0dfc42e Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Thu, 2 Apr 2020 13:35:11 -0400 Subject: [PATCH 1/2] PT #171932358 Flag for detailed java type data for sub/super types --- .../commons/test/JavaLangugeClientTest.java | 24 ++++---- .../commons/STS4LanguageClientImpl.java | 15 ++--- .../commons/jandex/JandexClasspath.java | 6 +- .../vscode/commons/java/ClasspathIndex.java | 6 +- .../ide/vscode/commons/jdtls/JdtLsIndex.java | 28 ++++----- .../commons/protocol/STS4LanguageClient.java | 10 +++- .../TypeHierarchyResponseAdapter.java | 57 +++++++++++++++++++ .../java/JavaTypeHierarchyParams.java | 24 ++++++-- .../vscode/commons/maven/JavaIndexTest.java | 6 +- .../testharness/LanguageServerHarness.java | 6 +- .../META-INF/MANIFEST.MF | 3 +- .../jdt/ls/commons/java/TypeHierarchy.java | 12 ++-- .../META-INF/MANIFEST.MF | 3 +- .../autowired/AutowiredHoverProvider.java | 4 +- .../boot/metadata/ClassReferenceProvider.java | 4 +- ...ropertyNameCompletionProposalProvider.java | 2 +- 16 files changed, 140 insertions(+), 70 deletions(-) create mode 100644 headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/TypeHierarchyResponseAdapter.java diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons.test/src/org/springframework/tooling/ls/eclipse/commons/test/JavaLangugeClientTest.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons.test/src/org/springframework/tooling/ls/eclipse/commons/test/JavaLangugeClientTest.java index b7a3080a5..d608b04f9 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons.test/src/org/springframework/tooling/ls/eclipse/commons/test/JavaLangugeClientTest.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons.test/src/org/springframework/tooling/ls/eclipse/commons/test/JavaLangugeClientTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 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 @@ -144,8 +144,8 @@ public class JavaLangugeClientTest { @Test public void map_Subtypes() throws Exception { List data = client - .javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", false)) - .get(10, TimeUnit.SECONDS); + .javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", false, false)) + .get(10, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); assertTrue(data.size() > 200); assertTrue(data.stream().filter(t -> "java.util.AbstractMap".equals(t.getFqName())).findFirst().isPresent()); @@ -154,8 +154,8 @@ public class JavaLangugeClientTest { @Test public void map_Subtypes_with_Itself() throws Exception { List data = client - .javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", true)) - .get(10, TimeUnit.SECONDS); + .javaSubTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.Map", true, false)) + .get(10, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); assertTrue(data.size() > 200); assertTrue(data.stream().filter(t -> "java.util.Map".equals(t.getFqName())).findFirst().isPresent()); @@ -164,8 +164,8 @@ public class JavaLangugeClientTest { @Test public void arrayList_SuperTypes() throws Exception { List data = client - .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", false)) - .get(10, TimeUnit.SECONDS); + .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", false, false)) + .get(10, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); Set actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet()); Set expected = new HashSet<>(Arrays.asList( @@ -185,8 +185,8 @@ public class JavaLangugeClientTest { @Test public void anonymousInnerType_SuperTypes() throws Exception { List data = client - .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "org.test.Application$1", false)) - .get(1000000000, TimeUnit.SECONDS); + .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "org.test.Application$1", false, false)) + .get(1000000000, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); Set actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet()); Set expected = new HashSet<>(Arrays.asList( @@ -206,8 +206,8 @@ public class JavaLangugeClientTest { @Test public void arrayList_SuperTypes_with_Itself() throws Exception { List data = client - .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", true)) - .get(10, TimeUnit.SECONDS); + .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "java.util.ArrayList", true, false)) + .get(10, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); Set actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet()); Set expected = new HashSet<>(Arrays.asList( @@ -229,7 +229,7 @@ public class JavaLangugeClientTest { public void taskExecutorFactoryBean_SuperTypes() throws Exception { List data = client .javaSuperTypes(new JavaTypeHierarchyParams(project.getLocationURI().toString(), "org.springframework.scheduling.config.TaskExecutorFactoryBean")) - .get(10, TimeUnit.SECONDS); + .get(10, TimeUnit.SECONDS).stream().map(e -> e.getLeft()).collect(Collectors.toList()); assertNotNull(data); Set actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet()); Set expected = new HashSet<>(Arrays.asList( diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java index 416ff8192..b7285a792 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2020 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 @@ -53,6 +53,7 @@ import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; @@ -518,17 +519,13 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La } @Override - public CompletableFuture> javaSubTypes(JavaTypeHierarchyParams params) { - return CompletableFuture.supplyAsync(() -> - typeHierarchy.subTypes(params).collect(Collectors.toList()) - ); + public CompletableFuture>> javaSubTypes(JavaTypeHierarchyParams params) { + return CompletableFuture.supplyAsync(() -> typeHierarchy.subTypes(params).collect(Collectors.toList())); } @Override - public CompletableFuture> javaSuperTypes(JavaTypeHierarchyParams params) { - return CompletableFuture.supplyAsync(() -> - typeHierarchy.superTypes(params).collect(Collectors.toList()) - ); + public CompletableFuture>> javaSuperTypes(JavaTypeHierarchyParams params) { + return CompletableFuture.supplyAsync(() -> typeHierarchy.superTypes(params).collect(Collectors.toList())); } @Override diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java index 5a53065c4..daa3e59f1 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2020 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 @@ -118,7 +118,7 @@ public final class JandexClasspath implements ClasspathIndex { } @Override - public Flux allSubtypesOf(String fqName, boolean includeFocusType) { + public Flux allSubtypesOf(String fqName, boolean includeFocusType, boolean detailed) { IType type = javaIndex.get().findType(fqName); if (type == null) { return Flux.empty(); @@ -164,7 +164,7 @@ public final class JandexClasspath implements ClasspathIndex { } @Override - public Flux allSuperTypesOf(String fqName, boolean includeFocusType) { + public Flux allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed) { Queue queue = new LinkedList<>(); HashSet visited = new HashSet<>(); queue.add(fqName); diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java index 8ce62f621..86f2501c4 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2020 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 @@ -20,8 +20,8 @@ public interface ClasspathIndex extends Disposable { Flux> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs); Flux> camelcaseSearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs); Flux> fuzzySearchPackages(String searchTerm, boolean includeBinaries, boolean includeSystemLibs); - Flux allSubtypesOf(String fqName, boolean includeFocusType); - Flux allSuperTypesOf(String fqName, boolean includeFocusType); + Flux allSubtypesOf(String fqName, boolean includeFocusType, boolean detailed); + Flux allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed); IJavaModuleData findClasspathResourceContainer(String fqName); } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jdtls/JdtLsIndex.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jdtls/JdtLsIndex.java index 04a269c04..c9008c9d0 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jdtls/JdtLsIndex.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jdtls/JdtLsIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,13 +11,13 @@ 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.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -167,22 +167,13 @@ public class JdtLsIndex implements ClasspathIndex { .filter(tuple -> tuple.getT2() != 0.0); } - private List convertTypeDescriptors(List descriptors) { - List types = new ArrayList<>(descriptors.size()); - for (TypeDescriptorData data : descriptors) { - if (data != null) { - types.add(toTypeFromDescriptor(data)); - } - } - return types; - } - @Override - public Flux allSubtypesOf(String fqName, boolean includeFocusType) { - JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType); + public Flux allSubtypesOf(String fqName, boolean includeFocusType, boolean detailed) { + JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType, detailed); try { CompletableFuture> future = subtypesCache.get(searchParams, () -> client - .javaSubTypes(searchParams).handle((results, exception) -> convertTypeDescriptors(results))); + .javaSubTypes(searchParams) + .handle((results, exception) -> results.stream().map(e -> detailed ? toType(e.getRight()) : toTypeFromDescriptor(e.getLeft())).collect(Collectors.toList()))); return Mono.fromFuture(future) .flatMapMany(results -> Flux.fromIterable(results)); } catch (ExecutionException e) { @@ -192,11 +183,12 @@ public class JdtLsIndex implements ClasspathIndex { } @Override - public Flux allSuperTypesOf(String fqName, boolean includeFocusType) { - JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType); + public Flux allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed) { + JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType, detailed); try { CompletableFuture> future = supertypesCache.get(searchParams, () -> client - .javaSuperTypes(searchParams).handle((results, exception) -> convertTypeDescriptors(results))); + .javaSuperTypes(searchParams) + .handle((results, exception) -> results.stream().map(e -> detailed ? toType(e.getRight()) : toTypeFromDescriptor(e.getLeft())).collect(Collectors.toList()))); return Mono.fromFuture(future) .flatMapMany(results -> Flux.fromIterable(results)); } catch (ExecutionException e) { diff --git a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/STS4LanguageClient.java b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/STS4LanguageClient.java index 626590859..a874195ff 100644 --- a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/STS4LanguageClient.java +++ b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/STS4LanguageClient.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,6 +15,8 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.jsonrpc.json.ResponseJsonAdapter; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.jsonrpc.services.JsonNotification; import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; import org.eclipse.lsp4j.services.LanguageClient; @@ -68,10 +70,12 @@ public interface STS4LanguageClient extends LanguageClient { CompletableFuture> javaSearchPackages(JavaSearchParams params); @JsonRequest("sts/javaSubTypes") - CompletableFuture> javaSubTypes(JavaTypeHierarchyParams params); + @ResponseJsonAdapter(TypeHierarchyResponseAdapter.class) + CompletableFuture>> javaSubTypes(JavaTypeHierarchyParams params); @JsonRequest("sts/javaSuperTypes") - CompletableFuture> javaSuperTypes(JavaTypeHierarchyParams params); + @ResponseJsonAdapter(TypeHierarchyResponseAdapter.class) + CompletableFuture>> javaSuperTypes(JavaTypeHierarchyParams params); @JsonRequest("sts/javaCodeComplete") CompletableFuture> javaCodeComplete(JavaCodeCompleteParams params); diff --git a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/TypeHierarchyResponseAdapter.java b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/TypeHierarchyResponseAdapter.java new file mode 100644 index 000000000..ccfa39f86 --- /dev/null +++ b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/TypeHierarchyResponseAdapter.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2020 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.protocol; + +import java.util.ArrayList; +import java.util.function.Predicate; + +import org.eclipse.lsp4j.jsonrpc.json.adapters.CollectionTypeAdapter; +import org.eclipse.lsp4j.jsonrpc.json.adapters.EitherTypeAdapter; +import org.eclipse.lsp4j.jsonrpc.json.adapters.EitherTypeAdapter.PropertyChecker; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +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.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; + +/** + * Helps to parse JSON for Either. + * Creates either {@link TypeData} or {@link TypeDescriptorData} based on + * {@link JsonObject} properties. + * + * @author Alex Boyko + * + */ +public class TypeHierarchyResponseAdapter implements TypeAdapterFactory { + + private static final TypeToken> ELEMENT_TYPE = new TypeToken>() { + }; + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Predicate rightChecker = new PropertyChecker("classpathEntry", JsonObject.class) + .or(new PropertyChecker("bindingKey", JsonPrimitive.class)); + Predicate leftChecker = new PropertyChecker("fqName", JsonPrimitive.class) + .and(rightChecker.negate()); + TypeAdapter> elementTypeAdapter = new EitherTypeAdapter<>(gson, + ELEMENT_TYPE, leftChecker, rightChecker); + return (TypeAdapter) new CollectionTypeAdapter<>(gson, ELEMENT_TYPE.getType(), elementTypeAdapter, + ArrayList::new); + } + +} diff --git a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/java/JavaTypeHierarchyParams.java b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/java/JavaTypeHierarchyParams.java index 969c126af..ae13b9b00 100644 --- a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/java/JavaTypeHierarchyParams.java +++ b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/java/JavaTypeHierarchyParams.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,16 +15,18 @@ public class JavaTypeHierarchyParams { private String projectUri; private String fqName; private boolean includeFocusType; + private boolean detailed; - public JavaTypeHierarchyParams(String projectUri, String fqName, boolean includeFocusType) { + public JavaTypeHierarchyParams(String projectUri, String fqName, boolean includeFocusType, boolean detailed) { super(); this.projectUri = projectUri; this.fqName = fqName; + this.setDetailed(detailed); this.setIncludeFocusType(includeFocusType); } public JavaTypeHierarchyParams(String projectUri, String fqName) { - this(projectUri, fqName, false); + this(projectUri, fqName, false, false); } public String getProjectUri() { @@ -51,6 +53,17 @@ public class JavaTypeHierarchyParams { this.includeFocusType = includeFocusType; } + public boolean isDetailed() { + return detailed; + } + + public void setDetailed(boolean detailed) { + this.detailed = detailed; + } + + /** + * IMPORTANT: Do not include 'detailed' flag in the {@link #hashCode()} and {@link #equals(Object)} + */ @Override public int hashCode() { final int prime = 31; @@ -61,6 +74,9 @@ public class JavaTypeHierarchyParams { return result; } + /** + * IMPORTANT: Do not include 'detailed' flag in the {@link #hashCode()} and {@link #equals(Object)} + */ @Override public boolean equals(Object obj) { if (this == obj) @@ -84,5 +100,5 @@ public class JavaTypeHierarchyParams { return false; return true; } - + } diff --git a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java index fc19eaff9..5ec4ebc5f 100644 --- a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java +++ b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2019 Pivotal, Inc. + * Copyright (c) 2016, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -163,7 +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"); - Set actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", false).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block(); + Set actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", false, true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block(); Set expected = new HashSet<>(Arrays.asList( "java.util.List", "java.util.RandomAccess", @@ -181,7 +181,7 @@ public class JavaIndexTest { @Test public void testFindAllSuperTypesWithFocusType() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - Set actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block(); + Set actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", true, true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block(); Set expected = new HashSet<>(Arrays.asList( "java.util.ArrayList", "java.util.List", diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index 6661080ff..a82e2d6b9 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2019 Pivotal, Inc. + * Copyright (c) 2016, 2020 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 @@ -379,12 +379,12 @@ public class LanguageServerHarness { } @Override - public CompletableFuture> javaSubTypes(JavaTypeHierarchyParams params) { + public CompletableFuture>> javaSubTypes(JavaTypeHierarchyParams params) { return CompletableFuture.completedFuture(Collections.emptyList()); } @Override - public CompletableFuture> javaSuperTypes(JavaTypeHierarchyParams params) { + public CompletableFuture>> javaSuperTypes(JavaTypeHierarchyParams params) { return CompletableFuture.completedFuture(Collections.emptyList()); } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/META-INF/MANIFEST.MF b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/META-INF/MANIFEST.MF index 0777e8e77..b74740f78 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/META-INF/MANIFEST.MF +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/META-INF/MANIFEST.MF @@ -15,7 +15,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.lsp4j, org.eclipse.lsp4j.jsonrpc, io.projectreactor.reactor-core, - org.reactivestreams.reactive-streams + org.reactivestreams.reactive-streams, + com.google.gson Export-Package: org.springframework.ide.vscode.commons.protocol, org.springframework.ide.vscode.commons.protocol.java, org.springframework.tooling.jdt.ls.commons, diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/TypeHierarchy.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/TypeHierarchy.java index faa939346..d2fc25a23 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/TypeHierarchy.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/java/TypeHierarchy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -17,7 +17,9 @@ 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.eclipse.lsp4j.jsonrpc.messages.Either; 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.resources.ResourceUtils; @@ -61,26 +63,26 @@ public class TypeHierarchy { return null; } - public Stream subTypes(JavaTypeHierarchyParams params) { + public Stream> subTypes(JavaTypeHierarchyParams params) { URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri()); ITypeHierarchy hierarchy = hierarchy(projectUri, params.getFqName(), false); if (hierarchy != null) { IType focusType = hierarchy.getType(); return Stream.concat(params.isIncludeFocusType() ? Stream.of(focusType) : Stream.empty(), Stream.of(hierarchy.getAllSubtypes(focusType))) .parallel() - .map(javaData::createTypeDescriptorData); + .map(type -> params.isDetailed() ? Either.forRight(javaData.createTypeData(type)) : Either.forLeft(javaData.createTypeDescriptorData(type))); } return Stream.of(); } - public Stream superTypes(JavaTypeHierarchyParams params) { + public Stream> superTypes(JavaTypeHierarchyParams params) { URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri()); ITypeHierarchy hierarchy = hierarchy(projectUri, params.getFqName(), true); if (hierarchy != null) { IType focusType = hierarchy.getType(); return Stream.concat(params.isIncludeFocusType() ? Stream.of(focusType) : Stream.empty(), Stream.of(hierarchy.getAllSupertypes(focusType))) .parallel() - .map(javaData::createTypeDescriptorData); + .map(type -> params.isDetailed() ? Either.forRight(javaData.createTypeData(type)) : Either.forLeft(javaData.createTypeDescriptorData(type))); } return Stream.of(); } diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/META-INF/MANIFEST.MF b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/META-INF/MANIFEST.MF index d3d17929f..6fc2f24ab 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/META-INF/MANIFEST.MF +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.extension/META-INF/MANIFEST.MF @@ -12,4 +12,5 @@ Require-Bundle: org.eclipse.jdt.ls.core, org.springframework.tooling.jdt.ls.commons, com.google.guava, com.google.gson, - org.eclipse.lsp4j + org.eclipse.lsp4j, + org.eclipse.lsp4j.jsonrpc diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java index 00e65fd17..af3c103e3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2020 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 @@ -269,7 +269,7 @@ 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) { - return jp.getIndex().allSuperTypesOf(liveBeanTypeFQName, true).map(IType::getFullyQualifiedName) + return jp.getIndex().allSuperTypesOf(liveBeanTypeFQName, true, false).map(IType::getFullyQualifiedName) .filter(fqn -> bindingQualifiedName.equals(fqn)).blockFirst() != null; } return false; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java index 6cf9fcec8..545dfc03f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2019 Pivotal, Inc. + * Copyright (c) 2016, 2020 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 @@ -141,7 +141,7 @@ public class ClassReferenceProvider extends CachingValueProvider { if (target == null) { typesWithScoresFlux = javaProject.getIndex().fuzzySearchTypes(query, true, false); } else { - typesWithScoresFlux = javaProject.getIndex().allSubtypesOf(target, true) + typesWithScoresFlux = javaProject.getIndex().allSubtypesOf(target, true, false) .filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t)) .map(type -> Tuples.of(type, FuzzyMatcher.matchScore(query, type.getFullyQualifiedName()))); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java index 06bf8a3c2..a1c6a2784 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java @@ -136,7 +136,7 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv } public static Stream propertyNameCandidateMethods(IJavaProject project, String beanClassFqName) { - return project.getIndex().allSuperTypesOf(beanClassFqName, true) + return project.getIndex().allSuperTypesOf(beanClassFqName, true, true) .toStream() .flatMap(type -> type.getMethods()) .filter(PropertyNameCompletionProposalProvider::isPropertyWriteMethod); From db9b41a193e4db336132b22f1a27fee0b861d915 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Fri, 3 Apr 2020 16:59:13 -0400 Subject: [PATCH 2/2] PT #172125155 Rework CP notifying mechanics for projects missing JARs --- .../classpath/ClasspathListenerManager.java | 92 +++++++++++++------ .../ReusableClasspathListenerHandler.java | 21 +---- .../SendClasspathNotificationsJob.java | 21 +---- 3 files changed, 65 insertions(+), 69 deletions(-) diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java index 56b412b1b..583cfaf20 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ClasspathListenerManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,11 +13,8 @@ package org.springframework.tooling.jdt.ls.commons.classpath; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResourceChangeEvent; -import org.eclipse.core.resources.IResourceChangeListener; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -27,6 +24,7 @@ import org.eclipse.jdt.core.IElementChangedListener; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaElementDelta; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.springframework.tooling.jdt.ls.commons.Logger; @@ -75,8 +73,14 @@ public class ClasspathListenerManager { visitChildren(delta); break; case IJavaElement.JAVA_PROJECT: - if (isCreatedOrDeleted(delta) || isClasspathChanged(delta.getFlags())) { - listener.classpathChanged((IJavaProject)el); + IJavaProject jp = (IJavaProject)el; + if (isCreatedOrDeleted(delta) + || isClasspathChanged(delta.getFlags()) + // Classpath unchanged but maven/gradle repo cache has JAR's removed or downloaded + // See individual method comments for more details + || isClasspathManifestFileChanged(jp, delta) + || areClasspathJarsChanged(delta)) { + listener.classpathChanged(jp); } break; default: @@ -84,6 +88,56 @@ public class ClasspathListenerManager { } } + /** + * Checks if any classpath JARs have been added/removed/content changed + * For the case when classpath stays the same while some classpath JARs are missing from maven/gradle repo cache. + * This handles Gradle case completely and partially handles Maven case + * @param delta + * @return + */ + private boolean areClasspathJarsChanged(IJavaElementDelta delta) { + for (IJavaElementDelta childDelta : delta.getAffectedChildren()) { + if (childDelta.getElement() instanceof IPackageFragmentRoot) { + IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) childDelta.getElement(); + if (pkgRoot.isArchive()) { + return true; + } + } + } + return false; + } + + /** + * When Maven project update is completed .classpath file content changed is one + * of the resource delta's expected. + * + * If maven cache JARs hav ebeen removed and then maven project update performed + * the following events sent: 1. JAR files removed 2. Once classpath is ready + * and downloaded .classpath file content changed comes in + * + * Next update of the same project will result in the following 1. JAR files + * added 2. Immidiately after .classpath file content changed + * + * Looks like M2E does a "refresh" before updating which is good, but no refresh + * after which is bad and hence JAR files added event come next Maven Update and + * we are forced to watch for .classpath content changed. + * + * @param jp + * @param delta + * @return + */ + private boolean isClasspathManifestFileChanged(IJavaProject jp, IJavaElementDelta delta) { + if (delta.getResourceDeltas() != null && (delta.getFlags() & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_CHILDREN)) != 0) { + IFile classpathFile = jp.getProject().getFile(IJavaProject.CLASSPATH_FILE_NAME); + for (IResourceDelta resourceDelta : delta.getResourceDeltas()) { + if (classpathFile.equals(resourceDelta.getResource())) { + return true; + } + } + } + return false; + } + private boolean isCreatedOrDeleted(IJavaElementDelta delta) { int kind = delta.getKind(); return kind == IJavaElementDelta.ADDED || kind==IJavaElementDelta.REMOVED; @@ -109,38 +163,18 @@ public class ClasspathListenerManager { private MyListener myListener; private final Logger logger; - private IResourceChangeListener workspaceListener = (event) -> { - if (event.getSource() instanceof IProject) { - projectBuilt((IProject) event.getSource()); - } else if (event.getSource() instanceof IWorkspace) { - for (IProject p : ((IWorkspace)event.getSource()).getRoot().getProjects()) { - projectBuilt(p); - } - } - }; - public ClasspathListenerManager(Logger logger, ClasspathListener listener) { this.logger = logger; - logger.log("Setting up ClasspathListenerManager"); + this.logger.log("Setting up ClasspathListenerManager"); this.listener = listener; JavaCore.addElementChangedListener(myListener=new MyListener(), ElementChangedEvent.POST_CHANGE); - final IWorkspace workspace = ResourcesPlugin.getWorkspace(); - workspace.addResourceChangeListener(workspaceListener, IResourceChangeEvent.POST_BUILD); } - private void projectBuilt(IProject project) { - IJavaProject jp = JavaCore.create(project); - if (jp != null) { - listener.projectBuilt(jp); - } - } - public void dispose() { if (myListener!=null) { JavaCore.removeElementChangedListener(myListener); myListener = null; } - ResourcesPlugin.getWorkspace().removeResourceChangeListener(workspaceListener); } } \ No newline at end of file diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java index afdd40c6e..c9fee3148 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/ReusableClasspathListenerHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2020 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 @@ -99,25 +99,15 @@ public class ReusableClasspathListenerHandler { public void subscribe(String callbackCommandId, boolean isBatched) { // keep out of synchronized block to avoid workspace locks - logger.log("Sorting projects..."); IProject[] sortedProjects = getSortedProjects(); - logger.log("Sorting projects... DONE"); synchronized(this) { - logger.log("inside synchronized Subscriptions"); if (!subscribers.containsKey(callbackCommandId)) { - logger.log("subscribing to classpath changes: " + callbackCommandId +" isBatched = "+isBatched); classpathListener = new ClasspathListenerManager(logger, new ClasspathListener() { @Override public void classpathChanged(IJavaProject jp) { sendNotification(jp, subscribers.keySet()); } - - @Override - public void projectBuilt(IJavaProject jp) { - sendNotificationOnProjectBuilt(jp, subscribers.keySet()); - } - }); final SendClasspathNotificationsJob job = new SendClasspathNotificationsJob(logger, conn, callbackCommandId, isBatched); subscribers.put(callbackCommandId, job); @@ -132,7 +122,6 @@ public class ReusableClasspathListenerHandler { } }); - logger.log("subsribers = " + subscribers); sendInitialEvents(callbackCommandId, sortedProjects); } } @@ -177,14 +166,6 @@ public class ReusableClasspathListenerHandler { } } - private synchronized void sendNotificationOnProjectBuilt(IJavaProject jp, Collection callbackIds) { - for (String callbackId : callbackIds) { - SendClasspathNotificationsJob sendNotificationJob = subscribers.get(callbackId); - sendNotificationJob.builtProjectQueue.add(jp); - sendNotificationJob.schedule(); - } - } - public synchronized void unsubscribe(String callbackCommandId) { logger.log("unsubscribing from classpath changes: " + callbackCommandId); subscribers.remove(callbackCommandId); diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/SendClasspathNotificationsJob.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/SendClasspathNotificationsJob.java index 609f47251..b1e0e5df0 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/SendClasspathNotificationsJob.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons/src/org/springframework/tooling/jdt/ls/commons/classpath/SendClasspathNotificationsJob.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2020 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -14,11 +14,9 @@ import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; @@ -55,9 +53,6 @@ public class SendClasspathNotificationsJob extends Job { */ private Map projectLocations = new HashMap<>(); public final Queue queue = new ConcurrentLinkedQueue<>(); - public final Queue builtProjectQueue = new ConcurrentLinkedQueue<>(); - - private final Set notReadyProjects = new HashSet<>(); public SendClasspathNotificationsJob(Logger logger, ClientCommandExecutor conn, String callbackId, boolean isBatched) { super("Send Classpath Notifications"); @@ -109,19 +104,9 @@ public class SendClasspathNotificationsJob extends Job { notificationsSentForProjects = null; synchronized (projectLocations) { //Could use some Eclipse job rule. But its really a bit of a PITA to create the right one. try { - // Try to see if classpath needs to be sent for the projects that have been - // built since classpath JAR may not have existed (not downloaded) at the time - // of classpath changed event - for (IJavaProject jp = builtProjectQueue.poll(); jp!=null; jp = builtProjectQueue.poll()) { - if (notReadyProjects.remove(jp)) { - queue.add(jp); - } - } for (IJavaProject jp = queue.poll(); jp!=null; jp = queue.poll()) { - logger.log("Preparing classpath changed notification " + jp.getElementName()); // Project wasn't ready before but now it's about to be processed for Classpath again. // Remove it from the set of not readt projects - notReadyProjects.remove(jp); URI projectLoc = getProjectLocation(jp); if (projectLoc==null) { logger.log("Could not send event for project because no project location: "+jp.getElementName()); @@ -138,8 +123,6 @@ public class SendClasspathNotificationsJob extends Job { Classpath classpath = Classpath.EMPTY; if (deleted) { - // Project has been removed no need to keep in not ready projects set - notReadyProjects.remove(jp); // projectLocations.remove(projectName); } else { projectLocations.put(projectName, projectLoc); @@ -153,8 +136,6 @@ public class SendClasspathNotificationsJob extends Job { } } if (filteredCPEs.size() != classpath.getEntries().size()) { - // If some entries in the classpath don't exist yet add the project to not ready projects set to process later when project is built - notReadyProjects.add(jp); // Only send effective classpath that has all entries physically present. classpath = new Classpath(filteredCPEs); }