Refactor, fix and simplify classpath infrastructure
This commit is contained in:
@@ -11,58 +11,73 @@
|
||||
package org.springframework.ide.vscode.commons.jandex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.ClasspathIndex;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.javadoc.JavaDocProviders;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.Disposable;
|
||||
import reactor.core.Disposables;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Classpath with Jandex Java index for searching types
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public abstract class JandexClasspath implements IClasspath {
|
||||
|
||||
public final class JandexClasspath implements ClasspathIndex {
|
||||
|
||||
public static JavadocProviderTypes providerType = JavadocProviderTypes.HTML;
|
||||
|
||||
|
||||
public enum JavadocProviderTypes {
|
||||
// JAVA_PARSER, //Used to be based on githb java parser. If need something back that can extract docs from source code, we have to implement
|
||||
// based on JDT parser. But at the moment this wasn't being used so just got removed.
|
||||
HTML
|
||||
}
|
||||
|
||||
|
||||
private Supplier<JandexIndex> javaIndex;
|
||||
|
||||
public JandexClasspath() {
|
||||
private final IClasspath classpath;
|
||||
private final FileObserver fileObserver;
|
||||
|
||||
public JandexClasspath(IClasspath classpath, FileObserver fileObserver) {
|
||||
this.fileObserver = fileObserver;
|
||||
this.classpath = classpath;
|
||||
this.javaIndex = Suppliers.synchronizedSupplier(Suppliers.memoize(() -> createIndex()));
|
||||
}
|
||||
|
||||
|
||||
protected JandexIndex createIndex() {
|
||||
Collection<Path> classpathEntries = ImmutableList.of();
|
||||
attachFolderListeners();
|
||||
Collection<File> classpathEntries = ImmutableList.of();
|
||||
try {
|
||||
classpathEntries = getClasspathEntryPaths();
|
||||
for (Path path : classpathEntries) {
|
||||
System.out.println(path);
|
||||
}
|
||||
classpathEntries = IClasspathUtil.getBinaryRoots(classpath);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return new JandexIndex(classpathEntries.stream().map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> {
|
||||
return new JandexIndex(classpathEntries, jarFile -> findIndexFile(jarFile), classpathResource -> {
|
||||
switch (providerType) {
|
||||
// case JAVA_PARSER:
|
||||
// return createParserJavadocProvider(classpathResource);
|
||||
@@ -73,23 +88,63 @@ public abstract class JandexClasspath implements IClasspath {
|
||||
}
|
||||
}, getBaseIndices());
|
||||
}
|
||||
|
||||
|
||||
private Disposable.Composite subscriptions = Disposables.composite();
|
||||
|
||||
private void attachFolderListeners() {
|
||||
synchronized (this) {
|
||||
subscriptions.dispose();
|
||||
subscriptions = Disposables.composite();
|
||||
}
|
||||
for (File cpe : IClasspathUtil.getBinaryRoots(classpath)) {
|
||||
if (!cpe.toString().endsWith(".jar")) {
|
||||
final List<String> rebuildGlobPattern = Arrays.asList(cpe.toString().replace(File.separator, "/") + "/**/*.class");
|
||||
Disposable disposable = fileObserver.onAnyChange(rebuildGlobPattern, (uri) -> reindex());
|
||||
subscriptions.add(disposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Composite toDispose = subscriptions;
|
||||
subscriptions = null;
|
||||
if (toDispose!=null) {
|
||||
toDispose.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private IJavadocProvider createHtmlJavdocProvider(File binaryClasspathRoot) {
|
||||
CPE cpe = IClasspathUtil.findEntryForBinaryRoot(classpath, binaryClasspathRoot);
|
||||
return JavaDocProviders.createFor(cpe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> sourceContainer(File binaryClasspathRoot) {
|
||||
CPE cpe = IClasspathUtil.findEntryForBinaryRoot(classpath, binaryClasspathRoot);
|
||||
return cpe == null ? Optional.empty() : Optional.ofNullable(cpe.getSourceContainerUrl());
|
||||
}
|
||||
|
||||
protected JandexIndex[] getBaseIndices() {
|
||||
return new JandexIndex[0];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IType findType(String fqName) {
|
||||
return javaIndex.get().findType(fqName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
|
||||
return javaIndex.get().fuzzySearchTypes(searchTerm, typeFilter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm) {
|
||||
return javaIndex.get().fuzzySearchPackages(searchTerm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
return javaIndex.get().allSubtypesOf(type);
|
||||
}
|
||||
@@ -101,21 +156,35 @@ public abstract class JandexClasspath implements IClasspath {
|
||||
}
|
||||
return new File(indexFolder.toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx");
|
||||
}
|
||||
|
||||
|
||||
protected File getIndexFolder() {
|
||||
return JandexIndex.getIndexFolder();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<File> findClasspathResourceContainer(String fqName) {
|
||||
return javaIndex.get().findClasspathResourceForType(fqName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reindex() {
|
||||
|
||||
private void reindex() {
|
||||
this.javaIndex = Suppliers.synchronizedSupplier(Suppliers.memoize(() -> createIndex()));
|
||||
}
|
||||
|
||||
abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource);
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getClasspathResources() {
|
||||
return IClasspathUtil.getSourceFolders(classpath)
|
||||
.flatMap(folder -> {
|
||||
try {
|
||||
return Files.walk(folder.toPath())
|
||||
.filter(path -> Files.isRegularFile(path))
|
||||
.map(path -> folder.toPath().relativize(path))
|
||||
.map(relativePath -> relativePath.toString())
|
||||
.filter(pathString -> !pathString.endsWith(".java") && !pathString.endsWith(".class"));
|
||||
} catch (IOException e) {
|
||||
return Stream.empty();
|
||||
}
|
||||
})
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,19 +10,23 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
|
||||
/**
|
||||
* Abstract java project. Has a folder to store some project calculated data to speed up access
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJavaProject implements IJavaProject {
|
||||
|
||||
public abstract class AbstractJavaProject extends JavaProject {
|
||||
|
||||
final protected Path projectDataCache;
|
||||
|
||||
public AbstractJavaProject(Path projectDataCache) {
|
||||
|
||||
public AbstractJavaProject(FileObserver fileObserver, URI loactionUri, Path projectDataCache, IClasspath classpath) {
|
||||
super(fileObserver, loactionUri, classpath);
|
||||
this.projectDataCache = projectDataCache;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
@@ -20,7 +21,7 @@ public class BootProjectUtil {
|
||||
try {
|
||||
IClasspath cp = jp.getClasspath();
|
||||
if (cp!=null) {
|
||||
return cp.getClasspathEntryPaths().stream().anyMatch(cpe -> isBootEntry(cpe));
|
||||
return IClasspathUtil.getBinaryRoots(cp).stream().anyMatch(cpe -> isBootEntry(cpe));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
@@ -28,8 +29,8 @@ public class BootProjectUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isBootEntry(Path cpe) {
|
||||
String name = cpe.getFileName().toString();
|
||||
private static boolean isBootEntry(File cpe) {
|
||||
String name = cpe.getName();
|
||||
return name.endsWith(".jar") && name.startsWith("spring-boot");
|
||||
}
|
||||
|
||||
|
||||
@@ -10,39 +10,50 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
public class ClasspathData {
|
||||
public class ClasspathData implements IClasspath {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ClasspathData.class);
|
||||
|
||||
final public static ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(
|
||||
null,
|
||||
Collections.emptySet()
|
||||
);
|
||||
|
||||
final public static ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(),
|
||||
Collections.emptySet(), null);
|
||||
|
||||
private String name;
|
||||
private Set<CPE> classpathEntries;
|
||||
private Set<String> classpathResources;
|
||||
private String outputFolder;
|
||||
|
||||
public ClasspathData() {
|
||||
}
|
||||
public ClasspathData() {}
|
||||
|
||||
public ClasspathData(String name, Set<CPE> classpathEntries, Set<String> classpathResources, String outputFolder) {
|
||||
public ClasspathData(String name, Collection<CPE> classpathEntries) {
|
||||
this.name = name;
|
||||
this.classpathEntries = classpathEntries;
|
||||
this.classpathResources = classpathResources;
|
||||
this.outputFolder = outputFolder;
|
||||
this.classpathEntries = ImmutableSet.copyOf(classpathEntries);
|
||||
}
|
||||
|
||||
|
||||
public static ClasspathData from(IClasspath d) {
|
||||
Collection<CPE> entries = null;
|
||||
try {
|
||||
entries = d.getClasspathEntries();
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return new ClasspathData(
|
||||
d.getName(),
|
||||
entries==null ? ImmutableSet.of() : entries
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -51,6 +62,7 @@ public class ClasspathData {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CPE> getClasspathEntries() {
|
||||
return classpathEntries;
|
||||
}
|
||||
@@ -59,47 +71,38 @@ public class ClasspathData {
|
||||
this.classpathEntries = classpathEntries;
|
||||
}
|
||||
|
||||
public Set<String> getClasspathResources() {
|
||||
return classpathResources;
|
||||
}
|
||||
|
||||
public void setClasspathResources(Set<String> classpathResources) {
|
||||
this.classpathResources = classpathResources;
|
||||
}
|
||||
|
||||
public String getOutputFolder() {
|
||||
return outputFolder;
|
||||
}
|
||||
|
||||
public void setOutputFolder(String outputFolder) {
|
||||
this.outputFolder = outputFolder;
|
||||
}
|
||||
|
||||
public static ClasspathData getEmptyClasspathData() {
|
||||
return EMPTY_CLASSPATH_DATA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ClasspathData) {
|
||||
ClasspathData other = (ClasspathData) obj;
|
||||
try {
|
||||
return Objects.equal(name, other.name) && Objects.equal(classpathEntries, other.classpathEntries)
|
||||
&& Objects.equal(classpathResources, other.classpathResources)
|
||||
&& Objects.equal(outputFolder, outputFolder);
|
||||
} catch (Throwable t) {
|
||||
Log.log(t);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((classpathEntries == null) ? 0 : classpathEntries.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ClasspathData from(String name, Collection<CPE> classpathEntries,
|
||||
Collection<String> classpathResources, Path outputFolder) {
|
||||
return new ClasspathData(name,
|
||||
new LinkedHashSet<>(classpathEntries),
|
||||
new LinkedHashSet<>(classpathResources),
|
||||
outputFolder==null ? null : outputFolder.toString()
|
||||
);
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ClasspathData other = (ClasspathData) obj;
|
||||
if (classpathEntries == null) {
|
||||
if (other.classpathEntries != null)
|
||||
return false;
|
||||
} else if (!classpathEntries.equals(other.classpathEntries))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -11,32 +11,22 @@
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class ClasspathFileBasedCache {
|
||||
|
||||
|
||||
public static final ClasspathFileBasedCache NULL = new ClasspathFileBasedCache(null);
|
||||
|
||||
|
||||
public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json";
|
||||
|
||||
private static final String OUTPUT_FOLDER_PROPERTY = "outputFolder";
|
||||
private static final String CLASSPATH_RESOURCES_PROPERTY = "classpathResources";
|
||||
private static final String CLASSPATH_ENTRIES_PROPERTY = "classpathEntries";
|
||||
private static final String NAME_PROPERTY = "name";
|
||||
|
||||
final private File file;
|
||||
|
||||
|
||||
public ClasspathFileBasedCache(File file) {
|
||||
super();
|
||||
this.file = file;
|
||||
@@ -63,7 +53,7 @@ public class ClasspathFileBasedCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isCached() {
|
||||
return file != null && file.exists();
|
||||
}
|
||||
@@ -80,7 +70,7 @@ public class ClasspathFileBasedCache {
|
||||
return ClasspathData.EMPTY_CLASSPATH_DATA;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void delete() {
|
||||
if (file != null && file.exists()) {
|
||||
file.delete();
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.Disposable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
public interface ClasspathIndex extends Disposable {
|
||||
|
||||
IType findType(String fqName);
|
||||
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter);
|
||||
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
|
||||
Flux<IType> allSubtypesOf(IType type);
|
||||
Optional<File> findClasspathResourceContainer(String fqName);
|
||||
|
||||
//Maybe the stuff below is another interface? Something that provides operations
|
||||
// on classpaths?
|
||||
|
||||
Optional<URL> sourceContainer(File binaryClasspathRoot);
|
||||
|
||||
/**
|
||||
* Classpath resources paths relative to the source folder path
|
||||
* @return classpath resource relative paths
|
||||
*/
|
||||
ImmutableList<String> getClasspathResources();
|
||||
|
||||
|
||||
}
|
||||
@@ -10,14 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
@@ -25,44 +19,41 @@ import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This wrapper around a classpath manages classpath data from and to a file-based cache (e.g. ".sts4-cache/classpath-data.json") with classpath data obtained
|
||||
* from a project (e.g., maven or gradle project) through an "update" operation.
|
||||
*
|
||||
* from a project (e.g., maven or gradle project) through an "update" operation.
|
||||
*
|
||||
* The cached classpath data is written to the file and loaded from it when instance of this classpath is created
|
||||
*
|
||||
*
|
||||
* NOTE: Classpath data may not be available until an actual update is requested on this wrapper.
|
||||
*
|
||||
*
|
||||
* As the wrapper is a classpath itself ,it delegates to the underlying classpath for classpath operations (e.g. getting classpath entries, resources, etc..). However, the data may not
|
||||
* be available until update is performed.
|
||||
*
|
||||
*
|
||||
* The wrapper caches some of classpath data such as
|
||||
* <li> Classpath entries </li>
|
||||
* <li> Classpath resources </li>
|
||||
* <li> Output folder </li>
|
||||
* <li> Projects' name </li>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Implementation is somewhat experimental at the moment...
|
||||
*
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
* @param <T> a subclass of {@link IClasspath} the delegated to classpath created from current data
|
||||
*/
|
||||
public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspath {
|
||||
|
||||
public class DelegatingCachedClasspath implements IClasspath {
|
||||
|
||||
private AtomicReference<ClasspathData> cachedData;
|
||||
private Callable<T> classpathCreator;
|
||||
private AtomicReference<T> cachedClasspath;
|
||||
private Callable<IClasspath> classpathCreator;
|
||||
private AtomicReference<IClasspath> cachedClasspath;
|
||||
|
||||
private final ClasspathFileBasedCache fileBasedCache;
|
||||
|
||||
|
||||
public DelegatingCachedClasspath(Callable<T> delegateCreator, ClasspathFileBasedCache fileCache) {
|
||||
|
||||
|
||||
public DelegatingCachedClasspath(Callable<IClasspath> delegateCreator, ClasspathFileBasedCache fileCache) {
|
||||
super();
|
||||
Assert.isLegal(delegateCreator != null);
|
||||
this.fileBasedCache = fileCache != null ? fileCache : ClasspathFileBasedCache.NULL;
|
||||
@@ -74,8 +65,8 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
|
||||
private ClasspathData loadFileBasedCache(ClasspathFileBasedCache fileCache) {
|
||||
return fileCache != null ? fileCache.load() : ClasspathData.EMPTY_CLASSPATH_DATA;
|
||||
}
|
||||
|
||||
public T delegate() {
|
||||
|
||||
public IClasspath delegate() {
|
||||
return cachedClasspath.get();
|
||||
}
|
||||
|
||||
@@ -84,26 +75,15 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
|
||||
return cachedData.get().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getOutputFolder() {
|
||||
String of = cachedData.get().getOutputFolder();
|
||||
return of == null ? null : Paths.get(of);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<CPE> getClasspathEntries() throws Exception {
|
||||
return ImmutableList.copyOf(cachedData.get().getClasspathEntries());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getClasspathResources() {
|
||||
return ImmutableList.copyOf(cachedData.get().getClasspathResources());
|
||||
}
|
||||
|
||||
public boolean isCached() {
|
||||
return fileBasedCache.isCached();
|
||||
}
|
||||
|
||||
|
||||
public boolean update() throws Exception {
|
||||
try {
|
||||
final ClasspathData newData = createClasspathData();
|
||||
@@ -119,74 +99,20 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
T t = cachedClasspath.get();
|
||||
return t != null && t.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType findType(String fqName) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? null : t.findType(fqName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? Flux.empty() : t.fuzzySearchTypes(searchTerm, typeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? Flux.empty() : t.fuzzySearchPackages(searchTerm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? Flux.empty() : t.allSubtypesOf(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClasspathData createClasspathData() throws Exception {
|
||||
T newDelegate = classpathCreator.call();
|
||||
private ClasspathData createClasspathData() throws Exception {
|
||||
IClasspath newDelegate = classpathCreator.call();
|
||||
cachedClasspath.set(newDelegate);
|
||||
if (newDelegate != null) {
|
||||
ClasspathData data = newDelegate.createClasspathData();
|
||||
ClasspathData data = createClasspathData(newDelegate);
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ClasspathData.EMPTY_CLASSPATH_DATA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getSourceFolders() {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? ImmutableList.of() : t.getSourceFolders();
|
||||
private ClasspathData createClasspathData(IClasspath d) {
|
||||
return ClasspathData.from(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<File> findClasspathResourceContainer(String fqName) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? Optional.empty() : t.findClasspathResourceContainer(fqName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reindex() {
|
||||
T t = cachedClasspath.get();
|
||||
if (t != null) {
|
||||
t.reindex();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> sourceContainer(File classpathResource) {
|
||||
T t = cachedClasspath.get();
|
||||
return t == null ? Optional.empty() : t.sourceContainer(classpathResource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,88 +10,30 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Classpath for a Java artifact
|
||||
*
|
||||
*
|
||||
* @author Kris De Volder
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public interface IClasspath {
|
||||
|
||||
String getName();
|
||||
|
||||
boolean exists();
|
||||
|
||||
IType findType(String fqName);
|
||||
|
||||
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter);
|
||||
|
||||
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
|
||||
|
||||
Flux<IType> allSubtypesOf(IType type);
|
||||
|
||||
Path getOutputFolder();
|
||||
|
||||
public static final Logger log = LoggerFactory.getLogger(IClasspath.class);
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Classpath entries paths
|
||||
*
|
||||
*
|
||||
* @return collection of classpath entries in a form file/folder paths
|
||||
* @throws Exception
|
||||
*/
|
||||
Collection<CPE> getClasspathEntries() throws Exception;
|
||||
|
||||
/**
|
||||
* Classpath resources paths relative to the source folder path
|
||||
* @return classpath resource relative paths
|
||||
*/
|
||||
ImmutableList<String> getClasspathResources();
|
||||
|
||||
ImmutableList<String> getSourceFolders();
|
||||
|
||||
Optional<File> findClasspathResourceContainer(String fqName);
|
||||
|
||||
ClasspathData createClasspathData() throws Exception;
|
||||
|
||||
void reindex();
|
||||
|
||||
Optional<URL> sourceContainer(File classpathResource);
|
||||
|
||||
@Deprecated
|
||||
default Collection<Path> getClasspathEntryPaths() throws Exception {
|
||||
LinkedHashSet<Path> entries = new LinkedHashSet<>();
|
||||
for (CPE cpe : this.getClasspathEntries()) {
|
||||
if (Classpath.ENTRY_KIND_BINARY.equals(cpe.getKind())) {
|
||||
entries.add(Paths.get(cpe.getPath()));
|
||||
} else if (Classpath.ENTRY_KIND_SOURCE.equals(cpe.getKind())) {
|
||||
String of = cpe.getOutputFolder();
|
||||
if (of!=null) {
|
||||
entries.add(Paths.get(cpe.getOutputFolder()));
|
||||
} else {
|
||||
Path op = getOutputFolder();
|
||||
if (op!=null) {
|
||||
entries.add(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ImmutableList.copyOf(entries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class IClasspathUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(IClasspath.class);
|
||||
|
||||
public static CPE findEntryForBinaryRoot(IClasspath cp, File binaryClasspathtRoot) {
|
||||
try {
|
||||
for (CPE cpe : cp.getClasspathEntries()) {
|
||||
if (correspondsToBinaryLocation(cpe, binaryClasspathtRoot)) {
|
||||
return cpe;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<File> getBinaryRoots(IClasspath cp) {
|
||||
ImmutableList.Builder<File> roots = ImmutableList.builder();
|
||||
try {
|
||||
for (CPE cpe : cp.getClasspathEntries()) {
|
||||
File loc = binaryLocation(cpe);
|
||||
if (loc!=null) {
|
||||
roots.add(loc);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return roots.build();
|
||||
}
|
||||
|
||||
private static boolean correspondsToBinaryLocation(CPE cpe, File classpathEntryFile) {
|
||||
classpathEntryFile = canonicalFile(classpathEntryFile);
|
||||
File canonicalFile = binaryLocation(cpe);
|
||||
return Objects.equals(canonicalFile, classpathEntryFile);
|
||||
}
|
||||
|
||||
private static File binaryLocation(CPE cpe) {
|
||||
switch (cpe.getKind()) {
|
||||
case Classpath.ENTRY_KIND_BINARY:
|
||||
return canonicalFile(cpe.getPath());
|
||||
case Classpath.ENTRY_KIND_SOURCE:
|
||||
return canonicalFile(cpe.getOutputFolder());
|
||||
default:
|
||||
throw new IllegalStateException("Missing switch case?");
|
||||
}
|
||||
}
|
||||
|
||||
private static File canonicalFile(String _f) {
|
||||
if (_f!=null) {
|
||||
File f = new File(_f);
|
||||
return canonicalFile(f);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static File canonicalFile(File f) {
|
||||
try {
|
||||
return f.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
return f.getAbsoluteFile();
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<File> getSourceFolders(IClasspath classpath) {
|
||||
try {
|
||||
if (classpath != null) {
|
||||
return classpath.getClasspathEntries().stream().filter(Classpath::isSource)
|
||||
.map(cpe -> new File(cpe.getPath()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
public static Stream<File> getOutputFolders(IClasspath classpath) {
|
||||
try {
|
||||
return classpath.getClasspathEntries().stream()
|
||||
.filter(Classpath::isSource)
|
||||
.map(cpe -> new File(cpe.getOutputFolder()));
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
@@ -10,27 +10,57 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
public interface IJavaProject extends IJavaElement {
|
||||
|
||||
|
||||
final static String PROJECT_CACHE_FOLDER = ".sts4-cache";
|
||||
|
||||
|
||||
IClasspath getClasspath();
|
||||
ClasspathIndex getIndex();
|
||||
|
||||
@Override
|
||||
default String getElementName() {
|
||||
return getClasspath().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default IJavadoc getJavaDoc() {
|
||||
return null;
|
||||
default IType findType(String fqName) {
|
||||
return getIndex().findType(fqName);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean exists() {
|
||||
return getClasspath().exists();
|
||||
default Flux<IType> allSubtypesOf(IType targetType) {
|
||||
return getIndex().allSubtypesOf(targetType);
|
||||
}
|
||||
|
||||
default Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
|
||||
return getIndex().fuzzySearchTypes(searchTerm, typeFilter);
|
||||
}
|
||||
|
||||
default Optional<URL> sourceContainer(File classpathResource) {
|
||||
return getIndex().sourceContainer(classpathResource);
|
||||
}
|
||||
|
||||
default List<String> getClasspathResources() {
|
||||
return getIndex().getClasspathResources();
|
||||
}
|
||||
|
||||
default Optional<File> findClasspathResourceContainer(String fqName) {
|
||||
return getIndex().findClasspathResourceContainer(fqName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
default IJavadoc getJavaDoc() {
|
||||
//?? why is this here ??
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.ide.vscode.commons.jandex.JandexClasspath;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
|
||||
import reactor.core.Disposable;
|
||||
|
||||
public class JavaProject implements IJavaProject, Disposable {
|
||||
|
||||
private final IClasspath classpath;
|
||||
private ClasspathIndex index;
|
||||
private URI uri;
|
||||
private final FileObserver fileObserver;
|
||||
|
||||
public JavaProject(FileObserver fileObserver, URI uri, IClasspath classpath) {
|
||||
super();
|
||||
this.classpath = classpath;
|
||||
this.fileObserver = fileObserver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
return classpath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ClasspathIndex getIndex() {
|
||||
if (index==null) {
|
||||
index = new JandexClasspath(classpath, fileObserver);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public URI getLocationUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Disposable toDispose = null;
|
||||
synchronized (this) {
|
||||
toDispose = index;
|
||||
index = null;
|
||||
}
|
||||
if (toDispose!=null) {
|
||||
toDispose.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return new File(uri).exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.javadoc;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
|
||||
public class JavaDocProviders {
|
||||
|
||||
public static IJavadocProvider createFor(CPE classpathEntry) {
|
||||
if (classpathEntry!=null && classpathEntry.getJavadocContainerUrl() != null) {
|
||||
URL containerUrl = classpathEntry.getJavadocContainerUrl();
|
||||
|
||||
TypeUrlProviderFromContainerUrl urlProvider = isJarUrl(containerUrl)
|
||||
? TypeUrlProviderFromContainerUrl.JAR_JAVADOC_URL_PROVIDER
|
||||
: TypeUrlProviderFromContainerUrl.JAVADOC_FOLDER_URL_SUPPLIER;
|
||||
return new HtmlJavadocProvider(
|
||||
type -> urlProvider.url(classpathEntry.getJavadocContainerUrl(), type.getFullyQualifiedName())
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isJarUrl(URL containerUrl) {
|
||||
return containerUrl.toString().endsWith(".jar");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,44 +15,44 @@ import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SourceUrlProviderFromSourceContainer {
|
||||
public interface TypeUrlProviderFromContainerUrl {
|
||||
|
||||
static String extractTopLevelType(String fqName) {
|
||||
int innerTypeIdx = fqName.indexOf('$');
|
||||
return innerTypeIdx > 0 ? fqName.substring(0, innerTypeIdx) : fqName;
|
||||
}
|
||||
|
||||
public static final SourceUrlProviderFromSourceContainer JAR_SOURCE_URL_PROVIDER = (sourceContainerUrl, fqName) -> {
|
||||
StringBuilder sourceUrlStr = new StringBuilder();
|
||||
sourceUrlStr.append("jar:");
|
||||
sourceUrlStr.append(sourceContainerUrl);
|
||||
sourceUrlStr.append("!");
|
||||
sourceUrlStr.append('/');
|
||||
sourceUrlStr.append(extractTopLevelType(fqName).replaceAll("\\.", "/"));
|
||||
sourceUrlStr.append(".java");
|
||||
return new URL(sourceUrlStr.toString());
|
||||
public static final TypeUrlProviderFromContainerUrl JAR_SOURCE_URL_PROVIDER = (jarSourceUrl, fqName) -> {
|
||||
StringBuilder urlStr = new StringBuilder();
|
||||
urlStr.append("jar:");
|
||||
urlStr.append(jarSourceUrl);
|
||||
urlStr.append("!");
|
||||
urlStr.append('/');
|
||||
urlStr.append(extractTopLevelType(fqName).replaceAll("\\.", "/"));
|
||||
urlStr.append(".java");
|
||||
return new URL(urlStr.toString());
|
||||
|
||||
};
|
||||
|
||||
public static final SourceUrlProviderFromSourceContainer SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
|
||||
public static final TypeUrlProviderFromContainerUrl SOURCE_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
|
||||
return Paths.get(sourceContainerUrl.toURI()).resolve(extractTopLevelType(fqName).replaceAll("\\.", "/") + ".java").toUri().toURL();
|
||||
};
|
||||
|
||||
public static final SourceUrlProviderFromSourceContainer JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, fqName) -> {
|
||||
StringBuilder sourceUrlStr = new StringBuilder();
|
||||
sourceUrlStr.append("jar:");
|
||||
sourceUrlStr.append(javadocContainerUrl);
|
||||
sourceUrlStr.append("!");
|
||||
sourceUrlStr.append('/');
|
||||
public static final TypeUrlProviderFromContainerUrl JAR_JAVADOC_URL_PROVIDER = (javadocContainerUrl, fqName) -> {
|
||||
StringBuilder urlStr = new StringBuilder();
|
||||
urlStr.append("jar:");
|
||||
urlStr.append(javadocContainerUrl);
|
||||
urlStr.append("!");
|
||||
urlStr.append('/');
|
||||
// Inner classes are in separate Top.Nesting1.Nesting2.Nesting3.MyType.html files
|
||||
sourceUrlStr.append(fqName.replaceAll("\\.", "/").replaceAll("\\$", "."));
|
||||
sourceUrlStr.append(".html");
|
||||
return new URL(sourceUrlStr.toString());
|
||||
urlStr.append(fqName.replaceAll("\\.", "/").replaceAll("\\$", "."));
|
||||
urlStr.append(".html");
|
||||
return new URL(urlStr.toString());
|
||||
|
||||
};
|
||||
|
||||
public static final SourceUrlProviderFromSourceContainer JAVADOC_FOLDER_URL_SUPPLIER = (sourceContainerUrl, fqName) -> {
|
||||
String urlStr = sourceContainerUrl.toString();
|
||||
public static final TypeUrlProviderFromContainerUrl JAVADOC_FOLDER_URL_SUPPLIER = (javadocContainerUrl, fqName) -> {
|
||||
String urlStr = javadocContainerUrl.toString();
|
||||
StringBuilder sb = new StringBuilder(urlStr);
|
||||
if (!urlStr.endsWith("/")) {
|
||||
sb.append('/');
|
||||
@@ -62,6 +62,6 @@ public interface SourceUrlProviderFromSourceContainer {
|
||||
return new URL(sb.toString());
|
||||
};
|
||||
|
||||
URL sourceUrl(URL sourceContainerUrl, String fqName) throws Exception;
|
||||
URL url(URL containerUrl, String fqName) throws Exception;
|
||||
|
||||
}
|
||||
@@ -60,14 +60,6 @@ public abstract class AbstractFileToProjectCache<P extends IJavaProject> extends
|
||||
notifyProjectDeleted(project);
|
||||
dispose();
|
||||
}));
|
||||
|
||||
Path outputFolder = project.getClasspath().getOutputFolder();
|
||||
if (outputFolder != null) {
|
||||
final List<String> rebuildGlobPattern = Arrays.asList(outputFolder.toString().replace(File.separator, "/") + "/**/*.class");
|
||||
subscriptions.add(getFileObserver().onFileChanged(rebuildGlobPattern, (uri) -> project.getClasspath().reindex()));
|
||||
subscriptions.add(getFileObserver().onFileCreated(rebuildGlobPattern, (uri) -> project.getClasspath().reindex()));
|
||||
subscriptions.add(getFileObserver().onFileDeleted(rebuildGlobPattern, (uri) -> project.getClasspath().reindex()));
|
||||
}
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.jandex;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.ide.vscode.commons.java.ClasspathData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
|
||||
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
public class JandexClasspathTest {
|
||||
|
||||
@Rule public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
class TestProject {
|
||||
String name;
|
||||
File root;
|
||||
File testClassesFolder;
|
||||
File outputFolder;
|
||||
BasicFileObserver fileObserver = new BasicFileObserver();
|
||||
|
||||
TestProject(String name) throws Exception {
|
||||
this.name = name;
|
||||
this.root = new File(JandexClasspathTest.class.getResource("/" + name ).toURI());
|
||||
testClassesFolder = new File(root, "bin");
|
||||
this.outputFolder = folder.newFolder();
|
||||
}
|
||||
|
||||
void createClass(String fqName) throws Exception {
|
||||
String relativePath = fqName.replace('.', '/')+".class";
|
||||
File classFile = new File(testClassesFolder, relativePath);
|
||||
File target = new File(outputFolder, relativePath);
|
||||
target.getParentFile().mkdirs();
|
||||
Files.copy(classFile, target);
|
||||
fileObserver.notifyFileCreated(target.toURI().toString());
|
||||
}
|
||||
|
||||
ClasspathData getClasspath() {
|
||||
return new ClasspathData(name, ImmutableList.of(
|
||||
CPE.source(new File(root, "src"), outputFolder)
|
||||
));
|
||||
}
|
||||
|
||||
JandexClasspath getJandexClasspath() {
|
||||
return new JandexClasspath(getClasspath(), fileObserver);
|
||||
}
|
||||
|
||||
public void deleteClass(String fqName, BiConsumer<BasicFileObserver, String> eventNoficator) {
|
||||
String relativePath = fqName.replace('.', '/')+".class";
|
||||
File classFile = new File(outputFolder, relativePath);
|
||||
classFile.delete();
|
||||
eventNoficator.accept(fileObserver, classFile.toURI().toString());
|
||||
}
|
||||
|
||||
public void deleteClass(String fqName) {
|
||||
deleteClass(fqName, (fileObserver, path) -> fileObserver.notifyFileDeleted(path));
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void classfileChangesShouldTriggerReindexing() throws Exception {
|
||||
TestProject project = new TestProject("simple-java-project");
|
||||
project.createClass("demo.Hello");
|
||||
|
||||
JandexClasspath subject = project.getJandexClasspath();
|
||||
|
||||
assertNotNull(subject.findType("demo.Hello"));
|
||||
assertNull(subject.findType("demo.Goodbye"));
|
||||
|
||||
project.createClass("demo.Goodbye");
|
||||
|
||||
assertNotNull(subject.findType("demo.Hello"));
|
||||
assertNotNull(subject.findType("demo.Goodbye"));
|
||||
|
||||
project.deleteClass("demo.Hello");
|
||||
|
||||
assertNull(subject.findType("demo.Hello"));
|
||||
assertNotNull(subject.findType("demo.Goodbye"));
|
||||
|
||||
project.deleteClass("demo.Goodbye", (fileObserver, deletedFile) -> fileObserver.notifyFileChanged(deletedFile));
|
||||
|
||||
assertNull(subject.findType("demo.Hello"));
|
||||
assertNull(subject.findType("demo.Goodbye"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
2
headless-services/commons/commons-java/src/test/resources/simple-java-project/.gitignore
vendored
Normal file
2
headless-services/commons/commons-java/src/test/resources/simple-java-project/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
!bin/
|
||||
!*.class
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>simple-java-project</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,11 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
package demo;
|
||||
|
||||
public class Goodbye {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package demo;
|
||||
|
||||
public class Hello {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user