Enable compiler to cope with Java 9 and later runtime packaging
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -102,4 +102,7 @@ public abstract class CloseableFilterableJavaFileObjectIterable implements Itera
|
||||
}
|
||||
|
||||
abstract void close();
|
||||
|
||||
abstract void reset();
|
||||
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
||||
class ClasspathEntriesIterator implements Iterator<JavaFileObject> {
|
||||
private int currentClasspathEntriesIndex = 0;
|
||||
|
||||
// Either a directory or an archive will be open at any one time
|
||||
// Walking one of three possible things: directory tree, zip, or Java runtime packaged in JDK9+ form
|
||||
private File openDirectory = null;
|
||||
private DirEnumeration openDirectoryEnumeration = null;
|
||||
|
||||
@@ -105,19 +105,25 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
||||
private File openFile = null;
|
||||
private ZipEntry nestedZip = null;
|
||||
private Stack<Enumeration<? extends ZipEntry>> openArchiveEnumeration = null;
|
||||
|
||||
private File openJrt;
|
||||
private JrtFsEnumeration openJrtEnumeration = null;
|
||||
|
||||
private JavaFileObject nextEntry = null;
|
||||
|
||||
private void findNext() {
|
||||
if (nextEntry == null) {
|
||||
try {
|
||||
while (openArchive!=null || openDirectory!=null || currentClasspathEntriesIndex < classpathEntries.size()) {
|
||||
if (openArchive == null && openDirectory == null) {
|
||||
while (openArchive!=null || openDirectory!=null || openJrt != null || currentClasspathEntriesIndex < classpathEntries.size()) {
|
||||
if (openArchive == null && openDirectory == null && openJrt == null) {
|
||||
// Open the next item
|
||||
File nextFile = classpathEntries.get(currentClasspathEntriesIndex);
|
||||
if (nextFile.isDirectory()) {
|
||||
openDirectory = nextFile;
|
||||
openDirectoryEnumeration = new DirEnumeration(nextFile);
|
||||
} else if (nextFile.getName().endsWith("jrt-fs.jar")) {
|
||||
openJrt = nextFile;
|
||||
openJrtEnumeration = new JrtFsEnumeration(nextFile,null);
|
||||
} else {
|
||||
openFile = nextFile;
|
||||
openArchive = new ZipFile(nextFile);
|
||||
@@ -166,6 +172,17 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
||||
}
|
||||
openDirectoryEnumeration = null;
|
||||
openDirectory = null;
|
||||
} else if (openJrtEnumeration != null) {
|
||||
while (openJrtEnumeration.hasMoreElements()) {
|
||||
JrtEntryJavaFileObject jrtEntry = openJrtEnumeration.nextElement();
|
||||
String name = openJrtEnumeration.getName(jrtEntry);
|
||||
if (accept(name)) {
|
||||
nextEntry = jrtEntry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
openJrtEnumeration = null;
|
||||
openJrt = null;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.java;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager.CompilationInfoCache;
|
||||
|
||||
/**
|
||||
* Iterable that will produce an iterator that returns classes found
|
||||
* in a specific module tree within the Java runtime image that exists in
|
||||
* Java 9 and later.
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class IterableJrtModule extends CloseableFilterableJavaFileObjectIterable {
|
||||
|
||||
// private static Logger logger = LoggerFactory.getLogger(IterableJrtModule.class);
|
||||
|
||||
private Path moduleRootPath;
|
||||
|
||||
Map<String, JrtFsEnumeration> walkers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @param compilationInfoCache cache of info that may help accelerate compilation
|
||||
* @param moduleRootPath path to the base of the relevant module within the JRT image
|
||||
* @param packageNameFilter an optional package name if choosing to filter (e.g. com.example)
|
||||
* @param includeSubpackages if true, include results in subpackages of the specified package filter
|
||||
*/
|
||||
public IterableJrtModule(CompilationInfoCache compilationInfoCache, Path moduleRootPath, String packageNameFilter,
|
||||
boolean includeSubpackages) {
|
||||
super(compilationInfoCache, packageNameFilter, includeSubpackages);
|
||||
this.moduleRootPath = moduleRootPath;
|
||||
}
|
||||
|
||||
public Iterator<JavaFileObject> iterator() {
|
||||
JrtFsEnumeration jrtFsWalker = walkers.get(moduleRootPath.toString());
|
||||
if (jrtFsWalker == null) {
|
||||
jrtFsWalker = new JrtFsEnumeration(null, moduleRootPath);
|
||||
walkers.put(moduleRootPath.toString(), jrtFsWalker);
|
||||
}
|
||||
jrtFsWalker.reset();
|
||||
return new IteratorOverJrtFsEnumeration(jrtFsWalker);
|
||||
}
|
||||
|
||||
class IteratorOverJrtFsEnumeration implements Iterator<JavaFileObject> {
|
||||
|
||||
private JavaFileObject nextEntry = null;
|
||||
|
||||
private JrtFsEnumeration jrtEnumeration;
|
||||
|
||||
public IteratorOverJrtFsEnumeration(JrtFsEnumeration jrtFsWalker) {
|
||||
this.jrtEnumeration = jrtFsWalker;
|
||||
}
|
||||
|
||||
private void findNext() {
|
||||
if (nextEntry == null) {
|
||||
while (jrtEnumeration.hasMoreElements()) {
|
||||
JrtEntryJavaFileObject jrtEntry = jrtEnumeration.nextElement();
|
||||
String name = jrtEnumeration.getName(jrtEntry);
|
||||
if (accept(name)) {
|
||||
nextEntry = jrtEntry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
findNext();
|
||||
return nextEntry != null;
|
||||
}
|
||||
|
||||
public JavaFileObject next() {
|
||||
findNext();
|
||||
if (nextEntry == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
JavaFileObject retval = nextEntry;
|
||||
nextEntry = null;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.java;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
/**
|
||||
* A JavaFileObject that represents a class from the Java runtime as packaged in Java 9 and later.
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class JrtEntryJavaFileObject implements JavaFileObject {
|
||||
|
||||
private String pathToClassString;
|
||||
private Path path;
|
||||
|
||||
/**
|
||||
* @param path entry in the Java runtime filesystem, for example '/modules/java.base/java/lang/Object.class'
|
||||
*/
|
||||
public JrtEntryJavaFileObject(Path path) {
|
||||
this.pathToClassString = path.subpath(2, path.getNameCount()).toString(); // e.g. java/lang/Object.class
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI toUri() {
|
||||
return path.toUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the path of the file relative to the base directory, for example: a/b/c/D.class
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return pathToClassString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInputStream() throws IOException {
|
||||
byte[] bytes = Files.readAllBytes(path);
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream() throws IOException {
|
||||
throw new IllegalStateException("Only expected to be used for input");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
|
||||
// It is bytecode
|
||||
throw new UnsupportedOperationException("openReader() not supported on class file: " + getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
||||
// It is bytecode
|
||||
throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer openWriter() throws IOException {
|
||||
throw new IllegalStateException("only expected to be used for input");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified() {
|
||||
try {
|
||||
return Files.getLastModifiedTime(path).toMillis();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unable to determine last modified time of "+pathToClassString, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
return false; // This object is for read only access to a class
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kind getKind() {
|
||||
return Kind.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNameCompatible(String simpleName, Kind kind) {
|
||||
if (kind != Kind.CLASS) {
|
||||
return false;
|
||||
}
|
||||
String name = getName();
|
||||
int lastSlash = name.lastIndexOf('/');
|
||||
return name.substring(lastSlash + 1).equals(simpleName + ".class");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NestingKind getNestingKind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Modifier getAccessLevel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof JrtEntryJavaFileObject)) {
|
||||
return false;
|
||||
}
|
||||
JrtEntryJavaFileObject that = (JrtEntryJavaFileObject)obj;
|
||||
return (getName().equals(that.getName()));
|
||||
}
|
||||
|
||||
public String getPathToClassString() {
|
||||
return pathToClassString;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.function.compiler.java;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Walks a JrtFS treating it like a directory (to avoid overcomplicating the walking
|
||||
* logic in IterableClasspath)
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class JrtFsEnumeration implements Enumeration<JrtEntryJavaFileObject> {
|
||||
|
||||
// private final static Logger logger = LoggerFactory.getLogger(JrtFsEnumeration.class);
|
||||
|
||||
private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
|
||||
|
||||
private final static FileSystem fs = FileSystems.getFileSystem(JRT_URI);
|
||||
|
||||
private Path pathWithinJrt;
|
||||
|
||||
private List<JrtEntryJavaFileObject> jfos = new ArrayList<>();
|
||||
|
||||
private Integer counter = 0;
|
||||
|
||||
private Boolean initialized = false;
|
||||
|
||||
public JrtFsEnumeration(File jrtFsFile, Path pathWithinJrt) {
|
||||
this.pathWithinJrt = pathWithinJrt;
|
||||
ensureInitialized();
|
||||
}
|
||||
|
||||
class FileCacheBuilderVisitor extends SimpleFileVisitor<Path> {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
int fnc = file.getNameCount();
|
||||
if (fnc >= 3 && file.toString().endsWith(".class")) { // There is a preceeding module name - e.g. /modules/java.base/java/lang/Object.class
|
||||
// file.subpath(2, fnc); // e.g. java/lang/Object.class
|
||||
jfos.add(new JrtEntryJavaFileObject(file));
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureInitialized() {
|
||||
synchronized (initialized) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
FileCacheBuilderVisitor visitor = new FileCacheBuilderVisitor();
|
||||
if (pathWithinJrt != null) {
|
||||
try {
|
||||
Files.walkFileTree(pathWithinJrt, visitor);
|
||||
// System.out.println("JrtFs enumeration for '"+pathWithinJrt+"' with #"+jfos.size()+" entries");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
Iterable<java.nio.file.Path> roots = fs.getRootDirectories();
|
||||
try {
|
||||
for (java.nio.file.Path path : roots) {
|
||||
Files.walkFileTree(path, visitor);
|
||||
}
|
||||
// System.out.println("JrtFs enumeration initialized with #"+jfos.size()+" entries");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return counter < jfos.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JrtEntryJavaFileObject nextElement() {
|
||||
if (counter>=jfos.size()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
JrtEntryJavaFileObject toReturn = jfos.get(counter++);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path of this file to the base directory that the directory enumeration was
|
||||
* started for.
|
||||
* @param file a file discovered returned by this enumeration
|
||||
* @return the relative path of the file (for example: a/b/c/D.class)
|
||||
*/
|
||||
public String getName(JrtEntryJavaFileObject file) {
|
||||
return file.getPathToClassString();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,11 +21,19 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -76,7 +84,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
|
||||
private CompilationInfoCache compilationInfoCache;
|
||||
|
||||
private Map<Key, IterableClasspath> iterables = new HashMap<>();
|
||||
private Map<Key, CloseableFilterableJavaFileObjectIterable> iterables = new HashMap<>();
|
||||
|
||||
public MemoryBasedJavaFileManager() {
|
||||
outputCollector = new CompilationOutputCollector();
|
||||
@@ -159,6 +167,46 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean packageCacheInitialized = false;
|
||||
private Map<String, Path> packageCache = new HashMap<String, Path>();
|
||||
private ArchiveInfo moduleArchiveInfo;
|
||||
|
||||
private class PackageCacheBuilderVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.getNameCount() > 3 && file.toString().endsWith(".class")) {
|
||||
int fnc = file.getNameCount();
|
||||
if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class
|
||||
Path packagePath = file.subpath(2, fnc-1); // e.g. java/lang
|
||||
String packagePathString = packagePath.toString()+"/";
|
||||
packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized ArchiveInfo buildPackageMap() {
|
||||
if (!packageCacheInitialized) {
|
||||
packageCacheInitialized = true;
|
||||
Iterable<java.nio.file.Path> roots = getJrtFs().getRootDirectories();
|
||||
PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor();
|
||||
try {
|
||||
for (java.nio.file.Path path : roots) {
|
||||
Files.walkFileTree(path, visitor);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
List<String> ls = new ArrayList<>();
|
||||
ls.addAll(packageCache.keySet());
|
||||
Collections.sort(ls);
|
||||
moduleArchiveInfo = new ArchiveInfo(ls, false);
|
||||
}
|
||||
return moduleArchiveInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the specified archive and collect up the package names of any .class files encountered. If
|
||||
* the archive contains nested jars packaged in a BOOT style way (under a BOOT-INF/lib folder) then
|
||||
@@ -168,6 +216,10 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
* @return an ArchiveInfo encapsulating package info from the archive
|
||||
*/
|
||||
private ArchiveInfo buildArchiveInfo(File file) {
|
||||
if (file.toString().endsWith("jrt-fs.jar")) {
|
||||
// Special treatment for >=JDK9 - treat this as intention to use modules
|
||||
return buildPackageMap();
|
||||
}
|
||||
List<String> packageNames = new ArrayList<>();
|
||||
boolean isBootJar = false;
|
||||
try (ZipFile openArchive = new ZipFile(file)) {
|
||||
@@ -234,12 +286,14 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
}
|
||||
|
||||
static class Key {
|
||||
private Location location;
|
||||
private String classpath;
|
||||
private String packageName;
|
||||
private Set<Kind> kinds;
|
||||
private boolean recurse;
|
||||
|
||||
public Key(String classpath, String packageName, Set<Kind> kinds, boolean recurse) {
|
||||
public Key(Location location, String classpath, String packageName, Set<Kind> kinds, boolean recurse) {
|
||||
this.location = location;
|
||||
this.classpath = classpath;
|
||||
this.packageName = packageName;
|
||||
this.kinds = kinds;
|
||||
@@ -248,7 +302,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ((classpath.hashCode()*37+(packageName==null?0:packageName.hashCode()))*37+kinds.hashCode())*37+(recurse?1:0);
|
||||
return (((location.hashCode()*37)+classpath.hashCode()*37+(packageName==null?0:packageName.hashCode()))*37+kinds.hashCode())*37+(recurse?1:0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,7 +311,8 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
return false;
|
||||
}
|
||||
Key that = (Key)obj;
|
||||
return classpath.equals(that.classpath) &&
|
||||
return location.equals(that.location) &&
|
||||
classpath.equals(that.classpath) &&
|
||||
kinds.equals(that.kinds) &&
|
||||
(recurse==that.recurse) &&
|
||||
(packageName==null?(that.packageName==null):this.packageName.equals(that.packageName));
|
||||
@@ -268,6 +323,9 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
if (platformClasspath == null) {
|
||||
platformClasspath = System.getProperty("sun.boot.class.path");
|
||||
}
|
||||
if (platformClasspath == null) {
|
||||
platformClasspath = "";
|
||||
}
|
||||
return platformClasspath;
|
||||
}
|
||||
|
||||
@@ -276,9 +334,20 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
Set<Kind> kinds, boolean recurse) throws IOException {
|
||||
logger.debug("list({},{},{},{})", location, packageName, kinds, recurse);
|
||||
String classpath = "";
|
||||
if (location == StandardLocation.PLATFORM_CLASS_PATH
|
||||
Path moduleRootPath = null;
|
||||
if (location instanceof JDKModuleLocation && (kinds == null || kinds.contains(Kind.CLASS))) {
|
||||
// list(org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager$JDKModuleLocation@550a1967,
|
||||
// java.lang,[SOURCE, CLASS, HTML, OTHER],false)
|
||||
moduleRootPath = ((JDKModuleLocation)location).getModuleRootPath();
|
||||
logger.debug("For JDKModuleLocation "+location.toString()+" root path is "+moduleRootPath);
|
||||
} else if (location == StandardLocation.PLATFORM_CLASS_PATH
|
||||
&& (kinds == null || kinds.contains(Kind.CLASS))) {
|
||||
classpath = getPlatformClassPath();
|
||||
// if (classpath.length() == 0) {
|
||||
// if (hasJrtFsPath()) {
|
||||
// classpath = getJrtFsPath();
|
||||
// }
|
||||
// }
|
||||
logger.debug("Creating iterable for boot class path: {}", classpath);
|
||||
}
|
||||
else if (location == StandardLocation.CLASS_PATH
|
||||
@@ -294,10 +363,14 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
classpath = javaClassPath;
|
||||
logger.debug("Creating iterable for class path: {}", classpath);
|
||||
}
|
||||
Key k = new Key(classpath, packageName, kinds, recurse);
|
||||
IterableClasspath resultIterable = iterables.get(k);
|
||||
Key k = new Key(location, classpath, packageName, kinds, recurse);
|
||||
CloseableFilterableJavaFileObjectIterable resultIterable = iterables.get(k);
|
||||
if (resultIterable == null) {
|
||||
resultIterable = new IterableClasspath(compilationInfoCache, classpath, packageName, recurse);
|
||||
if (moduleRootPath != null) {
|
||||
resultIterable = new IterableJrtModule(compilationInfoCache, moduleRootPath, packageName, recurse);
|
||||
} else {
|
||||
resultIterable = new IterableClasspath(compilationInfoCache, classpath, packageName, recurse);
|
||||
}
|
||||
iterables.put(k, resultIterable);
|
||||
}
|
||||
resultIterable.reset();
|
||||
@@ -330,6 +403,9 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
if (cp == null) {
|
||||
cp = System.getProperty("java.class.path");
|
||||
}
|
||||
if (hasJrtFsPath()) {
|
||||
cp = cp + File.pathSeparator + getJrtFsPath();
|
||||
}
|
||||
classpath = pathWithPlatformClassPathRemoved(cp);
|
||||
}
|
||||
return classpath;
|
||||
@@ -394,6 +470,10 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
public JavaFileObject getJavaFileForInput(Location location, String className,
|
||||
Kind kind) throws IOException {
|
||||
logger.debug("getJavaFileForInput({},{},{})", location, className, kind);
|
||||
// getJavaFileForInput(SOURCE_PATH,module-info,SOURCE)
|
||||
if (className.equals("module-info")) {
|
||||
return null;
|
||||
}
|
||||
throw new IllegalStateException("Not expected to be used in this context");
|
||||
}
|
||||
|
||||
@@ -432,8 +512,8 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Collection<IterableClasspath> toClose = iterables.values();
|
||||
for (IterableClasspath icp: toClose) {
|
||||
Collection<CloseableFilterableJavaFileObjectIterable> toClose = iterables.values();
|
||||
for (CloseableFilterableJavaFileObjectIterable icp: toClose) {
|
||||
icp.close();
|
||||
}
|
||||
}
|
||||
@@ -482,4 +562,138 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
||||
return resolvedAdditionalDependencies;
|
||||
}
|
||||
|
||||
private static URI JRT_URI = URI.create("jrt:/");
|
||||
|
||||
private static FileSystem fs;
|
||||
|
||||
static class JDKModuleLocation implements Location {
|
||||
private String moduleName;
|
||||
private Path moduleRootPath;
|
||||
|
||||
public JDKModuleLocation(String moduleName, Path moduleRootPath) {
|
||||
this.moduleName = moduleName;
|
||||
this.moduleRootPath = moduleRootPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MODULE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutputLocation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getModuleName() {
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
public Path getModuleRootPath() {
|
||||
return moduleRootPath;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "JDKModuleLocation(" + moduleName + ")";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return moduleName.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof JDKModuleLocation)) {
|
||||
return false;
|
||||
}
|
||||
return this.hashCode() == ((JDKModuleLocation)other).hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String inferModuleName(Location location) throws IOException {
|
||||
if (location instanceof JDKModuleLocation) {
|
||||
JDKModuleLocation m = (JDKModuleLocation)location;
|
||||
return m.getModuleName();
|
||||
}
|
||||
throw new IllegalStateException("Asked to inferModuleName from a "+location.getClass().getName());
|
||||
}
|
||||
|
||||
static class ModuleIdentifierVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
private Map<String, Path> modules = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.getNameCount() > 2 && file.toString().endsWith(".class")) {
|
||||
// /modules/jdk.rmic/sun/tools/tree/CaseStatement.class
|
||||
String moduleName = file.getName(1).toString(); // jdk.rmic
|
||||
Path moduleRootPath = file.subpath(0, 2); // /modules/jdk.rmic
|
||||
if (!modules.containsKey(moduleName)) {
|
||||
modules.put(moduleName, moduleRootPath);
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
public Set<Location> getModuleLocations() {
|
||||
if (modules.size()==0) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
Set<Location> locations = new HashSet<>();
|
||||
for (Map.Entry<String,Path> moduleEntry: modules.entrySet()) {
|
||||
locations.add(new JDKModuleLocation(moduleEntry.getKey(),moduleEntry.getValue()));
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String jrtFsFilePath = null;
|
||||
|
||||
private boolean checkedForJrtFsPath = false;
|
||||
|
||||
private boolean hasJrtFsPath() {
|
||||
return getJrtFsPath() != null;
|
||||
}
|
||||
|
||||
private String getJrtFsPath() {
|
||||
if (!checkedForJrtFsPath) {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
String jrtFsFilePath = javaHome + File.separator + "lib" + File.separator + "jrt-fs.jar";
|
||||
File jrtFsFile = new File(jrtFsFilePath);
|
||||
if (jrtFsFile.exists()) {
|
||||
this.jrtFsFilePath = jrtFsFilePath;
|
||||
}
|
||||
checkedForJrtFsPath = true;
|
||||
}
|
||||
return jrtFsFilePath;
|
||||
}
|
||||
|
||||
public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException {
|
||||
if (getJrtFsPath()!=null && location == StandardLocation.valueOf("SYSTEM_MODULES")) {
|
||||
Set<Set<Location>> ss = new HashSet<>();
|
||||
HashSet<Location> moduleLocations = new HashSet<>();
|
||||
ModuleIdentifierVisitor visitor = new ModuleIdentifierVisitor();
|
||||
Iterable<Path> roots = getJrtFs().getRootDirectories();
|
||||
try {
|
||||
for (Path path: roots) {
|
||||
Files.walkFileTree(path, visitor);
|
||||
}
|
||||
moduleLocations.addAll(visitor.getModuleLocations());
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
ss.add(moduleLocations);
|
||||
return ss;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
private static FileSystem getJrtFs() {
|
||||
if (fs == null) {
|
||||
fs = FileSystems.getFileSystem(JRT_URI);
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,10 @@ public class RuntimeJavaCompiler {
|
||||
JavaFileObject sourceFile = InMemoryJavaFileObject.getSourceJavaFileObject(className, classSourceCode);
|
||||
|
||||
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceFile);
|
||||
CompilationTask task = compiler.getTask(null, fileManager , diagnosticCollector, null, null, compilationUnits);
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add("-source");
|
||||
options.add("1.8");
|
||||
CompilationTask task = compiler.getTask(null, fileManager , diagnosticCollector, options, null, compilationUnits);
|
||||
|
||||
boolean success = task.call();
|
||||
CompilationResult compilationResult = new CompilationResult(success);
|
||||
|
||||
Reference in New Issue
Block a user