Refactor, fix and simplify classpath infrastructure

This commit is contained in:
Kris De Volder
2018-04-30 10:10:56 -07:00
parent aa1cb03f12
commit 16a56a5fdc
69 changed files with 1518 additions and 993 deletions

View File

@@ -0,0 +1,59 @@
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=false
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_functional_interfaces=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.insert_inferred_type_arguments=false
sp_cleanup.make_local_variable_final=true
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=false
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=true
sp_cleanup.organize_imports=false
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_redundant_type_arguments=false
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=false
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=false
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_anonymous_class_creation=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_lambda=true
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=false
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true

View File

@@ -16,45 +16,52 @@ import java.nio.file.Path;
import org.springframework.ide.vscode.commons.java.AbstractJavaProject;
import org.springframework.ide.vscode.commons.java.ClasspathFileBasedCache;
import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.Log;
/**
* Implementation of Gradle Java project
*
*
* @author Alex Boyko
*
*/
public class GradleJavaProject extends AbstractJavaProject {
private DelegatingCachedClasspath<GradleProjectClasspath> classpath;
private File projectDir;
public GradleJavaProject(GradleCore gradle, File projectDir, Path projectDataCache) {
super(projectDataCache);
private final File projectDir;
private GradleJavaProject(FileObserver fileObserver, Path projectDataCache, IClasspath classpath, File projectDir) {
super(fileObserver, projectDir.toURI(), projectDataCache, classpath);
this.projectDir = projectDir;
File file = projectDataCache == null ? null
}
public static GradleJavaProject create(FileObserver fileObserver, GradleCore gradle, File projectDir, Path projectDataCache) {
File file = projectDataCache == null
? null
: projectDataCache.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE).toFile();
ClasspathFileBasedCache fileBasedCache = new ClasspathFileBasedCache(file);
this.classpath = new DelegatingCachedClasspath<GradleProjectClasspath>(
IClasspath classpath = new DelegatingCachedClasspath(
() -> new GradleProjectClasspath(gradle, projectDir),
fileBasedCache
);
return new GradleJavaProject(fileObserver, projectDataCache, classpath, projectDir);
}
public GradleJavaProject(GradleCore gradle, File projectDir) {
this(gradle, projectDir, null);
if (!classpath.isCached()) {
public static GradleJavaProject create(FileObserver fileObserver, GradleCore gradle, File projectDir) {
GradleJavaProject thiss = create(fileObserver, gradle, projectDir, null);
if (!thiss.getClasspath().isCached()) {
try {
classpath.update();
thiss.getClasspath().update();
} catch (Exception e) {
Log.log(e);
}
}
return thiss;
}
@Override
public String getElementName() {
if (classpath.getName() == null) {
if (getClasspath().getName() == null) {
return projectDir.getName();
} else {
return super.getElementName();
@@ -66,13 +73,17 @@ public class GradleJavaProject extends AbstractJavaProject {
}
@Override
public DelegatingCachedClasspath<GradleProjectClasspath> getClasspath() {
return classpath;
public DelegatingCachedClasspath getClasspath() {
return (DelegatingCachedClasspath) super.getClasspath();
}
boolean update() throws Exception {
return classpath.update();
return getClasspath().update();
}
@Override
public String toString() {
return "GradleJavaProject("+getElementName()+")";
}
}

View File

@@ -21,19 +21,19 @@ import org.springframework.ide.vscode.commons.languageserver.util.ShowMessageExc
/**
* Tests whether document belongs to a Gradle project
*
*
* @author Alex Boyko
*
*/
public class GradleProjectCache extends AbstractFileToProjectCache<GradleJavaProject> {
private GradleCore gradle;
public GradleProjectCache(Sts4LanguageServer server, GradleCore gradle, boolean asyncUpdate, Path projectCacheFolder) {
super(server, asyncUpdate, projectCacheFolder);
this.gradle = gradle;
}
@Override
protected boolean update(GradleJavaProject project) {
try {
@@ -48,7 +48,7 @@ public class GradleProjectCache extends AbstractFileToProjectCache<GradleJavaPro
@Override
protected GradleJavaProject createProject(File gradleBuild) throws Exception {
File gradleFile = gradleBuild.getParentFile();
GradleJavaProject gradleJavaProject = new GradleJavaProject(gradle, gradleFile,
GradleJavaProject gradleJavaProject = GradleJavaProject.create(getFileObserver(), gradle, gradleFile,
projectCacheFolder == null ? null : gradleFile.toPath().resolve(projectCacheFolder)
);
performUpdate(gradleJavaProject, asyncUpdate, asyncUpdate);

View File

@@ -25,13 +25,14 @@ import org.gradle.tooling.model.build.BuildEnvironment;
import org.gradle.tooling.model.eclipse.EclipseExternalDependency;
import org.gradle.tooling.model.eclipse.EclipseProject;
import org.gradle.tooling.model.eclipse.EclipseProjectDependency;
import org.gradle.tooling.model.eclipse.EclipseSourceDirectory;
import org.springframework.ide.vscode.commons.jandex.JandexClasspath;
import org.springframework.ide.vscode.commons.jandex.JandexIndex;
import org.springframework.ide.vscode.commons.java.ClasspathData;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
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.Log;
@@ -41,46 +42,46 @@ import com.google.common.collect.ImmutableList.Builder;
/**
* Implementation of {@link IClasspath} for Gradle projects
*
*
* @author Alex Boyko
*
*/
public class GradleProjectClasspath extends JandexClasspath {
public class GradleProjectClasspath implements IClasspath {
private static final String JAVA_HOME = "java.home";
private static final String JAVA_RUNTIME_VERSION = "java.runtime.version";
private static final String JAVA_BOOT_CLASS_PATH = "sun.boot.class.path";
private EclipseProject project;
private BuildEnvironment buildEnvironment;
public GradleProjectClasspath(GradleCore gradle, File projectDir) throws GradleException {
super();
this.project = gradle.getModel(projectDir, EclipseProject.class);
this.buildEnvironment = gradle.getModel(projectDir, BuildEnvironment.class);
}
@Override
protected JandexIndex[] getBaseIndices() {
return new JandexIndex[] { new JandexIndex(getJreLibs().map(path -> path.toFile()).collect(Collectors.toList()),
jarFile -> findIndexFile(jarFile), (classpathResource) -> {
try {
String javaVersion = getJavaRuntimeMinorVersion();
if (javaVersion == null) {
javaVersion = "8";
}
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
return new HtmlJavadocProvider(
(type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
.sourceUrl(javadocUrl, type.getFullyQualifiedName()));
} catch (MalformedURLException e) {
Log.log(e);
return null;
}
}) };
}
public EclipseProject getRootProject() {
// @Override
// protected JandexIndex[] getBaseIndices() {
// return new JandexIndex[] { new JandexIndex(getJreLibs().map(path -> path.toFile()).collect(Collectors.toList()),
// jarFile -> findIndexFile(jarFile), (classpathResource) -> {
// try {
// String javaVersion = getJavaRuntimeMinorVersion();
// if (javaVersion == null) {
// javaVersion = "8";
// }
// URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
// return new HtmlJavadocProvider(
// (type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
// .sourceUrl(javadocUrl, type.getFullyQualifiedName()));
// } catch (MalformedURLException e) {
// Log.log(e);
// return null;
// }
// }) };
// }
private EclipseProject getRootProject() {
EclipseProject root = project;
if (root == null) {
return root;
@@ -99,7 +100,7 @@ public class GradleProjectClasspath extends JandexClasspath {
} else {
Builder<CPE> entries = ImmutableList.builder();
for (EclipseExternalDependency dep : project.getClasspath()) {
entries.add(new CPE(Classpath.ENTRY_KIND_BINARY, dep.getFile().toPath().toString()));
entries.add(new CPE(Classpath.ENTRY_KIND_BINARY, dep.getFile().getAbsolutePath()));
}
for (EclipseProjectDependency dep : project.getProjectDependencies()) {
EclipseProject peer = findPeer(root, dep.getTargetProject().getName());
@@ -109,50 +110,24 @@ public class GradleProjectClasspath extends JandexClasspath {
));
}
}
for (EclipseSourceDirectory sf : project.getSourceDirectories()) {
File sourceFolder = sf.getDirectory();
String of = sf.getOutput();
entries.add(CPE.source(sourceFolder.getAbsoluteFile(), new File(project.getProjectDirectory(), of)));
}
return entries.build();
}
}
private EclipseProject findPeer(EclipseProject root, String name) {
return root.getChildren().stream().filter(p -> p.getName().equals(name)).findFirst().orElse(null);
}
@Override
public ImmutableList<String> getClasspathResources() {
if (project == null) {
return ImmutableList.of();
} else {
return ImmutableList.copyOf(project.getSourceDirectories().stream().map(sourceDirectory -> sourceDirectory.getDirectory()).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();
}
}).toArray(String[]::new));
}
}
public Path getOutputFolder() {
return project == null ? null : project.getProjectDirectory().toPath().resolve(project.getOutputLocation().getPath());
}
public String getName() {
return project == null ? null : project.getName();
}
public boolean exists() {
return project != null;
}
@Override
protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) {
return null;
}
public String getGradleVersion() throws GradleException {
if (buildEnvironment == null) {
throw new GradleException(new Exception("Cannot find Gradle version"));
@@ -160,7 +135,7 @@ public class GradleProjectClasspath extends JandexClasspath {
return buildEnvironment.getGradle().getGradleVersion();
}
}
public File getGradleHome() throws GradleException {
if (buildEnvironment == null) {
throw new GradleException(new Exception("Cannot find Gradle home folder"));
@@ -168,11 +143,11 @@ public class GradleProjectClasspath extends JandexClasspath {
return buildEnvironment.getGradle().getGradleUserHome();
}
}
public String getJavaRuntimeVersion() {
return System.getProperty(JAVA_RUNTIME_VERSION);
}
public String getJavaRuntimeMinorVersion() {
String fullVersion = getJavaRuntimeVersion();
String[] tokenized = fullVersion.split("\\.");
@@ -183,7 +158,7 @@ public class GradleProjectClasspath extends JandexClasspath {
return null;
}
}
private String getJavaHome() {
if (buildEnvironment == null) {
return System.getProperty(JAVA_HOME);
@@ -191,7 +166,7 @@ public class GradleProjectClasspath extends JandexClasspath {
return buildEnvironment.getJava().getJavaHome().toString();
}
}
private Stream<Path> getJreLibs() {
String s = System.getProperty(JAVA_BOOT_CLASS_PATH);
return Arrays.stream(s.split(File.pathSeparator))
@@ -200,22 +175,7 @@ public class GradleProjectClasspath extends JandexClasspath {
.filter(f -> f.canRead())
.map(f -> f.toPath());
}
private File findIndexFile(File jarFile) {
String suffix = null;
String javaHome = getJavaHome();
if (javaHome != null) {
int index = javaHome.lastIndexOf('/');
if (index != -1) {
javaHome = javaHome.substring(0, index);
}
}
if (jarFile.toString().startsWith(javaHome)) {
suffix = getJavaRuntimeVersion();
}
return new File(JandexIndex.getIndexFolder().toString(), jarFile.getName() + "-" + suffix + ".jdx");
}
@Override
public boolean equals(Object obj) {
if (obj instanceof GradleProjectClasspath) {
@@ -224,20 +184,4 @@ public class GradleProjectClasspath extends JandexClasspath {
return false;
}
@Override
public ImmutableList<String> getSourceFolders() {
return ImmutableList.copyOf(project.getSourceDirectories().stream()
.map(dir -> dir.getDirectory().toPath().toString()).collect(Collectors.toList()));
}
@Override
public ClasspathData createClasspathData() throws Exception {
return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder());
}
@Override
public Optional<URL> sourceContainer(File classpathResource) {
return Optional.empty();
}
}

View File

@@ -37,19 +37,21 @@ import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CP
import org.springframework.ide.vscode.commons.languageserver.util.SimpleWorkspaceService;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import static org.springframework.ide.vscode.languageserver.testharness.ClasspathTestUtil.*;
import com.google.common.collect.ImmutableList;
/**
* Tests covering Gradle project data
*
*
* @author Alex Boyko
*
*/
public class GradleProjectTest {
private Sts4LanguageServer server;
private BasicFileObserver fileObserver;
@Before
public void setup() throws Exception {
fileObserver = new BasicFileObserver();
@@ -58,7 +60,7 @@ public class GradleProjectTest {
when(workspaceService.getFileObserver()).thenReturn(fileObserver);
when(server.getWorkspaceService()).thenReturn(workspaceService);
}
private static void writeContent(File file, String content) throws IOException {
FileWriter writer = null;
try {
@@ -68,39 +70,40 @@ public class GradleProjectTest {
writer.close();
}
}
private GradleJavaProject getGradleProject(String projectName) throws Exception {
Path testProjectPath = Paths.get(GradleProjectTest.class.getResource("/" + projectName).toURI());
return new GradleJavaProject(GradleCore.getDefault(), testProjectPath.toFile());
return GradleJavaProject.create(fileObserver, GradleCore.getDefault(), testProjectPath.toFile());
}
@Test
public void testEclipseGradleProject() throws Exception {
GradleJavaProject project = getGradleProject("empty-gradle-project");
ImmutableList<CPE> calculatedClassPath = project.getClasspath().getClasspathEntries();
assertEquals(48, calculatedClassPath.size());
assertEquals(51, calculatedClassPath.size());
}
@Test
public void outputFolder() throws Exception {
GradleJavaProject project = getGradleProject("test-app-1");
assertTrue(project.getClasspath().getOutputFolder().toString().contains("/bin"));
String of = getOutputFolder(project).toString();
assertTrue(of.endsWith("/bin") || of.endsWith("/bin/main"));
}
@Test
public void gradleClasspathResource() throws Exception {
GradleJavaProject project = getGradleProject("test-app-1");
List<String> resources = project.getClasspath().getClasspathResources();
List<String> resources = project.getClasspathResources();
assertArrayEquals(new String[] {"test-resource-1.txt"}, resources.toArray(new String[resources.size()]));
}
@Test
public void testGradleFileChanges() throws Exception {
Path testProjectPath = Paths.get(GradleProjectTest.class.getResource("/empty-gradle-project").toURI());
File gradleFile = testProjectPath.resolve(GradleCore.GRADLE_BUILD_FILE).toFile();
String gradelFileContents = Files.contentOf(gradleFile, Charset.defaultCharset());
try {
GradleProjectCache manager = new GradleProjectCache(server, GradleCore.getDefault(), false, null);
IJavaProject[] projectChanged = new IJavaProject[] { null };
@@ -108,7 +111,7 @@ public class GradleProjectTest {
manager.addListener(new Listener() {
@Override
public void created(IJavaProject project) {}
@Override
public void changed(IJavaProject project) {
projectChanged[0] = project;
@@ -118,25 +121,25 @@ public class GradleProjectTest {
projectDeleted[0] = project;
}
});
// Get the project from cache
GradleJavaProject cachedProject = manager.project(gradleFile);
assertNotNull(cachedProject);
ImmutableList<CPE> calculatedClassPath = cachedProject.getClasspath().getClasspathEntries();
assertEquals(48, calculatedClassPath.size());
assertEquals(51, calculatedClassPath.size());
fileObserver.notifyFileChanged(gradleFile.toURI().toString());
assertNull(projectChanged[0]);
writeContent(gradleFile, Files.contentOf(testProjectPath.resolve("build.newgradle").toFile(), Charset.defaultCharset()));
fileObserver.notifyFileChanged(gradleFile.toURI().toString());
assertNotNull(projectChanged[0]);
assertEquals(cachedProject, projectChanged[0]);
calculatedClassPath = cachedProject.getClasspath().getClasspathEntries();
assertEquals(49, calculatedClassPath.size());
assertEquals(52, calculatedClassPath.size());
fileObserver.notifyFileDeleted(gradleFile.toURI().toString());
assertEquals(cachedProject, projectDeleted[0]);
} finally {
@@ -165,5 +168,5 @@ public class GradleProjectTest {
GradleJavaProject gradleProject = (GradleJavaProject) project.get();
assertEquals(new File(GradleProjectTest.class.getResource("/test-app-2").toURI()), gradleProject.getLocation());
}
}

View File

@@ -23,5 +23,11 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -1,3 +1,5 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

View File

@@ -0,0 +1,59 @@
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=false
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_functional_interfaces=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.insert_inferred_type_arguments=false
sp_cleanup.make_local_variable_final=true
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=false
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=true
sp_cleanup.organize_imports=false
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_redundant_type_arguments=false
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=false
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=false
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_anonymous_class_creation=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_lambda=true
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=false
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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() {

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
!bin/
!*.class

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
package demo;
public class Goodbye {
}

View File

@@ -0,0 +1,5 @@
package demo;
public class Hello {
}

View File

@@ -1,20 +1,31 @@
/*******************************************************************************
* 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.languageserver.jdt.ls;
import java.io.File;
import java.net.URL;
import java.util.List;
import org.springframework.ide.vscode.commons.util.Assert;
public class Classpath {
public static final String ENTRY_KIND_SOURCE = "source";
public static final String ENTRY_KIND_BINARY = "binary";
private List<CPE> entries;
private String defaultOutputFolder;
public Classpath(List<CPE> entries, String defaultOutputFolder) {
public Classpath(List<CPE> entries) {
super();
this.entries = entries;
this.defaultOutputFolder = defaultOutputFolder;
}
public List<CPE> getEntries() {
@@ -25,33 +36,34 @@ public class Classpath {
this.entries = entries;
}
public String getDefaultOutputFolder() {
return defaultOutputFolder;
}
public void setDefaultOutputFolder(String defaultOutputFolder) {
this.defaultOutputFolder = defaultOutputFolder;
}
@Override
public String toString() {
return "Classpath [entries=" + entries + ", defaultOutputFolder=" + defaultOutputFolder + "]";
return "Classpath [entries=" + entries + "]";
}
public static class CPE {
private String kind;
private String path;
/**
* This only applies for 'source' entries.
*/
// TODO: it seems like a good idea to make all classpath entries the same in that they all have
// - a place with source code
// - a place with compiled code
// - a place with java doc
// So it seems like we should be able to chnage this so that the same named attribute is used
// in both cases (rather then one be 'getOutputFolder' and one 'getPath' to obtain location of the compiled code).
private String kind;
private String path; // TODO: Change to File, Path or URL?
private String outputFolder;
private URL sourceContainerUrl;
private URL javadocContainerUrl;
private boolean isSystem = false;
public String getOutputFolder() {
return outputFolder;
}
public void setOutputFolder(String outputFolder) {
Assert.isLegal(outputFolder==null || new File(outputFolder).isAbsolute());
this.outputFolder = outputFolder;
}
@@ -60,7 +72,7 @@ public class Classpath {
public CPE(String kind, String path) {
super();
this.kind = kind;
this.path = path;
setPath(path);
}
public String getKind() {
@@ -76,16 +88,54 @@ public class Classpath {
}
public void setPath(String path) {
Assert.isLegal(path == null || new File(path).isAbsolute());
this.path = path;
}
public URL getJavadocContainerUrl() {
return javadocContainerUrl;
}
public void setJavadocContainerUrl(URL javadocContainerUrl) {
this.javadocContainerUrl = javadocContainerUrl;
}
public URL getSourceContainerUrl() {
return sourceContainerUrl;
}
public void setSourceContainerUrl(URL sourceContainerUrl) {
this.sourceContainerUrl = sourceContainerUrl;
}
public static CPE binary(String path) {
return new CPE(ENTRY_KIND_BINARY, path);
}
public static CPE source(File sourceFolder, File outputFolder) {
CPE cpe = new CPE(ENTRY_KIND_SOURCE, sourceFolder.getAbsolutePath());
cpe.setOutputFolder(outputFolder.getAbsolutePath());
return cpe;
}
public boolean isSystem() {
return isSystem;
}
public void setSystem(boolean isSystem) {
this.isSystem = isSystem;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (isSystem ? 1231 : 1237);
result = prime * result + ((javadocContainerUrl == null) ? 0 : javadocContainerUrl.hashCode());
result = prime * result + ((kind == null) ? 0 : kind.hashCode());
result = prime * result + ((outputFolder == null) ? 0 : outputFolder.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + ((sourceContainerUrl == null) ? 0 : sourceContainerUrl.hashCode());
return result;
}
@@ -98,6 +148,13 @@ public class Classpath {
if (getClass() != obj.getClass())
return false;
CPE other = (CPE) obj;
if (isSystem != other.isSystem)
return false;
if (javadocContainerUrl == null) {
if (other.javadocContainerUrl != null)
return false;
} else if (!javadocContainerUrl.equals(other.javadocContainerUrl))
return false;
if (kind == null) {
if (other.kind != null)
return false;
@@ -113,12 +170,17 @@ public class Classpath {
return false;
} else if (!path.equals(other.path))
return false;
if (sourceContainerUrl == null) {
if (other.sourceContainerUrl != null)
return false;
} else if (!sourceContainerUrl.equals(other.sourceContainerUrl))
return false;
return true;
}
@Override
public String toString() {
return "CPE [kind=" + kind + ", path=" + path + ", outputFolder=" + outputFolder + "]";
return "CPE [kind=" + kind + ", path=" + path + ", isSystem=" + isSystem + "]";
}
}

View File

@@ -0,0 +1,59 @@
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=false
sp_cleanup.always_use_this_for_non_static_method_access=false
sp_cleanup.convert_functional_interfaces=false
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.insert_inferred_type_arguments=false
sp_cleanup.make_local_variable_final=true
sp_cleanup.make_parameters_final=false
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=false
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=true
sp_cleanup.organize_imports=false
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_redundant_type_arguments=false
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=false
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=false
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_anonymous_class_creation=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_lambda=true
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=false
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
sp_cleanup.use_this_for_non_static_method_access=false
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true

View File

@@ -57,7 +57,7 @@ import org.eclipse.aether.util.graph.visitor.CloningDependencyVisitor;
import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor;
import org.springframework.ide.vscode.commons.jandex.JandexIndex;
import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.base.Supplier;
@@ -95,7 +95,7 @@ public class MavenCore {
javaVersion = "8";
}
URL javadocUrl = new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/");
return new HtmlJavadocProvider((type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER.sourceUrl(javadocUrl, type.getFullyQualifiedName()));
return new HtmlJavadocProvider((type) -> TypeUrlProviderFromContainerUrl.JAVADOC_FOLDER_URL_SUPPLIER.url(javadocUrl, type.getFullyQualifiedName()));
} catch (MalformedURLException e) {
Log.log(e);
return null;

View File

@@ -16,7 +16,9 @@ import java.nio.file.Path;
import org.springframework.ide.vscode.commons.java.AbstractJavaProject;
import org.springframework.ide.vscode.commons.java.ClasspathFileBasedCache;
import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.Log;
/**
@@ -27,35 +29,40 @@ import org.springframework.ide.vscode.commons.util.Log;
*/
public class MavenJavaProject extends AbstractJavaProject {
private DelegatingCachedClasspath<MavenProjectClasspath> classpath;
private File pom;
public MavenJavaProject(MavenCore maven, File pom, Path projectDataCache) {
super(projectDataCache);
private final File pom;
private MavenJavaProject(FileObserver fileObserver, Path projectDataCache, IClasspath classpath, File pom) {
super(fileObserver, pom.getParentFile().toURI(), projectDataCache, classpath);
this.pom = pom;
File file = projectDataCache == null ? null
}
public static MavenJavaProject create(FileObserver fileObserver, MavenCore maven, File pom, Path projectDataCache) {
File file = projectDataCache == null
? null
: projectDataCache.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE).toFile();
ClasspathFileBasedCache fileBasedCache = new ClasspathFileBasedCache(file);
this.classpath = new DelegatingCachedClasspath<>(
DelegatingCachedClasspath classpath = new DelegatingCachedClasspath(
() -> new MavenProjectClasspath(maven, pom),
fileBasedCache
);
);
return new MavenJavaProject(fileObserver, projectDataCache, classpath, pom);
}
public MavenJavaProject(MavenCore maven, File pom) {
this(maven, pom, null);
if (!classpath.isCached()) {
public static MavenJavaProject create(FileObserver fileObserver, MavenCore maven, File pom) {
MavenJavaProject thiss = create(fileObserver, maven, pom, null);
if (!thiss.getClasspath().isCached()) {
try {
classpath.update();
thiss.getClasspath().update();
} catch (Exception e) {
Log.log(e);
}
}
return thiss;
}
@Override
public String getElementName() {
if (classpath.getName() == null) {
if (getClasspath().getName() == null) {
return pom.getParentFile().getName();
} else {
return super.getElementName();
@@ -63,12 +70,12 @@ public class MavenJavaProject extends AbstractJavaProject {
}
@Override
public DelegatingCachedClasspath<MavenProjectClasspath> getClasspath() {
return classpath;
public DelegatingCachedClasspath getClasspath() {
return (DelegatingCachedClasspath) super.getClasspath();
}
boolean update() throws Exception {
return classpath.update();
return getClasspath().update();
}
public File pom() {
@@ -77,7 +84,6 @@ public class MavenJavaProject extends AbstractJavaProject {
@Override
public String toString() {
return "MavenJavaProject("+classpath.getName()+")";
return "MavenJavaProject("+getElementName()+")";
}
}

View File

@@ -47,7 +47,7 @@ public class MavenProjectCache extends AbstractFileToProjectCache<MavenJavaProje
@Override
protected MavenJavaProject createProject(File pomFile) throws Exception {
MavenJavaProject mavenJavaProject = new MavenJavaProject(
MavenJavaProject mavenJavaProject = MavenJavaProject.create(getFileObserver(),
maven,
pomFile,
projectCacheFolder == null ? null : pomFile.getParentFile().toPath().resolve(projectCacheFolder)

View File

@@ -21,52 +21,54 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Generated;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Resource;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.DirectoryScanner;
import org.springframework.ide.vscode.commons.jandex.JandexClasspath;
import org.springframework.ide.vscode.commons.jandex.JandexIndex;
import org.springframework.ide.vscode.commons.java.ClasspathData;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
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.maven.MavenCore;
import org.springframework.ide.vscode.commons.maven.MavenException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.RunnableWithException;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.gson.internal.Streams;
/**
* Classpath for a maven project
*
*
* @author Alex Boyko
*
*/
public class MavenProjectClasspath extends JandexClasspath {
public class MavenProjectClasspath implements IClasspath {
private MavenCore maven;
private File pom;
private MavenClasspathData cachedData;
private ClasspathData cachedData;
MavenProjectClasspath(MavenCore maven, File pom) throws Exception {
super();
this.maven = maven;
this.pom = pom;
this.cachedData = createClasspathData();
}
@Override
protected JandexIndex[] getBaseIndices() {
return new JandexIndex[] { maven.getJavaIndexForJreLibs() };
}
private final MavenProject createMavenProject() throws MavenException {
try {
@@ -77,42 +79,115 @@ public class MavenProjectClasspath extends JandexClasspath {
return maven.readProject(pom, false);
}
}
public File getPomFile() {
return pom;
}
MavenCore maven() {
return maven;
}
public boolean exists() {
return pom.exists();
}
@Override
public String getName() {
return cachedData != null ? cachedData.getName() : null;
}
private ImmutableList<CPE> resolveClasspathEntries(MavenProject project) throws Exception {
return ImmutableList.copyOf(
Stream.concat(
projectDependencies(project).stream().map(a -> a.getFile().toPath()),
projectOutput(project).stream().map(f -> f.toPath())
)
.map(path -> new CPE(Classpath.ENTRY_KIND_BINARY, path.toString()))
.collect(Collectors.toList()));
LinkedHashSet<CPE> entries = new LinkedHashSet<>();
safe(() -> maven.getJreLibs().forEach(path -> safe(() -> {
CPE cpe = CPE.binary(path.toString());
String javaVersion = maven.getJavaRuntimeMinorVersion();
if (javaVersion == null) {
javaVersion = "8";
}
cpe.setJavadocContainerUrl(new URL("https://docs.oracle.com/javase/" + javaVersion + "/docs/api/"));
cpe.setSystem(true);
entries.add(cpe);
})));
//Add jar dependencies...
for (Artifact a : projectDependencies(project)) {
File f = a.getFile();
if (f!=null) {
CPE cpe = CPE.binary(a.getFile().toPath().toString());
safe(() -> { //add javadoc
Artifact jdoc = maven.getJavadoc(a, project.getRemoteArtifactRepositories());
if (jdoc!=null) {
cpe.setJavadocContainerUrl(jdoc.getFile().toURI().toURL());
}
});
safe(() -> { //add source
Artifact source = maven.getSources(a, project.getRemoteArtifactRepositories());
if (source!=null) {
cpe.setSourceContainerUrl(source.getFile().toURI().toURL());
}
});
entries.add(cpe);
}
}
//Add source folders...
{ //main/java
File sourceFolder = new File(project.getBuild().getSourceDirectory());
File outputFolder = new File(project.getBuild().getOutputDirectory());
CPE cpe = CPE.source(sourceFolder, outputFolder);
safe(() -> {
String reportingDir = project.getModel().getReporting().getOutputDirectory();
if (reportingDir!=null) {
File apidocs = new File(new File(reportingDir), "apidocs");
cpe.setJavadocContainerUrl(apidocs.toURI().toURL());
}
});
entries.add(cpe);
}
{ //main/resources
for (Resource resource : project.getBuild().getResources()) {
File sourceFolder = new File(resource.getDirectory());
String targetPath = resource.getTargetPath();
if (targetPath==null) {
targetPath = project.getBuild().getOutputDirectory();
}
entries.add(CPE.source(sourceFolder, new File(targetPath)));
}
}
{ //test/resources
for (Resource resource : project.getBuild().getTestResources()) {
File sourceFolder = new File(resource.getDirectory());
String targetPath = resource.getTargetPath();
if (targetPath==null) {
targetPath = project.getBuild().getTestOutputDirectory();
}
entries.add(CPE.source(sourceFolder, targetPath==null ? null : new File(targetPath)));
}
}
{ //test/java
File sourceFolder = new File(project.getBuild().getTestSourceDirectory());
File outputFolder = new File(project.getBuild().getTestOutputDirectory());
CPE cpe = CPE.source(sourceFolder, outputFolder);
safe(() -> {
String reportingDir = project.getModel().getReporting().getOutputDirectory();
if (reportingDir!=null) {
File apidocs = new File(new File(reportingDir), "apidocs");
cpe.setJavadocContainerUrl(apidocs.toURI().toURL());
}
});
entries.add(cpe);
}
return ImmutableList.copyOf(entries);
}
@Override
public ImmutableList<CPE> getClasspathEntries() throws Exception {
return cachedData != null ? ImmutableList.copyOf(cachedData.getClasspathEntries()) : ImmutableList.of();
}
private Set<Artifact> projectDependencies(MavenProject project) {
return project == null ? Collections.emptySet() : project.getArtifacts();
}
private List<File> projectOutput(MavenProject project) {
if (project == null) {
return Collections.emptyList();
@@ -120,133 +195,22 @@ public class MavenProjectClasspath extends JandexClasspath {
return Arrays.asList(new File(project.getBuild().getOutputDirectory()), new File(project.getBuild().getTestOutputDirectory()));
}
}
private Path resolveOutputFolder(MavenProject project) {
return project == null ? null : new File(project.getBuild().getOutputDirectory()).toPath();
}
public Path getOutputFolder() {
if (cachedData!=null) {
String of = cachedData.getOutputFolder();
return of == null ? null : Paths.get(of);
private static void safe(RunnableWithException do_stuff) {
try {
do_stuff.run();
} catch (Exception e) {
// log.error("", e);
}
return null;
}
private ImmutableList<String> resolveClasspathResources(MavenProject project) {
if (project == null) {
return ImmutableList.of();
}
return ImmutableList.copyOf(project.getBuild().getResources().stream().filter(resource -> new File(resource.getDirectory()).exists()).flatMap(resource -> {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(resource.getDirectory());
if (resource.getIncludes() != null && !resource.getIncludes().isEmpty()) {
scanner.setIncludes(resource.getIncludes().toArray(new String[resource.getIncludes().size()]));
}
if (resource.getExcludes() != null && !resource.getExcludes().isEmpty()) {
scanner.setExcludes(resource.getExcludes().toArray(new String[resource.getExcludes().size()]));
}
scanner.setCaseSensitive(false);
scanner.scan();
return Arrays.stream(scanner.getIncludedFiles());
}).toArray(String[]::new));
}
@Override
public ImmutableList<String> getClasspathResources() {
return cachedData != null ? ImmutableList.copyOf(cachedData.getClasspathResources()) : ImmutableList.of();
}
/*
* Roaster lib is experiment to generate javadoc from source. Commented out for now since roaster lib is taken out
*/
// private IJavadocProvider createRoasterJavadocProvider(File classpathResource) {
// if (classpathResource.isDirectory()) {
// if (classpathResource.toString().startsWith(project.getBuild().getOutputDirectory())) {
// return new RoasterJavadocProvider(type -> {
// return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
// .sourceUrl(new File(project.getBuild().getSourceDirectory()).toURI().toURL(), type);
// });
// } else if (classpathResource.toString().startsWith(project.getBuild().getTestOutputDirectory())) {
// return new RoasterJavadocProvider(type -> {
// return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
// .sourceUrl(new File(project.getBuild().getTestSourceDirectory()).toURI().toURL(), type);
// });
// } else {
// throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
// }
// } else {
// // Assume it's a JAR file
// return new RoasterJavadocProvider(type -> {
// try {
// Artifact artifact = getArtifactFromJarFile(classpathResource).get();
// URL sourceContainer = maven.getSources(artifact).getFile().toURI().toURL();
// return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(sourceContainer,
// type);
// } catch (MavenException e) {
// Log.log("Failed to find sources JAR for " + classpathResource, e);
// } catch (MalformedURLException e) {
// Log.log("Invalid URL for sources JAR for " + classpathResource, e);
// }
// return null;
// });
// }
// }
private ClasspathData createClasspathData() throws Exception {
MavenProject project = createMavenProject();
@Override
public Optional<URL> sourceContainer(File classpathResource) {
if (cachedData == null) {
return Optional.empty();
}
return cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().map(artifact -> {
try {
return maven.getSources(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
} catch (MalformedURLException e) {
Log.log("Invalid URL for sources JAR for " + classpathResource, e);
return null;
} catch (MavenException e) {
Log.log("Failed to find sources JAR for " + classpathResource, e);
return null;
}
});
}
ImmutableList<CPE> entries = resolveClasspathEntries(project);
String name = project.getArtifact().getArtifactId();
@Override
protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) {
if (cachedData == null) {
return null;
}
if (classpathResource.isDirectory()) {
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
return new HtmlJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type.getFullyQualifiedName());
});
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
return new HtmlJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type.getFullyQualifiedName());
});
} else {
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
}
} else {
// Assume it's a JAR file
return new HtmlJavadocProvider(type -> {
try {
Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get();
URL sourceContainer = maven.getJavadoc(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
return SourceUrlProviderFromSourceContainer.JAR_JAVADOC_URL_PROVIDER.sourceUrl(sourceContainer,
type.getFullyQualifiedName());
} catch (MavenException e) {
Log.log("Failed to find sources JAR for " + classpathResource, e);
} catch (MalformedURLException e) {
Log.log("Invalid URL for sources JAR for " + classpathResource, e);
}
return null;
});
}
return new ClasspathData(name, new LinkedHashSet<>(entries));
}
@Override
@@ -265,95 +229,4 @@ public class MavenProjectClasspath extends JandexClasspath {
return false;
}
@Override
public ImmutableList<String> getSourceFolders() {
return cachedData != null ? ImmutableList.of(cachedData.sourceDirectory) : ImmutableList.of();
}
@Override
public MavenClasspathData createClasspathData() throws Exception {
MavenProject project = createMavenProject();
ImmutableList<CPE> entries = resolveClasspathEntries(project);
String name = project.getArtifact().getArtifactId();
ImmutableList<String> resources = resolveClasspathResources(project);
Path outputFolder = resolveOutputFolder(project);
MavenClasspathData data = new MavenClasspathData(name, new LinkedHashSet<>(entries),
new LinkedHashSet<>(resources), outputFolder);
data.outputDirectory = project.getBuild().getOutputDirectory();
data.reportingOutputDirectory = project.getModel().getReporting().getOutputDirectory();
data.testOutputDirectory = project.getBuild().getTestOutputDirectory();
data.testSourceDirectory = project.getBuild().getTestSourceDirectory();
data.artifacts = project.getArtifacts();
data.remoteArtifactRepositories = project.getRemoteArtifactRepositories();
data.sourceDirectory = project.getBuild().getSourceDirectory();
return data;
}
static class MavenClasspathData extends ClasspathData {
private String testSourceDirectory;
private List<ArtifactRepository> remoteArtifactRepositories;
private Set<Artifact> artifacts;
private String testOutputDirectory;
private String reportingOutputDirectory;
private String outputDirectory;
private String sourceDirectory;
public MavenClasspathData(String name, Set<CPE> classpathEntries, Set<String> classpathResources,
Path outputFolder) {
super(name, classpathEntries, classpathResources, outputFolder == null ? null : outputFolder.toString());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
MavenClasspathData other = (MavenClasspathData) obj;
if (artifacts == null) {
if (other.artifacts != null)
return false;
} else if (!artifacts.equals(other.artifacts))
return false;
if (outputDirectory == null) {
if (other.outputDirectory != null)
return false;
} else if (!outputDirectory.equals(other.outputDirectory))
return false;
if (remoteArtifactRepositories == null) {
if (other.remoteArtifactRepositories != null)
return false;
} else if (!remoteArtifactRepositories.equals(other.remoteArtifactRepositories))
return false;
if (reportingOutputDirectory == null) {
if (other.reportingOutputDirectory != null)
return false;
} else if (!reportingOutputDirectory.equals(other.reportingOutputDirectory))
return false;
if (sourceDirectory == null) {
if (other.sourceDirectory != null)
return false;
} else if (!sourceDirectory.equals(other.sourceDirectory))
return false;
if (testOutputDirectory == null) {
if (other.testOutputDirectory != null)
return false;
} else if (!testOutputDirectory.equals(other.testOutputDirectory))
return false;
if (testSourceDirectory == null) {
if (other.testSourceDirectory != null)
return false;
} else if (!testSourceDirectory.equals(other.testSourceDirectory))
return false;
return true;
}
}
}

View File

@@ -28,19 +28,22 @@ import org.springframework.ide.vscode.commons.java.IMethod;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
public class HtmlJavadocTest {
private static FileObserver fileObserver = new BasicFileObserver();
private static Supplier<MavenJavaProject> projectSupplier = Suppliers.memoize(() -> {
Path testProjectPath;
try {
JandexClasspath.providerType = JavadocProviderTypes.HTML;
testProjectPath = Paths.get(HtmlJavadocTest.class.getResource("/gs-rest-service-cors-boot-1.4.1-with-classpath-file").toURI());
MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute();
return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
return MavenJavaProject.create(fileObserver, MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
} catch (Exception e) {
return null;
}
@@ -52,7 +55,7 @@ public class HtmlJavadocTest {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("java.util.Map");
IType type = project.findType("java.util.Map");
assertNotNull(type);
String expected = String.join("\n",
"<div class=\"block\">An object that maps keys to values. A map cannot contain duplicate keys;",
@@ -68,7 +71,7 @@ public class HtmlJavadocTest {
Assume.assumeTrue(javaVersionHigherThan(6));
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("java.util.ArrayList");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
IMethod method = type.getMethod("<init>", Stream.empty());
assertNotNull(method);
@@ -86,7 +89,7 @@ public class HtmlJavadocTest {
public void html_testEmptyJavadocClass() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.Application");
IType type = project.findType("hello.Application");
assertNotNull(type);
assertNull(type.getJavaDoc());
}
@@ -95,7 +98,7 @@ public class HtmlJavadocTest {
public void html_testFieldAndMethodJavadocForJar() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("org.springframework.boot.SpringApplication");
IType type = project.findType("org.springframework.boot.SpringApplication");
assertNotNull(type);
IField field = type.getField("BANNER_LOCATION_PROPERTY_VALUE");
@@ -135,7 +138,7 @@ public class HtmlJavadocTest {
public void html_testInnerClassJavadocForOutputFolder() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.Greeting$TestInnerClass");
IType type = project.findType("hello.Greeting$TestInnerClass");
assertNotNull(type);
IJavadoc javaDoc = type.getJavaDoc();
assertNotNull(javaDoc);
@@ -168,7 +171,7 @@ public class HtmlJavadocTest {
public void html_testInnerClassLevel2_JavadocForOutputFolder() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.Greeting$TestInnerClass$TestInnerClassLevel2");
IType type = project.findType("hello.Greeting$TestInnerClass$TestInnerClassLevel2");
assertNotNull(type);
IJavadoc javaDoc = type.getJavaDoc();
assertNotNull(javaDoc);
@@ -200,7 +203,7 @@ public class HtmlJavadocTest {
@Test
public void html_testJavadocOutputFolder() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.Greeting");
IType type = project.findType("hello.Greeting");
assertNotNull(type);
String expected = "<div class=\"block\">Comment for Greeting class</div>";
@@ -237,7 +240,7 @@ public class HtmlJavadocTest {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("java.util.ArrayList");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
IMethod method = type.getMethod("size", Stream.empty());
assertNotNull(method);
@@ -258,7 +261,7 @@ public class HtmlJavadocTest {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("java.util.Map$Entry");
IType type = project.findType("java.util.Map$Entry");
assertNotNull(type);
String expected = String.join("\n",
"<div class=\"block\">A map entry (key-value pair). The <tt>Map.entrySet</tt> method returns",
@@ -272,7 +275,7 @@ public class HtmlJavadocTest {
public void html_testNoJavadocClass() throws Exception {
MavenJavaProject project = projectSupplier.get();;
IType type = project.getClasspath().findType("hello.GreetingController");
IType type = project.findType("hello.GreetingController");
assertNotNull(type);
assertNull(type.getJavaDoc());
}
@@ -281,7 +284,7 @@ public class HtmlJavadocTest {
public void html_testNoJavadocField() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.GreetingController");
IType type = project.findType("hello.GreetingController");
assertNotNull(type);
IField field = type.getField("template");
assertNotNull(field);
@@ -302,7 +305,7 @@ public class HtmlJavadocTest {
public void html_testNoJavadocMethod() throws Exception {
MavenJavaProject project = projectSupplier.get();
IType type = project.getClasspath().findType("hello.Application");
IType type = project.findType("hello.Application");
assertNotNull(type);
IMethod method = type.getMethod("corsConfigurer", Stream.empty());
assertNotNull(method);

View File

@@ -32,6 +32,8 @@ import org.springframework.ide.vscode.commons.java.IPrimitiveType;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.java.IVoidType;
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@@ -39,15 +41,19 @@ import com.google.common.cache.LoadingCache;
import reactor.util.function.Tuple2;
import static org.springframework.ide.vscode.languageserver.testharness.ClasspathTestUtil.*;
public class JavaIndexTest {
private static BasicFileObserver fileObserver = new BasicFileObserver();
private static LoadingCache<String, MavenJavaProject> mavenProjectsCache = CacheBuilder.newBuilder().build(new CacheLoader<String, MavenJavaProject>() {
@Override
public MavenJavaProject load(String projectName) throws Exception {
Path testProjectPath = Paths.get(DependencyTreeTest.class.getResource("/" + projectName).toURI());
MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute();
return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
return MavenJavaProject.create(fileObserver, MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
}
});
@@ -85,28 +91,28 @@ public class JavaIndexTest {
@Test
public void findClassInJar() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("org.springframework.test.web.client.ExpectedCount");
IType type = project.findType("org.springframework.test.web.client.ExpectedCount");
assertNotNull(type);
}
@Test
public void findClassInOutputFolder() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("hello.Greeting");
IType type = project.findType("hello.Greeting");
assertNotNull(type);
}
@Test
public void classNotFound() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("hello.NonExistentClass");
IType type = project.findType("hello.NonExistentClass");
assertNull(type);
}
@Test
public void voidMethodNoParams() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("java.util.ArrayList");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
IMethod m = type.getMethod("clear", Stream.empty());
assertEquals("clear", m.getElementName());
@@ -117,7 +123,7 @@ public class JavaIndexTest {
@Test
public void voidConstructor() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("java.util.ArrayList");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
IMethod m = type.getMethod("<init>", Stream.empty());
assertEquals(type.getElementName(), m.getElementName());
@@ -128,7 +134,7 @@ public class JavaIndexTest {
@Test
public void constructorMethodWithParams() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.getClasspath().findType("java.util.ArrayList");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
IMethod m = type.getMethod("<init>", Stream.of(IPrimitiveType.INT));
assertEquals(m.getDeclaringType().getElementName(), m.getElementName());
@@ -139,7 +145,7 @@ public class JavaIndexTest {
@Test
public void testFindJarResource() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
Optional<File> jar = project.getClasspath().findClasspathResourceContainer("org.springframework.boot.autoconfigure.SpringBootApplication");
Optional<File> jar = project.findClasspathResourceContainer("org.springframework.boot.autoconfigure.SpringBootApplication");
assertTrue(jar.isPresent());
assertEquals("spring-boot-autoconfigure-1.4.1.RELEASE.jar", jar.get().getName());
}
@@ -147,9 +153,9 @@ public class JavaIndexTest {
@Test
public void testFindJavaResource() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
Optional<File> file = project.getClasspath().findClasspathResourceContainer("hello.GreetingController");
Optional<File> file = project.findClasspathResourceContainer("hello.GreetingController");
assertTrue(file.isPresent());
assertTrue(file.get().exists());
assertEquals(project.getClasspath().getOutputFolder().toString(), file.get().toString());
assertEquals(getOutputFolder(project).toString(), file.get().toString());
}
}

View File

@@ -133,7 +133,7 @@ public class MavenProjectCacheTest {
assertNotNull(cachedProject);
ImmutableList<CPE> calculatedClassPath = cachedProject.getClasspath().getClasspathEntries();
assertEquals(48, calculatedClassPath.size());
assertEquals(50, calculatedClassPath.stream().filter(cpe -> !cpe.isSystem()).count());
fileObserver.notifyFileChanged(pomFile.toURI().toString());
assertNull(projectChanged[0]);
@@ -144,7 +144,7 @@ public class MavenProjectCacheTest {
assertNotNull(projectChanged[0]);
assertEquals(cachedProject, projectChanged[0]);
calculatedClassPath = cachedProject.getClasspath().getClasspathEntries();
assertEquals(49, calculatedClassPath.size());
assertEquals(51, calculatedClassPath.stream().filter(cpe -> !cpe.isSystem()).count());
fileObserver.notifyFileDeleted(pomFile.toURI().toString());
assertEquals(cachedProject, projectDeleted[0]);
@@ -190,7 +190,7 @@ public class MavenProjectCacheTest {
}).get(30, TimeUnit.SECONDS);
assertTrue(classpathCacheFile.exists());
assertEquals(48, project.getClasspath().getClasspathEntries().size());
assertEquals(50, project.getClasspath().getClasspathEntries().stream().filter(cpe -> !cpe.isSystem()).count());
progressDone.set(false);
@@ -199,7 +199,7 @@ public class MavenProjectCacheTest {
// Check loaded from cache file
project = cache.project(pomFile);
assertEquals(48, project.getClasspath().getClasspathEntries().size());
assertEquals(50, project.getClasspath().getClasspathEntries().stream().filter(cpe -> !cpe.isSystem()).count());
}
@Test

View File

@@ -44,6 +44,11 @@
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>${reactor-version}</version>
</dependency>
<!-- HTM -> Markdown converter -->
<dependency>
<groupId>com.kotcrab.remark</groupId>

View File

@@ -24,6 +24,8 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.ImmutablePair;
import reactor.core.Disposable;
/**
* Basic implementation of File Observer interface
*
@@ -87,10 +89,26 @@ public class BasicFileObserver implements FileObserver {
Path path = Paths.get(URI.create(uri));
registry.values().stream()
.filter(pair -> pair.left.stream()
.filter(matcher -> matcher.matches(path))
.filter(matcher ->
matcher.matches(path)
)
.findFirst()
.isPresent())
.forEach(pair -> pair.right.accept(uri));
}
@Override
public Disposable onAnyChange(List<String> globPattern, Consumer<String> handler) {
String[] ids = {
onFileChanged(globPattern, handler),
onFileCreated(globPattern, handler),
onFileDeleted(globPattern, handler)
};
return () -> {
for (String id : ids) {
unsubscribe(id);
}
};
}
}

View File

@@ -13,6 +13,8 @@ package org.springframework.ide.vscode.commons.util;
import java.util.List;
import java.util.function.Consumer;
import reactor.core.Disposable;
/**
* Object able to add/remove {@link FileListener} objects and fire events via these listeners
*
@@ -28,5 +30,7 @@ public interface FileObserver {
String onFileDeleted(List<String> globPattern, Consumer<String> handler);
boolean unsubscribe(String subscriptionId);
Disposable onAnyChange(List<String> globPattern, Consumer<String> handler);
}

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* 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.languageserver.testharness;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath;
import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE;
public class ClasspathTestUtil {
public static Path getOutputFolder(IJavaProject jp) throws Exception {
for (CPE cpe : jp.getClasspath().getClasspathEntries()) {
if (Classpath.isSource(cpe)) {
if (cpe.getPath().endsWith("main/java")) {
return Paths.get(cpe.getOutputFolder());
}
}
}
return null;
}
}

View File

@@ -1,20 +1,31 @@
/*******************************************************************************
* 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.tooling.jdt.ls.commons.classpath;
import java.io.File;
import java.net.URL;
import java.util.List;
import org.eclipse.core.runtime.Assert;
public class Classpath {
public static final String ENTRY_KIND_SOURCE = "source";
public static final String ENTRY_KIND_BINARY = "binary";
public static final String OUTPUT_LOCATION = "output_location";
private List<CPE> entries;
private String defaultOutputFolder;
public Classpath(List<CPE> entries, String defaultOutputFolder) {
public Classpath(List<CPE> entries) {
super();
this.entries = entries;
this.defaultOutputFolder = defaultOutputFolder;
}
public List<CPE> getEntries() {
@@ -25,38 +36,43 @@ public class Classpath {
this.entries = entries;
}
public String getDefaultOutputFolder() {
return defaultOutputFolder;
}
public void setDefaultOutputFolder(String defaultOutputFolder) {
this.defaultOutputFolder = defaultOutputFolder;
}
@Override
public String toString() {
return "Classpath [entries=" + entries + ", defaultOutputFolder=" + defaultOutputFolder + "]";
return "Classpath [entries=" + entries + "]";
}
public static class CPE {
// TODO: it seems like a good idea to make all classpath entries the same in that they all have
// - a place with source code
// - a place with compiled code
// - a place with java doc
// So it seems like we should be able to chnage this so that the same named attribute is used
// in both cases (rather then one be 'getOutputFolder' and one 'getPath' to obtain location of the compiled code).
private String kind;
private String path;
private String path; // TODO: Change to File, Path or URL?
private String outputFolder;
private URL sourceContainerUrl;
private URL javadocContainerUrl;
private boolean isSystem = false;
public String getOutputFolder() {
return outputFolder;
}
public void setOutputFolder(String outputFolder) {
Assert.isLegal(new File(outputFolder).isAbsolute());
this.outputFolder = outputFolder;
}
public CPE() {}
public CPE(String kind, String path) {
private CPE(String kind, String path) {
super();
this.kind = kind;
this.path = path;
setPath(path);
}
public String getKind() {
@@ -72,13 +88,47 @@ public class Classpath {
}
public void setPath(String path) {
Assert.isLegal(path == null || new File(path).isAbsolute());
this.path = path;
}
@Override
public String toString() {
return "CPE [kind=" + kind + ", path=" + path + ", outputFolder=" + outputFolder + "]";
public URL getJavadocContainerUrl() {
return javadocContainerUrl;
}
public void setJavadocContainerUrl(URL javadocContainerUrl) {
this.javadocContainerUrl = javadocContainerUrl;
}
public URL getSourceContainerUrl() {
return sourceContainerUrl;
}
public void setSourceContainerUrl(URL sourceContainerUrl) {
this.sourceContainerUrl = sourceContainerUrl;
}
public static CPE binary(String path) {
return new CPE(ENTRY_KIND_BINARY, path);
}
public static CPE source(File sourceFolder, File outputFolder) {
CPE cpe = new CPE(ENTRY_KIND_SOURCE, sourceFolder.getAbsolutePath());
cpe.setOutputFolder(outputFolder.getAbsolutePath());
return cpe;
}
public boolean isSystem() {
return isSystem;
}
public void setSystem(boolean isSystem) {
this.isSystem = isSystem;
}
}
public static boolean isSource(CPE e) {
return e!=null && Classpath.ENTRY_KIND_SOURCE.equals(e.getKind());
}
}

View File

@@ -39,7 +39,7 @@ public class ClasspathUtil {
switch (kind) {
case Classpath.ENTRY_KIND_BINARY: {
String path = entry.getPath().toString();
CPE cpe = new CPE(kind, path);
CPE cpe = CPE.binary(path);
cpEntries.add(cpe);
break;
}
@@ -49,15 +49,15 @@ public class ClasspathUtil {
IPath absoluteSourcePath = resolveWorkspacePath(sourcePath);
//log("absoluteSourcePath =" + absoluteSourcePath);
if (absoluteSourcePath!=null) {
CPE cpe = new CPE(kind, absoluteSourcePath.toString());
IPath of = entry.getOutputLocation();
//log("outputFolder =" + of);
IPath absoluteOutFolder;
if (of!=null) {
IPath absoluteOutFolder = resolveWorkspacePath(of);
//log("absoluteOutFolder =" + absoluteOutFolder);
cpe.setOutputFolder(absoluteOutFolder.toString());
absoluteOutFolder = resolveWorkspacePath(of);
} else {
absoluteOutFolder = resolveWorkspacePath(javaProject.getOutputLocation());
}
cpEntries.add(cpe);
cpEntries.add(CPE.source(absoluteSourcePath.toFile(), absoluteOutFolder.toFile()));
}
break;
}
@@ -66,8 +66,7 @@ public class ClasspathUtil {
}
}
}
Classpath classpath = new Classpath(cpEntries, resolveWorkspacePath(javaProject.getOutputLocation()).toString());
log("classpath.outputFolder=" + classpath.getDefaultOutputFolder());
Classpath classpath = new Classpath(cpEntries);
log("classpath=" + classpath.getEntries().size() + " entries");
return classpath;
}

View File

@@ -35,6 +35,7 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyA
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
@@ -267,8 +268,8 @@ public class BootJavaHoverProvider implements HoverHandler {
try {
IClasspath classpath = project.getClasspath();
if (classpath!=null) {
return classpath.getClasspathEntryPaths().stream().anyMatch(cpe -> {
String name = cpe.getFileName().toString();
return IClasspathUtil.getBinaryRoots(classpath).stream().anyMatch(cpe -> {
String name = cpe.getName();
return name.startsWith("spring-boot-actuator-");
});
}

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
@@ -27,6 +28,7 @@ import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.ReferenceParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
@@ -125,10 +127,11 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
private String[] getClasspathEntries(IDocument doc) throws Exception {
IJavaProject project = this.projectFinder.find(new TextDocumentIdentifier(doc.getUri())).get();
IClasspath classpath = project.getClasspath();
Stream<Path> classpathEntries = classpath.getClasspathEntryPaths().stream();
Stream<File> classpathEntries = IClasspathUtil.getBinaryRoots(classpath).stream();
return classpathEntries
.filter(path -> path.toFile().exists())
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
.filter(file -> file.exists())
.map(file -> file.getAbsolutePath())
.toArray(String[]::new);
}
}

View File

@@ -33,8 +33,9 @@ import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer;
import org.springframework.ide.vscode.commons.javadoc.TypeUrlProviderFromContainerUrl;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -59,7 +60,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
@Override
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
Optional<File> classpathResource = project.getClasspath().findClasspathResourceContainer(fqName);
Optional<File> classpathResource = project.getIndex().findClasspathResourceContainer(fqName);
if (classpathResource.isPresent()) {
File file = classpathResource.get();
if (file.isDirectory()) {
@@ -83,10 +84,10 @@ public abstract class AbstractSourceLinks implements SourceLinks {
private Optional<String> javaSourceLinkUrl(IJavaProject project, String fqName, File containerFolder) {
IClasspath classpath = project.getClasspath();
return project.getClasspath().getSourceFolders().stream()
return IClasspathUtil.getSourceFolders(classpath)
.map(sourceFolder -> {
try {
return Paths.get(sourceFolder).toUri().toURL();
return sourceFolder.toURI().toURL();
} catch (MalformedURLException e) {
LOG.get().warn("Failed to convert source folder " + sourceFolder + "to URI." + fqName, e);
return null;
@@ -94,7 +95,7 @@ public abstract class AbstractSourceLinks implements SourceLinks {
})
.map(url -> {
try {
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER.sourceUrl(url, fqName);
return TypeUrlProviderFromContainerUrl.SOURCE_FOLDER_URL_SUPPLIER.url(url, fqName);
} catch (Exception e) {
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
return null;
@@ -163,10 +164,10 @@ public abstract class AbstractSourceLinks implements SourceLinks {
private Optional<CompilationUnit> findCUForFQNameFromJar(IJavaProject project, File jarFile, String clientSourceUri, String fqName) {
Optional<CompilationUnit> cu = findCUfromCache(clientSourceUri);
if (cu == null) {
cu = project.getClasspath().sourceContainer(jarFile)
cu = project.sourceContainer(jarFile)
.map(url -> {
try {
return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(url, fqName);
return TypeUrlProviderFromContainerUrl.JAR_SOURCE_URL_PROVIDER.url(url, fqName);
} catch (Exception e) {
LOG.get().warn("Failed to determine source URL from url=" + url + " fqName=" + fqName, e);
return null;

View File

@@ -10,8 +10,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.utils;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -27,6 +27,7 @@ import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
@@ -172,10 +173,10 @@ public final class CompilationUnitCache {
return new String[0];
} else {
IClasspath classpath = project.getClasspath();
Stream<Path> classpathEntries = classpath.getClasspathEntryPaths().stream();
Stream<File> classpathEntries = IClasspathUtil.getBinaryRoots(classpath).stream();
return classpathEntries
.filter(path -> path.toFile().exists())
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
.filter(file -> file.exists())
.map(file -> file.getAbsolutePath()).toArray(String[]::new);
}
}

View File

@@ -63,6 +63,7 @@ import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformati
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
@@ -619,10 +620,11 @@ public class SpringIndexer {
private String[] getClasspathEntries(IJavaProject project) throws Exception {
IClasspath classpath = project.getClasspath();
Stream<Path> classpathEntries = classpath.getClasspathEntryPaths().stream();
Stream<File> classpathEntries = IClasspathUtil.getBinaryRoots(classpath).stream();
return classpathEntries
.filter(path -> path.toFile().exists())
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
.filter(file -> file.exists())
.map(file -> file.getAbsolutePath())
.toArray(String[]::new);
}
/**

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.utils;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
@@ -18,6 +19,7 @@ import java.util.regex.Pattern;
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.Renderables;
@@ -83,9 +85,12 @@ public class SpringResource {
private String projectRelativePath(String pathStr) {
Path path = Paths.get(pathStr);
IClasspath classpath = project.getClasspath();
Path outputFolder = classpath.getOutputFolder();
if (path.startsWith(outputFolder)) {
return outputFolder.relativize(path).toString();
Iterable<File> ofs = () -> IClasspathUtil.getOutputFolders(classpath).iterator();
for (File _outputFolder : ofs) {
Path outputFolder = _outputFolder.toPath();
if (path.startsWith(outputFolder)) {
return outputFolder.relativize(path).toString();
}
}
return pathStr;
}

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.boot.jdt.ls;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -32,6 +33,7 @@ import org.springframework.ide.vscode.commons.java.ClasspathData;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.JavaProject;
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.languageserver.jdt.ls.ClasspathListener;
@@ -39,6 +41,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.UriUtil;
import com.google.common.base.Supplier;
@@ -53,7 +56,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
private CompletableFuture<Void> initialized = new CompletableFuture<Void>();
private SimpleLanguageServer server;
private Map<String, JdtLsProject> table = new HashMap<String, JdtLsProject>();
private Map<String, JavaProject> table = new HashMap<String, JavaProject>();
private Logger log = LoggerFactory.getLogger(JdtLsProjectCache.class);
private List<Listener> listeners = new ArrayList<>();
@@ -70,20 +73,24 @@ public class JdtLsProjectCache implements JavaProjectsService {
@Override
public void changed(Event event) {
initialized.thenRun(() -> {
synchronized (table) {
String uri = UriUtil.normalize(event.projectUri);
if (event.deleted) {
JdtLsProject deleted = table.remove(uri);
notifyDelete(deleted);
} else {
JdtLsProject newProject = new JdtLsProject(event.name, uri, event.classpath);
JdtLsProject oldProject = table.put(uri, newProject);
if (oldProject != null) {
notifyChanged(newProject);
try {
synchronized (table) {
String uri = UriUtil.normalize(event.projectUri);
if (event.deleted) {
JavaProject deleted = table.remove(uri);
notifyDelete(deleted);
} else {
notifyCreated(newProject);
JavaProject newProject = new JavaProject(getFileObserver(), new URI(uri), new ClasspathData(event.name, event.classpath.getEntries()));
JavaProject oldProject = table.put(uri, newProject);
if (oldProject != null) {
notifyChanged(newProject);
} else {
notifyCreated(newProject);
}
}
}
} catch (Exception e) {
log.error("", e);
}
});
}
@@ -106,6 +113,10 @@ public class JdtLsProjectCache implements JavaProjectsService {
);
}
private FileObserver getFileObserver() {
return server.getWorkspaceService().getFileObserver();
}
private boolean isOldJdt(Throwable e) {
return ExceptionUtil.getMessage(e).contains("'sts.java.addClasspathListener' not supported");
}
@@ -142,7 +153,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
});
}
private void notifyCreated(JdtLsProject newProject) {
private void notifyCreated(JavaProject newProject) {
logEvent("Created", newProject);
synchronized (listeners) {
for (Listener listener : listeners) {
@@ -151,16 +162,17 @@ public class JdtLsProjectCache implements JavaProjectsService {
}
}
private void notifyDelete(JdtLsProject deleted) {
private void notifyDelete(JavaProject deleted) {
logEvent("Deleted", deleted);
synchronized (listeners) {
for (Listener listener : listeners) {
listener.deleted(deleted);
}
}
deleted.dispose();
}
private void notifyChanged(JdtLsProject newProject) {
private void notifyChanged(JavaProject newProject) {
logEvent("Changed", newProject);
synchronized (listeners) {
for (Listener listener : listeners) {
@@ -169,7 +181,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
}
}
private void logEvent(String type, JdtLsProject newProject) {
private void logEvent(String type, JavaProject newProject) {
try {
log.info("Project "+type+": " + newProject.getLocationUri());
log.info("Classpath has "+newProject.getClasspath().getClasspathEntries().size()+" entries");
@@ -190,7 +202,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
}
synchronized (table) {
for (Entry<String, JdtLsProject> e : table.entrySet()) {
for (Entry<String, JavaProject> e : table.entrySet()) {
String projectUri = e.getKey();
log.debug("projectUri = '{}'", projectUri);
if (UriUtil.contains(projectUri, uri) ) {
@@ -206,98 +218,4 @@ public class JdtLsProjectCache implements JavaProjectsService {
return Optional.empty();
}
private class JdtLsProject implements IJavaProject {
private final JdtClasspath classpath;
public JdtLsProject(String name, String projectUri, Classpath classpath) {
this.classpath = new JdtClasspath(name, projectUri, classpath);
}
@Override
public IClasspath getClasspath() {
return classpath;
}
public String getLocationUri() {
return classpath.projectUri;
}
}
private class JdtClasspath extends JandexClasspath {
private Classpath classpath;
private String name;
private String projectUri;
public JdtClasspath(String name, String uri, Classpath classpath) {
this.name = name;
this.projectUri = uri;
this.classpath = classpath;
}
@Override
public String getName() {
return this.name;
}
@Override
public boolean exists() {
return new File(projectUri).exists();
}
@Override
public Path getOutputFolder() {
return Paths.get(classpath.getDefaultOutputFolder());
}
@Override
public Collection<CPE> getClasspathEntries() throws Exception {
return classpath.getEntries();
}
@Override
public ImmutableList<String> getClasspathResources() {
// TODO Auto-generated method stub
return null;
}
@Override
public ImmutableList<String> getSourceFolders() {
ImmutableList.Builder<String> sourceEntries = ImmutableList.builder();
try {
for (CPE e : getClasspathEntries()) {
if (Classpath.isSource(e)) {
sourceEntries.add(e.getPath());
}
}
} catch (Exception e) {
log.error("", e);
}
return sourceEntries.build();
}
@Override
public ClasspathData createClasspathData() throws Exception {
// We should not be needing this as we dont use DelegatingCachedClasspath
throw new UnsupportedOperationException("Not supported for JDT classpath: ");
}
@Override
public Optional<URL> sourceContainer(File classpathResource) {
// TODO Auto-generated method stub
return null;
}
@Override
protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) {
// TODO Auto-generated method stub
return null;
}
}
}

View File

@@ -131,11 +131,11 @@ public class ClassReferenceProvider extends CachingValueProvider {
@Override
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
IType targetType = target == null || target.isEmpty() ? javaProject.getClasspath().findType("java.lang.Object") : javaProject.getClasspath().findType(target);
IType targetType = target == null || target.isEmpty() ? javaProject.findType("java.lang.Object") : javaProject.findType(target);
if (targetType == null) {
return Flux.empty();
}
Set<IType> allSubclasses = javaProject.getClasspath()
Set<IType> allSubclasses = javaProject
.allSubtypesOf(targetType)
.filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t))
.collect(Collectors.toSet())
@@ -143,7 +143,7 @@ public class ClassReferenceProvider extends CachingValueProvider {
if (allSubclasses.isEmpty()) {
return Flux.empty();
} else {
return javaProject.getClasspath()
return javaProject
.fuzzySearchTypes(query, type -> allSubclasses.contains(type))
.collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2()))
.flatMapIterable(l -> l)

View File

@@ -37,10 +37,10 @@ public class LoggerNameProvider extends CachingValueProvider {
@Override
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
return Flux.concat(
javaProject.getClasspath()
javaProject.getIndex()
.fuzzySearchPackages(query)
.map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())),
javaProject.getClasspath()
javaProject.getIndex()
.fuzzySearchTypes(query, null)
.map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2()))
)

View File

@@ -25,6 +25,7 @@ import java.util.zip.ZipEntry;
import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataRepository;
import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.util.Log;
public class PropertiesLoader {
@@ -55,14 +56,12 @@ public class PropertiesLoader {
public ConfigurationMetadataRepository load(IClasspath classPath) {
try {
classPath.getClasspathEntryPaths().forEach(entry -> {
//Log.info("Indexing "+entry);
File fileEntry = entry.toFile();
IClasspathUtil.getBinaryRoots(classPath).forEach(fileEntry -> {
if (fileEntry.exists()) {
if (fileEntry.isDirectory()) {
loadFromOutputFolder(entry);
loadFromOutputFolder(fileEntry.toPath());
} else {
loadFromJar(entry);
loadFromJar(fileEntry.toPath());
}
}
});

View File

@@ -63,7 +63,11 @@ public class ResourceHintProvider implements ValueProviderStrategy {
private static class ClasspathHints extends CachingValueProvider {
@Override
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
return Flux.fromStream(javaProject.getClasspath().getClasspathResources().stream().distinct().map(r -> r.replaceAll("\\\\", "/")).map(StsValueHint::create));
return Flux.fromStream(
javaProject.getClasspathResources().stream()
.distinct().map(r -> r.replaceAll("\\\\", "/"))
.map(StsValueHint::create)
);
}
}

View File

@@ -79,7 +79,7 @@ public class StsValueHint {
try {
IJavaProject jp = typeUtil.getJavaProject();
if (jp!=null) {
IType type = jp.getClasspath().findType(fqName);
IType type = jp.findType(fqName);
if (type!=null) {
return create(type);
}

View File

@@ -557,7 +557,7 @@ public class TypeUtil {
private IType findType(String typeName) {
try {
if (javaProject!=null) {
return javaProject.getClasspath().findType(typeName);
return javaProject.findType(typeName);
}
} catch (Exception e) {
Log.log(e);

View File

@@ -73,7 +73,7 @@ public class AutowiredHoverProviderTest {
.build();
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app", FOO_INTERFACE);
assertTrue(jp.getClasspath().findType("com.example.Foo").exists());
assertTrue(jp.findType("com.example.Foo").exists());
harness.useProject(projects.mavenProject("empty-boot-15-web-app"));
harness.intialize(null);
}

View File

@@ -56,7 +56,7 @@ public class BeanInjectedIntoHoverProviderTest {
.build();
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app", FOO_INTERFACE);
assertTrue(jp.getClasspath().findType("hello.Foo").exists());
assertTrue(jp.findType("hello.Foo").exists());
harness.useProject(jp);
harness.intialize(null);
}

View File

@@ -70,7 +70,7 @@ public class ComponentInjectionsHoverProviderTest {
.build();
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app", EXTRA_TYPES);
assertTrue(jp.getClasspath().findType("com.example.Foo").exists());
assertTrue(jp.findType("com.example.Foo").exists());
harness.useProject(jp);
harness.intialize(null);
}

View File

@@ -27,6 +27,7 @@ import org.junit.Test;
import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.JavaProject;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -52,12 +53,7 @@ public class CompilationUnitCacheTest {
public void cu_cached() throws Exception {
harness = BootJavaLanguageServerHarness.builder()
.mockDefaults().build();
harness.useProject(new IJavaProject() {
@Override
public IClasspath getClasspath() {
return new DelegatingCachedClasspath<>(() -> null, null);
}
});
harness.useProject(ProjectsHarness.dummyProject());
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
@@ -94,12 +90,7 @@ public class CompilationUnitCacheTest {
public void cu_cache_invalidated_by_doc_change() throws Exception {
harness = BootJavaLanguageServerHarness.builder()
.mockDefaults().build();
harness.useProject(new IJavaProject() {
@Override
public IClasspath getClasspath() {
return new DelegatingCachedClasspath<>(() -> null, null);
}
});
harness.useProject(ProjectsHarness.dummyProject());
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
@@ -125,12 +116,7 @@ public class CompilationUnitCacheTest {
public void cu_cache_invalidated_by_doc_close() throws Exception {
harness = BootJavaLanguageServerHarness.builder()
.mockDefaults().build();
harness.useProject(new IJavaProject() {
@Override
public IClasspath getClasspath() {
return new DelegatingCachedClasspath<>(() -> null, null);
}
});
harness.useProject(ProjectsHarness.dummyProject());
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +

View File

@@ -24,6 +24,8 @@ import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks;
import org.springframework.ide.vscode.commons.maven.MavenBuilder;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@@ -43,7 +45,7 @@ public class VSCodeSourceLinksTest {
public MavenJavaProject load(String projectName) throws Exception {
Path testProjectPath = Paths.get(VSCodeSourceLinksTest.class.getResource("/test-projects/" + projectName).toURI());
MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute();
return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
return MavenJavaProject.create(new BasicFileObserver(), MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
}
});

View File

@@ -68,8 +68,8 @@ public class TypeUtilTest {
@Test
public void testGetProperties() throws Exception {
useProject("enums-boot-1.3.2-app");
assertNotNull(project.getClasspath().findType("demo.Color"));
assertNotNull(project.getClasspath().findType("demo.ColorData"));
assertNotNull(project.findType("demo.Color"));
assertNotNull(project.findType("demo.ColorData"));
Type data = TypeParser.parse("demo.ColorData");

View File

@@ -40,10 +40,13 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import static org.springframework.ide.vscode.languageserver.testharness.ClasspathTestUtil.*;
/**
* Boot App Properties Editor tests
*
@@ -220,7 +223,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
@Test public void testPredefinedProject() throws Exception {
IJavaProject p = createPredefinedMavenProject("tricky-getters-boot-1.3.1-app");
IType type = p.getClasspath().findType("demo.DemoApplication");
IType type = p.findType("demo.DemoApplication");
assertNotNull(type);
}
@@ -229,7 +232,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
//Check some assumptions about the initial state of the test project (if these checks fail then
// the test may be 'vacuous' since the things we are testing for already exist beforehand.
Path metadataFile = p.getClasspath().getOutputFolder().resolve(PropertiesLoader.PROJECT_META_DATA_LOCATIONS[0]);
Path metadataFile = getOutputFolder(p).resolve(PropertiesLoader.PROJECT_META_DATA_LOCATIONS[0]);
assertTrue(metadataFile.toFile().isFile());
assertContains("\"name\": \"foo.counter\"", Files.toString(metadataFile.toFile(), Charset.forName("UTF8")));
}
@@ -294,7 +297,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Foo"));
assertNotNull(p.findType("demo.Foo"));
Editor editor = newEditor(
"token.bad.guy=problem\n"+
@@ -319,7 +322,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Foo"));
assertNotNull(p.findType("demo.Foo"));
assertCompletionsVariations("volder.foo.l<*>", "volder.foo.list[<*>");
assertCompletionsDisplayStringAndDetail("volder.foo.list[0].<*>",
@@ -468,7 +471,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
data("foo.colors", "java.util.List<demo.Color>", null, "A foonky list");
@@ -491,7 +494,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
data("foo.color", "demo.Color", null, "A foonky colour");
@@ -510,7 +513,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
data("foo.color", "demo.Color", null, "A foonky colour");
Editor editor = newEditor(
@@ -533,7 +536,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
assertCompletionsVariations("foo.nam<*>",
"foo.name-colors.<*>",
@@ -552,7 +555,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
useProject(p);
data("foo.name-colors", "java.util.Map<java.lang.String,demo.Color>", null, "Map with colors in its values");
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
Editor editor = newEditor(
"foo.name-colors.jacket=BLUE\n" +
@@ -571,8 +574,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
useProject(p);
data("foo.color-names", "java.util.Map<demo.Color,java.lang.String>", null, "Map with colors in its keys");
data("foo.color-data", "java.util.Map<demo.Color,demo.ColorData>", null, "Map with colors in its keys, and pojo in values");
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
//Map Enum -> String:
assertCompletionsVariations("foo.colnam<*>", "foo.color-names.<*>");
@@ -611,8 +614,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
Editor editor = newEditor(
"foo.color-names.RED=Rood\n"+
@@ -631,8 +634,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
assertCompletion("foo.dat<*>", "foo.data.<*>");
@@ -666,8 +669,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
Editor editor = newEditor(
"foo.data.bogus=Something\n" +
@@ -701,8 +704,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
data("atommap", "java.util.Map<java.lang.String,java.lang.Integer>", null, "map of atomic data");
data("objectmap", "java.util.Map<java.lang.String,java.lang.Object>", null, "map of atomic object (recursive map)");
@@ -741,8 +744,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.getClasspath().findType("demo.ColorData"));
assertNotNull(p.findType("demo.Color"));
assertNotNull(p.findType("demo.ColorData"));
Editor editor = newEditor(
"foo.color-names.BLUE.dot=Blauw\n"+
@@ -767,7 +770,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.ClothingSize"));
assertNotNull(p.findType("demo.ClothingSize"));
data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size");
@@ -811,7 +814,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.ClothingSize"));
assertNotNull(p.findType("demo.ClothingSize"));
data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size");
@@ -1414,7 +1417,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
data("my.colors", collectionType+"<demo.Color>", null, "Ooh! nice colors!");

View File

@@ -585,7 +585,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
@Test public void testReconcileBeanPropName() throws Exception {
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Foo"));
assertNotNull(p.findType("demo.Foo"));
data("some-foo", "demo.Foo", null, "some Foo pojo property");
Editor editor = newEditor(
"some-foo:\n" +
@@ -617,7 +617,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
@Test public void testReconcilePojoArray() throws Exception {
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Foo"));
assertNotNull(p.findType("demo.Foo"));
{
Editor editor = newEditor(
@@ -694,7 +694,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
@Test public void testEnumPropertyReconciling() throws Exception {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.Color"));
assertNotNull(p.findType("demo.Color"));
data("foo.color", "demo.Color", null, "A foonky colour");
Editor editor = newEditor(
@@ -1876,7 +1876,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
@Ignore @Test public void testEnumsInLowerCaseContentAssist() throws Exception {
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
useProject(p);
assertNotNull(p.getClasspath().findType("demo.ClothingSize"));
assertNotNull(p.findType("demo.ClothingSize"));
data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size");

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.project.harness;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import org.junit.Assert;
@@ -20,10 +21,13 @@ import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.composable.ComposableLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
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.languageserver.util.LSFactory;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
@@ -135,9 +139,16 @@ public class BootJavaLanguageServerHarness extends LanguageServerHarness<Composa
indexHarness.useProject(p);
}
public Path getOutputFolder() {
return getProjectFinder().find(null).get().getClasspath().getOutputFolder();
public Path getOutputFolder() throws Exception {
IClasspath classpath = getProjectFinder().find(null).get().getClasspath();
for (CPE cpe : classpath.getClasspathEntries()) {
if (Classpath.isSource(cpe)) {
if (cpe.getPath().endsWith("main/java")) {
return Paths.get(cpe.getOutputFolder());
}
}
}
return null;
}
}

View File

@@ -19,10 +19,16 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.JavaProject;
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.maven.MavenBuilder;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.IOUtil;
import com.google.common.cache.Cache;
@@ -40,10 +46,12 @@ import reactor.util.function.Tuples;
*/
public class ProjectsHarness {
public static final ProjectsHarness INSTANCE = new ProjectsHarness();;
public static final ProjectsHarness INSTANCE = new ProjectsHarness(new BasicFileObserver());
public Cache<Object, IJavaProject> cache = CacheBuilder.newBuilder().concurrencyLevel(1).build();
private final FileObserver fileObserver;
/**
* A callback that is given a chance to make changes to test project contents before the test project
* is created from it.
@@ -81,8 +89,13 @@ public class ProjectsHarness {
MAVEN
// GRADLE?
}
public static final IJavaProject dummyProject() throws URISyntaxException {
return new JavaProject(new BasicFileObserver(), new URI("file:///someplace/nonexistent"), new DelegatingCachedClasspath(() -> null, null));
}
private ProjectsHarness() {
private ProjectsHarness(FileObserver fileObserver) {
this.fileObserver = fileObserver;
}
public IJavaProject project(ProjectType type, String name, ProjectCustomizer customizer) throws Exception {
@@ -100,7 +113,7 @@ public class ProjectsHarness {
switch (type) {
case MAVEN:
MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute();
return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
return MavenJavaProject.create(fileObserver, MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile());
default:
throw new IllegalStateException("Bug!!! Missing case");
}
@@ -129,4 +142,5 @@ public class ProjectsHarness {
public MavenJavaProject mavenProject(String name) throws Exception {
return (MavenJavaProject) project(ProjectType.MAVEN, name);
}
}