Avoid caching maven projects in the maven classpath.

Instead extract all the required information into classpath data and
cache that instead.
This commit is contained in:
nsingh
2018-01-24 16:12:30 -08:00
parent aa41817081
commit f7978ba94b
6 changed files with 123 additions and 84 deletions

View File

@@ -25,6 +25,7 @@ import org.gradle.tooling.model.build.BuildEnvironment;
import org.gradle.tooling.model.eclipse.EclipseProject;
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.java.parser.ParserJavadocProvider;
@@ -241,5 +242,10 @@ public class GradleProjectClasspath extends JandexClasspath {
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());
}
}

View File

@@ -57,12 +57,17 @@ public abstract class JandexClasspath implements IClasspath {
Log.log(e);
}
return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> {
switch (providerType) {
case JAVA_PARSER:
return createParserJavadocProvider(classpathResource);
default:
return createHtmlJavdocProvider(classpathResource);
try {
switch (providerType) {
case JAVA_PARSER:
return createParserJavadocProvider(classpathResource);
default:
return createHtmlJavdocProvider(classpathResource);
}
} catch (Exception e) {
Log.log(e);
}
return null;
}, getBaseIndices());
}
@@ -103,8 +108,8 @@ public abstract class JandexClasspath implements IClasspath {
return javaIndex.get().findClasspathResourceForType(fqName);
}
abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource);
abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource) throws Exception;
abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource);
abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) throws Exception;
}

View File

@@ -19,7 +19,6 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
@@ -55,45 +54,11 @@ import reactor.util.function.Tuple2;
public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspath {
public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json";
private static final ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(),
Collections.emptySet(), null);
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";
protected static class ClasspathData {
final public String name;
final public Set<Path> classpathEntries;
final public Set<String> classpathResources;
final public Path outputFolder;
public ClasspathData(String name, Set<Path> classpathEntries, Set<String> classpathResources, Path outputFolder) {
this.name = name;
this.classpathEntries = classpathEntries;
this.classpathResources = classpathResources;
this.outputFolder = outputFolder;
}
@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;
}
}
private AtomicReference<ClasspathData> cachedData;
private Callable<T> delegateCreator;
@@ -245,16 +210,17 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
return t == null ? Flux.empty() : t.allSubtypesOf(type);
}
protected ClasspathData createClasspathData() throws Exception {
@Override
public ClasspathData createClasspathData() throws Exception {
T newDelegate = delegateCreator.call();
cachedDelegate.set(newDelegate);
if (newDelegate == null) {
return EMPTY_CLASSPATH_DATA;
} else {
LinkedHashSet<Path> classpathEntries = new LinkedHashSet<>(newDelegate.getClasspathEntries());
return new ClasspathData(newDelegate.getName(), classpathEntries,
new LinkedHashSet<>(newDelegate.getClasspathResources()), newDelegate.getOutputFolder());
}
if (newDelegate != null) {
ClasspathData data = newDelegate.createClasspathData();
if (data != null) {
return data;
}
}
return EMPTY_CLASSPATH_DATA;
}
@Override

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.commons.java;
import java.io.File;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Optional;
import java.util.function.Predicate;
@@ -60,5 +61,10 @@ public interface IClasspath {
ImmutableList<String> getSourceFolders();
Optional<File> findClasspathResourceContainer(String fqName);
ClasspathData createClasspathData() throws Exception;
public static final ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(),
Collections.emptySet(), null);
}

View File

@@ -16,17 +16,19 @@ import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
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.IJavadocProvider;
import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider;
import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider;
@@ -48,13 +50,13 @@ public class MavenProjectClasspath extends JandexClasspath {
private MavenCore maven;
private File pom;
private MavenProject project;
private MavenClasspathData cachedData;
MavenProjectClasspath(MavenCore maven, File pom) throws MavenException {
MavenProjectClasspath(MavenCore maven, File pom) throws Exception {
super();
this.maven = maven;
this.pom = pom;
this.project = createMavenProject();
this.cachedData = createClasspathData();
}
@Override
@@ -85,24 +87,28 @@ public class MavenProjectClasspath extends JandexClasspath {
}
public String getName() {
return project == null ? null : project.getArtifact().getArtifactId();
return cachedData != null ? cachedData.name : null;
}
private ImmutableList<Path> resolveClasspathEntries(MavenProject project) throws Exception {
// return Stream.concat(maven.resolveDependencies(project, null).stream().map(artifact -> {
// return artifact.getFile().toPath();
// }), projectResolvedOutput());
ImmutableList<Path> classpathEntries = ImmutableList.copyOf(Stream.concat(projectDependencies(project).stream().map(a -> a.getFile().toPath()),
projectOutput(project).stream().map(f -> f.toPath())).collect(Collectors.toList()));
return classpathEntries;
}
@Override
public ImmutableList<Path> getClasspathEntries() throws Exception {
// return Stream.concat(maven.resolveDependencies(project, null).stream().map(artifact -> {
// return artifact.getFile().toPath();
// }), projectResolvedOutput());
ImmutableList<Path> classpathEntries = ImmutableList.copyOf(Stream.concat(projectDependencies().stream().map(a -> a.getFile().toPath()),
projectOutput().stream().map(f -> f.toPath())).collect(Collectors.toList()));
return classpathEntries;
return cachedData != null ? ImmutableList.copyOf(cachedData.classpathEntries) : ImmutableList.of();
}
private Set<Artifact> projectDependencies() {
private Set<Artifact> projectDependencies(MavenProject project) {
return project == null ? Collections.emptySet() : project.getArtifacts();
}
private List<File> projectOutput() {
private List<File> projectOutput(MavenProject project) {
if (project == null) {
return Collections.emptyList();
} else {
@@ -110,16 +116,15 @@ public class MavenProjectClasspath extends JandexClasspath {
}
}
public Path getOutputFolder() {
private Path resolveOutputFolder(MavenProject project) {
return project == null ? null : new File(project.getBuild().getOutputDirectory()).toPath();
}
private Optional<Artifact> getArtifactFromJarFile(File file) throws MavenException {
return project.getArtifacts().stream().filter(a -> file.equals(a.getFile())).findFirst();
public Path getOutputFolder() {
return cachedData != null ? cachedData.outputFolder : null;
}
@Override
public ImmutableList<String> getClasspathResources() {
private ImmutableList<String> resolveClasspathResources(MavenProject project) {
if (project == null) {
return ImmutableList.of();
}
@@ -137,6 +142,11 @@ public class MavenProjectClasspath extends JandexClasspath {
return Arrays.stream(scanner.getIncludedFiles());
}).toArray(String[]::new));
}
@Override
public ImmutableList<String> getClasspathResources() {
return cachedData != null ? ImmutableList.copyOf(cachedData.classpathResources) : ImmutableList.of();
}
/*
* Roaster lib is experiment to generate javadoc from source. Commented out for now since roaster lib is taken out
@@ -174,20 +184,21 @@ public class MavenProjectClasspath extends JandexClasspath {
// }
// }
@Override
protected IJavadocProvider createParserJavadocProvider(File classpathResource) {
if (project == null) {
if (cachedData == null) {
return null;
}
if (classpathResource.isDirectory()) {
if (classpathResource.toString().startsWith(project.getBuild().getOutputDirectory())) {
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
return new ParserJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
.sourceUrl(new File(project.getBuild().getSourceDirectory()).toURI().toURL(), type);
.sourceUrl(new File(cachedData.sourceDirectory).toURI().toURL(), type);
});
} else if (classpathResource.toString().startsWith(project.getBuild().getTestOutputDirectory())) {
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
return new ParserJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER
.sourceUrl(new File(project.getBuild().getTestSourceDirectory()).toURI().toURL(), type);
.sourceUrl(new File(cachedData.testSourceDirectory).toURI().toURL(), type);
});
} else {
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
@@ -196,8 +207,8 @@ public class MavenProjectClasspath extends JandexClasspath {
// Assume it's a JAR file
return new ParserJavadocProvider(type -> {
try {
Artifact artifact = getArtifactFromJarFile(classpathResource).get();
URL sourceContainer = maven.getSources(artifact, project.getRemoteArtifactRepositories()).getFile().toURI().toURL();
Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get();
URL sourceContainer = maven.getSources(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL();
return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(sourceContainer,
type);
} catch (MavenException e) {
@@ -210,20 +221,21 @@ public class MavenProjectClasspath extends JandexClasspath {
}
}
@Override
protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) {
if (project == null) {
if (cachedData == null) {
return null;
}
if (classpathResource.isDirectory()) {
if (classpathResource.toString().startsWith(project.getBuild().getOutputDirectory())) {
if (classpathResource.toString().startsWith(cachedData.outputDirectory)) {
return new HtmlJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
.sourceUrl(new File(project.getModel().getReporting().getOutputDirectory(), "apidocs").toURI().toURL(), type);
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type);
});
} else if (classpathResource.toString().startsWith(project.getBuild().getTestOutputDirectory())) {
} else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) {
return new ParserJavadocProvider(type -> {
return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER
.sourceUrl(new File(project.getModel().getReporting().getOutputDirectory(), "apidocs").toURI().toURL(), type);
.sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type);
});
} else {
throw new IllegalArgumentException("Cannot find source folder for " + classpathResource);
@@ -232,8 +244,8 @@ public class MavenProjectClasspath extends JandexClasspath {
// Assume it's a JAR file
return new HtmlJavadocProvider(type -> {
try {
Artifact artifact = getArtifactFromJarFile(classpathResource).get();
URL sourceContainer = maven.getJavadoc(artifact, project.getRemoteArtifactRepositories()).getFile().toURI().toURL();
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);
} catch (MavenException e) {
@@ -252,7 +264,7 @@ public class MavenProjectClasspath extends JandexClasspath {
MavenProjectClasspath other = (MavenProjectClasspath) obj;
try {
if (pom.equals(other.pom)
&& Objects.equal(project, other.project)) {
&& Objects.equal(cachedData, other.cachedData)) {
return super.equals(obj);
}
} catch (Throwable t) {
@@ -264,7 +276,46 @@ public class MavenProjectClasspath extends JandexClasspath {
@Override
public ImmutableList<String> getSourceFolders() {
return ImmutableList.of(project.getBuild().getSourceDirectory());
return cachedData != null ? ImmutableList.of(cachedData.sourceDirectory) : ImmutableList.of();
}
@Override
public MavenClasspathData createClasspathData() throws Exception {
MavenProject project = createMavenProject();
ImmutableList<Path> 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;
}
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<Path> classpathEntries, Set<String> classpathResources,
Path outputFolder) {
super(name, classpathEntries, classpathResources, outputFolder);
}
}
}

View File

@@ -18,6 +18,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.ide.vscode.commons.java.ClasspathData;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.maven.MavenCore;
@@ -99,4 +100,8 @@ public class FileClasspath implements IClasspath {
return Optional.empty();
}
@Override
public ClasspathData createClasspathData() throws Exception {
return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder());
}
}