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