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

This commit is contained in:
Kris De Volder
2020-04-06 17:18:51 -07:00
19 changed files with 205 additions and 139 deletions

View File

@@ -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<TypeDescriptorData> 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<TypeDescriptorData> 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<TypeDescriptorData> 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<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(
@@ -185,8 +185,8 @@ public class JavaLangugeClientTest {
@Test
public void anonymousInnerType_SuperTypes() throws Exception {
List<TypeDescriptorData> 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<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(
@@ -206,8 +206,8 @@ public class JavaLangugeClientTest {
@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);
.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<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(
@@ -229,7 +229,7 @@ public class JavaLangugeClientTest {
public void taskExecutorFactoryBean_SuperTypes() throws Exception {
List<TypeDescriptorData> 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<String> actual = data.stream().map(t -> t.getFqName()).collect(Collectors.toSet());
Set<String> expected = new HashSet<>(Arrays.asList(

View File

@@ -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<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() ->
typeHierarchy.subTypes(params).collect(Collectors.toList())
);
public CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSubTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() -> typeHierarchy.subTypes(params).collect(Collectors.toList()));
}
@Override
public CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() ->
typeHierarchy.superTypes(params).collect(Collectors.toList())
);
public CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSuperTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.supplyAsync(() -> typeHierarchy.superTypes(params).collect(Collectors.toList()));
}
@Override

View File

@@ -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<IType> allSubtypesOf(String fqName, boolean includeFocusType) {
public Flux<IType> 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<IType> allSuperTypesOf(String fqName, boolean includeFocusType) {
public Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed) {
Queue<String> queue = new LinkedList<>();
HashSet<String> visited = new HashSet<>();
queue.add(fqName);

View File

@@ -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<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<Tuple2<IType, Double>> camelcaseSearchTypes(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm, boolean includeBinaries, boolean includeSystemLibs);
Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType);
Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType);
Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType, boolean detailed);
Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed);
IJavaModuleData findClasspathResourceContainer(String fqName);
}

View File

@@ -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<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> allSubtypesOf(String fqName, boolean includeFocusType) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType);
public Flux<IType> allSubtypesOf(String fqName, boolean includeFocusType, boolean detailed) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType, detailed);
try {
CompletableFuture<List<IType>> 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<IType> allSuperTypesOf(String fqName, boolean includeFocusType) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType);
public Flux<IType> allSuperTypesOf(String fqName, boolean includeFocusType, boolean detailed) {
JavaTypeHierarchyParams searchParams = new JavaTypeHierarchyParams(projectUri.toString(), fqName, includeFocusType, detailed);
try {
CompletableFuture<List<IType>> 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) {

View File

@@ -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<List<String>> javaSearchPackages(JavaSearchParams params);
@JsonRequest("sts/javaSubTypes")
CompletableFuture<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params);
@ResponseJsonAdapter(TypeHierarchyResponseAdapter.class)
CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSubTypes(JavaTypeHierarchyParams params);
@JsonRequest("sts/javaSuperTypes")
CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params);
@ResponseJsonAdapter(TypeHierarchyResponseAdapter.class)
CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSuperTypes(JavaTypeHierarchyParams params);
@JsonRequest("sts/javaCodeComplete")
CompletableFuture<List<JavaCodeCompleteData>> javaCodeComplete(JavaCodeCompleteParams params);

View File

@@ -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 <code>Either<TypeDescriptorData, TypeData></code>.
* Creates either {@link TypeData} or {@link TypeDescriptorData} based on
* {@link JsonObject} properties.
*
* @author Alex Boyko
*
*/
public class TypeHierarchyResponseAdapter implements TypeAdapterFactory {
private static final TypeToken<Either<TypeDescriptorData, TypeData>> ELEMENT_TYPE = new TypeToken<Either<TypeDescriptorData, TypeData>>() {
};
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Predicate<JsonElement> rightChecker = new PropertyChecker("classpathEntry", JsonObject.class)
.or(new PropertyChecker("bindingKey", JsonPrimitive.class));
Predicate<JsonElement> leftChecker = new PropertyChecker("fqName", JsonPrimitive.class)
.and(rightChecker.negate());
TypeAdapter<Either<TypeDescriptorData, TypeData>> elementTypeAdapter = new EitherTypeAdapter<>(gson,
ELEMENT_TYPE, leftChecker, rightChecker);
return (TypeAdapter<T>) new CollectionTypeAdapter<>(gson, ELEMENT_TYPE.getType(), elementTypeAdapter,
ArrayList::new);
}
}

View File

@@ -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;
}
}

View File

@@ -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<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", false).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", false, true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> 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<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> actual = project.getIndex().allSuperTypesOf("java.util.ArrayList", true, true).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> expected = new HashSet<>(Arrays.asList(
"java.util.ArrayList",
"java.util.List",

View File

@@ -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<List<TypeDescriptorData>> javaSubTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSubTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
@Override
public CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params) {
public CompletableFuture<List<Either<TypeDescriptorData, TypeData>>> javaSuperTypes(JavaTypeHierarchyParams params) {
return CompletableFuture.completedFuture(Collections.emptyList());
}

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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<String> 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);

View File

@@ -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<String, URI> projectLocations = new HashMap<>();
public final Queue<IJavaProject> queue = new ConcurrentLinkedQueue<>();
public final Queue<IJavaProject> builtProjectQueue = new ConcurrentLinkedQueue<>();
private final Set<IJavaProject> 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);
}

View File

@@ -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<TypeDescriptorData> subTypes(JavaTypeHierarchyParams params) {
public Stream<Either<TypeDescriptorData, TypeData>> 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<TypeDescriptorData> superTypes(JavaTypeHierarchyParams params) {
public Stream<Either<TypeDescriptorData, TypeData>> 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();
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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())));
}

View File

@@ -136,7 +136,7 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv
}
public static Stream<IMethod> 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);