Use classpath URLs from class loader instead of system property

The system property doesn't work for a bootiful jar. With this change
there is no need to scan the jar for nested jars either.
This commit is contained in:
Dave Syer
2017-01-03 10:46:41 +00:00
committed by markfisher
parent 948e03b060
commit 7408664aeb

View File

@@ -16,7 +16,10 @@
package org.springframework.cloud.function.compiler.java; package org.springframework.cloud.function.compiler.java;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -32,16 +35,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A file manager that serves source code from in memory and ensures output results are kept in memory * A file manager that serves source code from in memory and ensures output results are
* rather than being flushed out to disk. The JavaFileManager is also used as a lookup mechanism * kept in memory rather than being flushed out to disk. The JavaFileManager is also used
* for resolving types. * as a lookup mechanism for resolving types.
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class MemoryBasedJavaFileManager implements JavaFileManager { public class MemoryBasedJavaFileManager implements JavaFileManager {
private static Logger logger = LoggerFactory.getLogger(MemoryBasedJavaFileManager.class); private static Logger logger = LoggerFactory
.getLogger(MemoryBasedJavaFileManager.class);
private CompilationOutputCollector outputCollector; private CompilationOutputCollector outputCollector;
private List<CloseableFilterableJavaFileObjectIterable> toClose = new ArrayList<>(); private List<CloseableFilterableJavaFileObjectIterable> toClose = new ArrayList<>();
@@ -52,7 +56,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
@Override @Override
public int isSupportedOption(String option) { public int isSupportedOption(String option) {
logger.debug("isSupportedOption({})",option); logger.debug("isSupportedOption({})", option);
return -1; // Not yet supporting options return -1; // Not yet supporting options
} }
@@ -60,41 +64,69 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
public ClassLoader getClassLoader(Location location) { public ClassLoader getClassLoader(Location location) {
// Do not simply return the context classloader as it may get closed and then // Do not simply return the context classloader as it may get closed and then
// be unusable for loading any further classes // be unusable for loading any further classes
logger.debug("getClassLoader({})",location); logger.debug("getClassLoader({})", location);
return null; // Do not currently need to load plugins return null; // Do not currently need to load plugins
} }
@Override @Override
public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) public Iterable<JavaFileObject> list(Location location, String packageName,
throws IOException { Set<Kind> kinds, boolean recurse) throws IOException {
logger.debug("list({},{},{},{})",location,packageName,kinds,recurse); logger.debug("list({},{},{},{})", location, packageName, kinds, recurse);
CloseableFilterableJavaFileObjectIterable resultIterable = null; CloseableFilterableJavaFileObjectIterable resultIterable = null;
if (location == StandardLocation.PLATFORM_CLASS_PATH && (kinds==null || kinds.contains(Kind.CLASS))) { if (location == StandardLocation.PLATFORM_CLASS_PATH
&& (kinds == null || kinds.contains(Kind.CLASS))) {
String sunBootClassPath = System.getProperty("sun.boot.class.path"); String sunBootClassPath = System.getProperty("sun.boot.class.path");
logger.debug("Creating iterable for boot class path: {}",sunBootClassPath); logger.debug("Creating iterable for boot class path: {}", sunBootClassPath);
resultIterable = new IterableClasspath(sunBootClassPath, packageName, recurse); resultIterable = new IterableClasspath(sunBootClassPath, packageName,
recurse);
toClose.add(resultIterable); toClose.add(resultIterable);
} else if (location == StandardLocation.CLASS_PATH && (kinds==null || kinds.contains(Kind.CLASS))) { }
String javaClassPath = System.getProperty("java.class.path"); else if (location == StandardLocation.CLASS_PATH
logger.debug("Creating iterable for class path: {}",javaClassPath); && (kinds == null || kinds.contains(Kind.CLASS))) {
String javaClassPath = getClassPath();
logger.debug("Creating iterable for class path: {}", javaClassPath);
resultIterable = new IterableClasspath(javaClassPath, packageName, recurse); resultIterable = new IterableClasspath(javaClassPath, packageName, recurse);
toClose.add(resultIterable); toClose.add(resultIterable);
} else if (location == StandardLocation.SOURCE_PATH) { }
else if (location == StandardLocation.SOURCE_PATH) {
// There are no 'extra sources' // There are no 'extra sources'
resultIterable = EmptyIterable.instance; resultIterable = EmptyIterable.instance;
} else { }
else {
// Nothing to list // Nothing to list
resultIterable = EmptyIterable.instance; resultIterable = EmptyIterable.instance;
} }
return resultIterable; return resultIterable;
} }
private String getClassPath() {
ClassLoader loader = InMemoryJavaFileObject.class.getClassLoader();
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
if (urls.length > 1) { // heuristic that catches Maven surefire tests
StringBuilder builder = new StringBuilder();
for (URL url : urls) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
String path = url.toString();
if (path.startsWith("file:")) {
path = path.substring("file:".length());
}
builder.append(url);
}
return builder.toString();
}
}
return System.getProperty("java.class.path");
}
@Override @Override
public boolean hasLocation(Location location) { public boolean hasLocation(Location location) {
logger.debug("hasLocation({})",location); logger.debug("hasLocation({})", location);
return (location == StandardLocation.SOURCE_PATH || return (location == StandardLocation.SOURCE_PATH
location == StandardLocation.CLASS_PATH || || location == StandardLocation.CLASS_PATH
location == StandardLocation.PLATFORM_CLASS_PATH); || location == StandardLocation.PLATFORM_CLASS_PATH);
} }
@Override @Override
@@ -110,44 +142,50 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
@Override @Override
public boolean isSameFile(FileObject a, FileObject b) { public boolean isSameFile(FileObject a, FileObject b) {
logger.debug("isSameFile({},{})",a,b); logger.debug("isSameFile({},{})", a, b);
return a.equals(b); return a.equals(b);
} }
@Override @Override
public boolean handleOption(String current, Iterator<String> remaining) { public boolean handleOption(String current, Iterator<String> remaining) {
logger.debug("handleOption({},{})",current,remaining); logger.debug("handleOption({},{})", current, remaining);
return false; // This file manager does not manage any options return false; // This file manager does not manage any options
} }
@Override @Override
public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { public JavaFileObject getJavaFileForInput(Location location, String className,
logger.debug("getJavaFileForInput({},{},{})",location,className,kind); Kind kind) throws IOException {
logger.debug("getJavaFileForInput({},{},{})", location, className, kind);
throw new IllegalStateException("Not expected to be used in this context"); throw new IllegalStateException("Not expected to be used in this context");
} }
@Override @Override
public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) public JavaFileObject getJavaFileForOutput(Location location, String className,
throws IOException { Kind kind, FileObject sibling) throws IOException {
logger.debug("getJavaFileForOutput({},{},{},{})",location,className,kind,sibling); logger.debug("getJavaFileForOutput({},{},{},{})", location, className, kind,
// Example parameters: CLASS_OUTPUT, Foo, CLASS, StringBasedJavaSourceFileObject[string:///a/b/c/Foo.java] sibling);
// Example parameters: CLASS_OUTPUT, Foo, CLASS,
// StringBasedJavaSourceFileObject[string:///a/b/c/Foo.java]
return outputCollector.getJavaFileForOutput(location, className, kind, sibling); return outputCollector.getJavaFileForOutput(location, className, kind, sibling);
} }
@Override @Override
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { public FileObject getFileForInput(Location location, String packageName,
logger.debug("getFileForInput({},{},{})",location,packageName,relativeName); String relativeName) throws IOException {
logger.debug("getFileForInput({},{},{})", location, packageName, relativeName);
throw new IllegalStateException("Not expected to be used in this context"); throw new IllegalStateException("Not expected to be used in this context");
} }
@Override @Override
public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) public FileObject getFileForOutput(Location location, String packageName,
throws IOException { String relativeName, FileObject sibling) throws IOException {
logger.debug("getFileForOutput({},{},{},{})",location,packageName,relativeName,sibling); logger.debug("getFileForOutput({},{},{},{})", location, packageName, relativeName,
sibling);
// This can be called when the annotation config processor runs // This can be called when the annotation config processor runs
// Example parameters: CLASS_OUTPUT, , META-INF/spring-configuration-metadata.json, null // Example parameters: CLASS_OUTPUT, ,
return outputCollector.getFileForOutput(location, packageName, relativeName, sibling); // META-INF/spring-configuration-metadata.json, null
return outputCollector.getFileForOutput(location, packageName, relativeName,
sibling);
} }
@Override @Override
@@ -156,7 +194,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
for (CloseableFilterableJavaFileObjectIterable closeable: toClose) { for (CloseableFilterableJavaFileObjectIterable closeable : toClose) {
closeable.close(); closeable.close();
} }
} }