Caching JDT types. Invalidate on project change
This commit is contained in:
@@ -13,20 +13,23 @@ package org.springframework.ide.vscode.commons.java;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.ide.vscode.commons.jdtls.JdtLsIndex;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
|
||||
|
||||
public class JdtLsJavaProject extends AbstractJavaProject {
|
||||
|
||||
final private STS4LanguageClient client;
|
||||
final private ProjectObserver projectObserver;
|
||||
|
||||
public JdtLsJavaProject(STS4LanguageClient client, URI uri, IClasspath classpath) {
|
||||
public JdtLsJavaProject(STS4LanguageClient client, URI uri, IClasspath classpath, ProjectObserver projectObserver) {
|
||||
super(uri, classpath);
|
||||
this.client = client;
|
||||
this.projectObserver = projectObserver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClasspathIndex createIndex() {
|
||||
return new JdtLsIndex(client, getLocationUri());
|
||||
return new JdtLsIndex(client, getLocationUri(), projectObserver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,10 +23,14 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.java.ClasspathIndex;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaModuleData;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.java.JavaUtils;
|
||||
import org.springframework.ide.vscode.commons.javadoc.JdtLsJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver.Listener;
|
||||
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.Classpath;
|
||||
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;
|
||||
@@ -46,26 +50,52 @@ import reactor.util.function.Tuples;
|
||||
|
||||
public class JdtLsIndex implements ClasspathIndex {
|
||||
|
||||
private static final long SEARCH_TIMEOUT = 700;
|
||||
final private static long SEARCH_TIMEOUT = 700;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JdtLsIndex.class);
|
||||
final private static Logger log = LoggerFactory.getLogger(JdtLsIndex.class);
|
||||
|
||||
private final STS4LanguageClient client;
|
||||
private final URI projectUri;
|
||||
private final JdtLsJavadocProvider javadocProvider;
|
||||
final private STS4LanguageClient client;
|
||||
final private URI projectUri;
|
||||
final private JdtLsJavadocProvider javadocProvider;
|
||||
final private ProjectObserver projectObserver;
|
||||
|
||||
final private Cache<String, Optional<IType>> binaryTypeCache = CacheBuilder.newBuilder().build();
|
||||
final private Cache<String, Optional<IType>> sourceTypeCache = 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) {
|
||||
final private Listener projectListener = new Listener() {
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
binaryTypeCache.invalidateAll();
|
||||
sourceTypeCache.invalidateAll();
|
||||
}
|
||||
};
|
||||
|
||||
public JdtLsIndex(STS4LanguageClient client, URI projectUri, ProjectObserver projectObserver) {
|
||||
this.client = client;
|
||||
this.projectUri = projectUri;
|
||||
this.projectObserver = projectObserver;
|
||||
this.javadocProvider = new JdtLsJavadocProvider(client, projectUri.toString());
|
||||
|
||||
this.projectObserver.addListener(projectListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
projectObserver.removeListener(projectListener);
|
||||
}
|
||||
|
||||
private IType toType(TypeData data) {
|
||||
@@ -80,25 +110,38 @@ public class JdtLsIndex implements ClasspathIndex {
|
||||
return Wrappers.wrap(data, Suppliers.memoize(() -> findType(data.getFqName())), Suppliers.memoize(() -> declaringTypeFqName == null ? null : findType(declaringTypeFqName)), javadocProvider);
|
||||
}
|
||||
|
||||
private TypeData findTypeData(String fqName) {
|
||||
JavaDataParams params = new JavaDataParams(projectUri.toString(), "L" + fqName.replace('.', '/') + ";", false);
|
||||
try {
|
||||
return client.javaType(params).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType findType(String fqName) {
|
||||
try {
|
||||
return typeCache.get(fqName, () -> {
|
||||
JavaDataParams params = new JavaDataParams(projectUri.toString(), "L" + fqName.replace('.', '/') + ";", false);
|
||||
try {
|
||||
TypeData data = client.javaType(params).get();
|
||||
if (data != null) {
|
||||
return Optional.ofNullable(toType(data));
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}).orElse(null);
|
||||
} catch (ExecutionException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
Optional<IType> type = binaryTypeCache.getIfPresent(fqName);
|
||||
if (type == null) {
|
||||
type = sourceTypeCache.getIfPresent(fqName);
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
TypeData data = findTypeData(fqName);
|
||||
if (data == null) {
|
||||
type = Optional.empty();
|
||||
sourceTypeCache.put(fqName, type);
|
||||
} else {
|
||||
type = Optional.of(toType(data));
|
||||
if (Classpath.isBinary(data.getClasspathEntry().getCpe())) {
|
||||
binaryTypeCache.put(fqName, type);
|
||||
} else {
|
||||
sourceTypeCache.put(fqName, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return type.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IPrimitiveType;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.jdtls.JdtLsIndex;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
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;
|
||||
@@ -69,7 +70,7 @@ public class JdtLsIndexTest {
|
||||
}
|
||||
}));
|
||||
// Some valid URI necessary for URI#toString() to succeed
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")), ProjectObserver.NULL);
|
||||
IType type = index.findType("java.util.Map");
|
||||
assertNotNull(type);
|
||||
assertEquals("Ljava/util/Map;", type.getBindingKey());
|
||||
@@ -91,7 +92,7 @@ public class JdtLsIndexTest {
|
||||
}
|
||||
}));
|
||||
// Some valid URI necessary for URI#toString() to succeed
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")), ProjectObserver.NULL);
|
||||
IType type = index.findType("java.util.Map");
|
||||
assertNotNull(type);
|
||||
|
||||
@@ -114,7 +115,7 @@ public class JdtLsIndexTest {
|
||||
}
|
||||
}));
|
||||
// Some valid URI necessary for URI#toString() to succeed
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")), ProjectObserver.NULL);
|
||||
IType type = index.findType("org.springframework.boot.autoconfigure.web.ServerProperties");
|
||||
assertNotNull(type);
|
||||
|
||||
@@ -138,7 +139,7 @@ public class JdtLsIndexTest {
|
||||
}
|
||||
}));
|
||||
// Some valid URI necessary for URI#toString() to succeed
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")), ProjectObserver.NULL);
|
||||
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());
|
||||
@@ -155,7 +156,7 @@ public class JdtLsIndexTest {
|
||||
}
|
||||
}));
|
||||
// Some valid URI necessary for URI#toString() to succeed
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")));
|
||||
JdtLsIndex index = new JdtLsIndex(client, URI.create(System.getProperty("java.io.tmpdir")), ProjectObserver.NULL);
|
||||
List<Tuple2<String, Double>> results = index.fuzzySearchPackages("com.e", true, false).collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())).block();
|
||||
List<String> packages = results.stream().map(t -> t.getT1()).collect(Collectors.toList());
|
||||
assertEquals(Arrays.asList("com.example", "com.another.example"), packages);
|
||||
|
||||
@@ -207,7 +207,7 @@ public class JdtLsProjectCache implements InitializableJavaProjectsService {
|
||||
IJavaProject newProject = IS_JANDEX_INDEX
|
||||
? new JavaProject(getFileObserver(), projectUri, classpath,
|
||||
JdtLsProjectCache.this)
|
||||
: new JdtLsJavaProject(server.getClient(), projectUri, classpath);
|
||||
: new JdtLsJavaProject(server.getClient(), projectUri, classpath, JdtLsProjectCache.this);
|
||||
IJavaProject oldProject = table.put(uri, newProject);
|
||||
if (oldProject != null) {
|
||||
notifyChanged(newProject);
|
||||
|
||||
Reference in New Issue
Block a user