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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 close();
|
||||||
|
|
||||||
|
abstract void reset();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
|||||||
class ClasspathEntriesIterator implements Iterator<JavaFileObject> {
|
class ClasspathEntriesIterator implements Iterator<JavaFileObject> {
|
||||||
private int currentClasspathEntriesIndex = 0;
|
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 File openDirectory = null;
|
||||||
private DirEnumeration openDirectoryEnumeration = null;
|
private DirEnumeration openDirectoryEnumeration = null;
|
||||||
|
|
||||||
@@ -106,18 +106,24 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
|||||||
private ZipEntry nestedZip = null;
|
private ZipEntry nestedZip = null;
|
||||||
private Stack<Enumeration<? extends ZipEntry>> openArchiveEnumeration = null;
|
private Stack<Enumeration<? extends ZipEntry>> openArchiveEnumeration = null;
|
||||||
|
|
||||||
|
private File openJrt;
|
||||||
|
private JrtFsEnumeration openJrtEnumeration = null;
|
||||||
|
|
||||||
private JavaFileObject nextEntry = null;
|
private JavaFileObject nextEntry = null;
|
||||||
|
|
||||||
private void findNext() {
|
private void findNext() {
|
||||||
if (nextEntry == null) {
|
if (nextEntry == null) {
|
||||||
try {
|
try {
|
||||||
while (openArchive!=null || openDirectory!=null || currentClasspathEntriesIndex < classpathEntries.size()) {
|
while (openArchive!=null || openDirectory!=null || openJrt != null || currentClasspathEntriesIndex < classpathEntries.size()) {
|
||||||
if (openArchive == null && openDirectory == null) {
|
if (openArchive == null && openDirectory == null && openJrt == null) {
|
||||||
// Open the next item
|
// Open the next item
|
||||||
File nextFile = classpathEntries.get(currentClasspathEntriesIndex);
|
File nextFile = classpathEntries.get(currentClasspathEntriesIndex);
|
||||||
if (nextFile.isDirectory()) {
|
if (nextFile.isDirectory()) {
|
||||||
openDirectory = nextFile;
|
openDirectory = nextFile;
|
||||||
openDirectoryEnumeration = new DirEnumeration(nextFile);
|
openDirectoryEnumeration = new DirEnumeration(nextFile);
|
||||||
|
} else if (nextFile.getName().endsWith("jrt-fs.jar")) {
|
||||||
|
openJrt = nextFile;
|
||||||
|
openJrtEnumeration = new JrtFsEnumeration(nextFile,null);
|
||||||
} else {
|
} else {
|
||||||
openFile = nextFile;
|
openFile = nextFile;
|
||||||
openArchive = new ZipFile(nextFile);
|
openArchive = new ZipFile(nextFile);
|
||||||
@@ -166,6 +172,17 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable
|
|||||||
}
|
}
|
||||||
openDirectoryEnumeration = null;
|
openDirectoryEnumeration = null;
|
||||||
openDirectory = 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) {
|
} 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.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@@ -76,7 +84,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
|
|
||||||
private CompilationInfoCache compilationInfoCache;
|
private CompilationInfoCache compilationInfoCache;
|
||||||
|
|
||||||
private Map<Key, IterableClasspath> iterables = new HashMap<>();
|
private Map<Key, CloseableFilterableJavaFileObjectIterable> iterables = new HashMap<>();
|
||||||
|
|
||||||
public MemoryBasedJavaFileManager() {
|
public MemoryBasedJavaFileManager() {
|
||||||
outputCollector = new CompilationOutputCollector();
|
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
|
* 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
|
* 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
|
* @return an ArchiveInfo encapsulating package info from the archive
|
||||||
*/
|
*/
|
||||||
private ArchiveInfo buildArchiveInfo(File file) {
|
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<>();
|
List<String> packageNames = new ArrayList<>();
|
||||||
boolean isBootJar = false;
|
boolean isBootJar = false;
|
||||||
try (ZipFile openArchive = new ZipFile(file)) {
|
try (ZipFile openArchive = new ZipFile(file)) {
|
||||||
@@ -234,12 +286,14 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Key {
|
static class Key {
|
||||||
|
private Location location;
|
||||||
private String classpath;
|
private String classpath;
|
||||||
private String packageName;
|
private String packageName;
|
||||||
private Set<Kind> kinds;
|
private Set<Kind> kinds;
|
||||||
private boolean recurse;
|
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.classpath = classpath;
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.kinds = kinds;
|
this.kinds = kinds;
|
||||||
@@ -248,7 +302,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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
|
@Override
|
||||||
@@ -257,7 +311,8 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Key that = (Key)obj;
|
Key that = (Key)obj;
|
||||||
return classpath.equals(that.classpath) &&
|
return location.equals(that.location) &&
|
||||||
|
classpath.equals(that.classpath) &&
|
||||||
kinds.equals(that.kinds) &&
|
kinds.equals(that.kinds) &&
|
||||||
(recurse==that.recurse) &&
|
(recurse==that.recurse) &&
|
||||||
(packageName==null?(that.packageName==null):this.packageName.equals(that.packageName));
|
(packageName==null?(that.packageName==null):this.packageName.equals(that.packageName));
|
||||||
@@ -268,6 +323,9 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
if (platformClasspath == null) {
|
if (platformClasspath == null) {
|
||||||
platformClasspath = System.getProperty("sun.boot.class.path");
|
platformClasspath = System.getProperty("sun.boot.class.path");
|
||||||
}
|
}
|
||||||
|
if (platformClasspath == null) {
|
||||||
|
platformClasspath = "";
|
||||||
|
}
|
||||||
return platformClasspath;
|
return platformClasspath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,9 +334,20 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
Set<Kind> kinds, boolean recurse) throws IOException {
|
Set<Kind> kinds, boolean recurse) throws IOException {
|
||||||
logger.debug("list({},{},{},{})", location, packageName, kinds, recurse);
|
logger.debug("list({},{},{},{})", location, packageName, kinds, recurse);
|
||||||
String classpath = "";
|
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))) {
|
&& (kinds == null || kinds.contains(Kind.CLASS))) {
|
||||||
classpath = getPlatformClassPath();
|
classpath = getPlatformClassPath();
|
||||||
|
// if (classpath.length() == 0) {
|
||||||
|
// if (hasJrtFsPath()) {
|
||||||
|
// classpath = getJrtFsPath();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
logger.debug("Creating iterable for boot class path: {}", classpath);
|
logger.debug("Creating iterable for boot class path: {}", classpath);
|
||||||
}
|
}
|
||||||
else if (location == StandardLocation.CLASS_PATH
|
else if (location == StandardLocation.CLASS_PATH
|
||||||
@@ -294,10 +363,14 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
classpath = javaClassPath;
|
classpath = javaClassPath;
|
||||||
logger.debug("Creating iterable for class path: {}", classpath);
|
logger.debug("Creating iterable for class path: {}", classpath);
|
||||||
}
|
}
|
||||||
Key k = new Key(classpath, packageName, kinds, recurse);
|
Key k = new Key(location, classpath, packageName, kinds, recurse);
|
||||||
IterableClasspath resultIterable = iterables.get(k);
|
CloseableFilterableJavaFileObjectIterable resultIterable = iterables.get(k);
|
||||||
if (resultIterable == null) {
|
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);
|
iterables.put(k, resultIterable);
|
||||||
}
|
}
|
||||||
resultIterable.reset();
|
resultIterable.reset();
|
||||||
@@ -330,6 +403,9 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
if (cp == null) {
|
if (cp == null) {
|
||||||
cp = System.getProperty("java.class.path");
|
cp = System.getProperty("java.class.path");
|
||||||
}
|
}
|
||||||
|
if (hasJrtFsPath()) {
|
||||||
|
cp = cp + File.pathSeparator + getJrtFsPath();
|
||||||
|
}
|
||||||
classpath = pathWithPlatformClassPathRemoved(cp);
|
classpath = pathWithPlatformClassPathRemoved(cp);
|
||||||
}
|
}
|
||||||
return classpath;
|
return classpath;
|
||||||
@@ -394,6 +470,10 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
public JavaFileObject getJavaFileForInput(Location location, String className,
|
public JavaFileObject getJavaFileForInput(Location location, String className,
|
||||||
Kind kind) throws IOException {
|
Kind kind) throws IOException {
|
||||||
logger.debug("getJavaFileForInput({},{},{})", location, className, kind);
|
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");
|
throw new IllegalStateException("Not expected to be used in this context");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,8 +512,8 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
Collection<IterableClasspath> toClose = iterables.values();
|
Collection<CloseableFilterableJavaFileObjectIterable> toClose = iterables.values();
|
||||||
for (IterableClasspath icp: toClose) {
|
for (CloseableFilterableJavaFileObjectIterable icp: toClose) {
|
||||||
icp.close();
|
icp.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,4 +562,138 @@ public class MemoryBasedJavaFileManager implements JavaFileManager {
|
|||||||
return resolvedAdditionalDependencies;
|
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);
|
JavaFileObject sourceFile = InMemoryJavaFileObject.getSourceJavaFileObject(className, classSourceCode);
|
||||||
|
|
||||||
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceFile);
|
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();
|
boolean success = task.call();
|
||||||
CompilationResult compilationResult = new CompilationResult(success);
|
CompilationResult compilationResult = new CompilationResult(success);
|
||||||
|
|||||||
Reference in New Issue
Block a user