You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ge...@apache.org on 2018/02/20 08:34:45 UTC
[incubator-netbeans] branch master updated: Adding utilities to
construct boot classpath and module boot classpath on both JDK 8 and JDK 9+
(replaces TestUtil.getBootClassPath). Using it in hint tests and completion
tests. (#430)
This is an automated email from the ASF dual-hosted git repository.
geertjan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 8a773b5 Adding utilities to construct boot classpath and module boot classpath on both JDK 8 and JDK 9+ (replaces TestUtil.getBootClassPath). Using it in hint tests and completion tests. (#430)
8a773b5 is described below
commit 8a773b5aa86847acdb2fe3166bf568daa2676bb9
Author: Jan Lahoda <la...@gmail.com>
AuthorDate: Tue Feb 20 09:34:42 2018 +0100
Adding utilities to construct boot classpath and module boot classpath on both JDK 8 and JDK 9+ (replaces TestUtil.getBootClassPath). Using it in hint tests and completion tests. (#430)
---
.../java/completion/CompletionTestBase.java | 13 +-
java.hints.test/nbproject/project.properties | 2 +-
java.hints.test/nbproject/project.xml | 29 +-
.../modules/java/hints/test/BootClassPathUtil.java | 307 +++++++++++++++++++++
.../modules/java/hints/test/api/HintTest.java | 49 +---
.../modules/java/hints/test/api/HintTestTest.java | 18 ++
java.hints/nbproject/project.xml | 3 +
.../modules/java/source/BootClassPathUtil.java | 307 +++++++++++++++++++++
.../org/netbeans/modules/java/source/TestUtil.java | 60 +---
9 files changed, 682 insertions(+), 106 deletions(-)
diff --git a/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java b/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
index 7e77cfe..217f8a9 100644
--- a/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
+++ b/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
@@ -55,6 +55,7 @@ import org.netbeans.api.lexer.Language;
import org.netbeans.core.startup.Main;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.java.JavaDataLoader;
+import org.netbeans.modules.java.source.BootClassPathUtil;
import org.netbeans.modules.java.source.TestUtil;
import org.netbeans.modules.java.source.indexing.TransactionContext;
import org.netbeans.modules.java.source.usages.BinaryAnalyser;
@@ -118,6 +119,7 @@ public class CompletionTestBase extends NbTestCase {
protected void setUp() throws Exception {
ClassPathProvider cpp = new ClassPathProvider() {
volatile ClassPath bootCache;
+ volatile ClassPath moduleBootCache;
@Override
public ClassPath findClassPath(FileObject file, String type) {
try {
@@ -127,10 +129,17 @@ public class CompletionTestBase extends NbTestCase {
if (type.equals(ClassPath.COMPILE)) {
return ClassPathSupport.createClassPath(new FileObject[0]);
}
- if (type.equals(ClassPath.BOOT) || type.equals(JavaClassPathConstants.MODULE_BOOT_PATH)) {
+ if (type.equals(ClassPath.BOOT)) {
ClassPath cp = bootCache;
if (cp == null) {
- cp = TestUtil.getBootClassPath();
+ bootCache = cp = BootClassPathUtil.getBootClassPath();
+ }
+ return cp;
+ }
+ if (type.equals(JavaClassPathConstants.MODULE_BOOT_PATH)) {
+ ClassPath cp = moduleBootCache;
+ if (cp == null) {
+ moduleBootCache = cp = BootClassPathUtil.getModuleBootPath();
}
return cp;
}
diff --git a/java.hints.test/nbproject/project.properties b/java.hints.test/nbproject/project.properties
index 0bc79b3..f211965 100644
--- a/java.hints.test/nbproject/project.properties
+++ b/java.hints.test/nbproject/project.properties
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
is.autoload=true
-javac.source=1.7
+javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
spec.version.base=1.19.0
javadoc.arch=${basedir}/arch.xml
diff --git a/java.hints.test/nbproject/project.xml b/java.hints.test/nbproject/project.xml
index 0a5da9d..fc7a21a 100644
--- a/java.hints.test/nbproject/project.xml
+++ b/java.hints.test/nbproject/project.xml
@@ -87,6 +87,13 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.java.j2seplatform</code-name-base>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.42</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.java.lexer</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -147,6 +154,12 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.parsing.nb</code-name-base>
+ <run-dependency>
+ <specification-version>1.4</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.projectapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -156,6 +169,12 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.projectapi.nb</code-name-base>
+ <run-dependency>
+ <specification-version>1.4</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.projectuiapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -231,7 +250,7 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.ui</code-name-base>
+ <code-name-base>org.openide.util</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
@@ -239,19 +258,19 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util</code-name-base>
+ <code-name-base>org.openide.util.lookup</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.3</specification-version>
+ <specification-version>8.12</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.lookup</code-name-base>
+ <code-name-base>org.openide.util.ui</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>8.12</specification-version>
+ <specification-version>9.8</specification-version>
</run-dependency>
</dependency>
</module-dependencies>
diff --git a/java.hints.test/src/org/netbeans/modules/java/hints/test/BootClassPathUtil.java b/java.hints.test/src/org/netbeans/modules/java/hints/test/BootClassPathUtil.java
new file mode 100644
index 0000000..4e44114
--- /dev/null
+++ b/java.hints.test/src/org/netbeans/modules/java/hints/test/BootClassPathUtil.java
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.netbeans.modules.java.hints.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.spi.java.classpath.PathResourceImplementation;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileSystem;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.BaseUtilities;
+
+import static junit.framework.TestCase.assertFalse;
+import org.openide.filesystems.MultiFileSystem;
+import org.openide.filesystems.Repository;
+
+/** Note this is duplicated in:
+ * java.source.base/test/unit/src/org/netbeans/modules/java/source/BootClassPathUtil.java
+ *
+ * @author lahvac
+ */
+public class BootClassPathUtil {
+
+ public static ClassPath getBootClassPath() {
+ String cp = System.getProperty("sun.boot.class.path");
+ if (cp != null) {
+ List<URL> urls = new ArrayList<>();
+ String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
+ for (String path : paths) {
+ File f = new File(path);
+
+ if (!f.canRead())
+ continue;
+
+ FileObject fo = FileUtil.toFileObject(f);
+ if (FileUtil.isArchiveFile(fo)) {
+ fo = FileUtil.getArchiveRoot(fo);
+ }
+ if (fo != null) {
+ urls.add(fo.toURL());
+ }
+ }
+ return ClassPathSupport.createClassPath((URL[])urls.toArray(new URL[0]));
+ } else {
+ try {
+ Class.forName("org.netbeans.ProxyURLStreamHandlerFactory").getMethod("register")
+ .invoke(null);
+ } catch (ClassNotFoundException | NoSuchMethodException |
+ SecurityException | IllegalAccessException |
+ IllegalArgumentException | InvocationTargetException ex) {
+ throw new IllegalStateException(ex);
+ }
+ final List<PathResourceImplementation> modules = new ArrayList<>();
+ final File installDir = new File(System.getProperty("java.home"));
+ final URI imageURI = getImageURI(installDir);
+ try {
+ final FileObject jrtRoot = URLMapper.findFileObject(imageURI.toURL());
+ final FileObject root = getModulesRoot(jrtRoot);
+ for (FileObject module : root.getChildren()) {
+ modules.add(ClassPathSupport.createResource(module.toURL()));
+ }
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ assertFalse(modules.isEmpty());
+ return ClassPathSupport.createClassPath(modules);
+ }
+ }
+
+ public static ClassPath getModuleBootPath() {
+ if (System.getProperty("sun.boot.class.path") != null) {
+ try {
+ //JDK 8:
+ return getModuleBootOnJDK8();
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ } else {
+ return getBootClassPath();
+ }
+ }
+
+ private static final String PROTOCOL = "nbjrt"; //NOI18N
+
+ private static URI getImageURI(@NonNull final File jdkHome) {
+ try {
+ return new URI(String.format(
+ "%s:%s!/%s", //NOI18N
+ PROTOCOL,
+ BaseUtilities.toURI(jdkHome).toString(),
+ ""));
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException();
+ }
+ }
+
+ @NonNull
+ private static FileObject getModulesRoot(@NonNull final FileObject jrtRoot) {
+ final FileObject modules = jrtRoot.getFileObject("modules"); //NOI18N
+ //jimage v1 - modules are located in the root
+ //jimage v2 - modules are located in "modules" folder
+ return modules == null ?
+ jrtRoot :
+ modules;
+ }
+
+ //create fake "system module path" while running on JDK 8
+ //java.base contains rt.jar and exports all java.* packages:
+ private static ClassPath moduleBootOnJDK8;
+
+ private static ClassPath getModuleBootOnJDK8() throws Exception {
+ if (moduleBootOnJDK8 == null) {
+ List<FileSystem> roots = new ArrayList<>();
+
+ FileSystem output = FileUtil.createMemoryFileSystem();
+ FileObject sink = output.getRoot();
+
+ roots.add(output);
+
+ Set<String> packages = new HashSet<>();
+ for (FileObject r : getBootClassPath().getRoots()) {
+ FileObject javaDir = r.getFileObject("java");
+
+ if (javaDir == null)
+ continue;
+
+ roots.add(r.getFileSystem());
+
+ Enumeration<? extends FileObject> c = javaDir.getChildren(true);
+
+ while (c.hasMoreElements()) {
+ FileObject current = c.nextElement();
+
+ if (!current.isData() || !current.hasExt("class")) continue;
+
+ String rel = FileUtil.getRelativePath(r, current.getParent());
+
+ packages.add(rel.replace('/', '.'));
+ }
+ }
+
+ FileSystem outS = new MultiFileSystem(roots.toArray(new FileSystem[0])) {
+ {
+ setSystemName("module-boot");
+ }
+ };
+
+ Repository.getDefault().addFileSystem(outS);
+
+ StringBuilder moduleInfo = new StringBuilder();
+
+ moduleInfo.append("module java.base {\n");
+
+ for (String pack : packages) {
+ moduleInfo.append(" exports " + pack + ";\n");
+ }
+
+ moduleInfo.append("}\n");
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ FileObject javaBase = outS.getRoot();
+
+ try (JavaFileManager fm = compiler.getStandardFileManager(null, null, null);
+ JFMImpl fmImpl = new JFMImpl(fm, javaBase, sink)) {
+ compiler.getTask(null, fmImpl, null, Arrays.asList("-proc:none"), null,
+ Arrays.asList(new SimpleJavaFileObject(new URI("mem:///module-info.java"), javax.tools.JavaFileObject.Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return moduleInfo.toString();
+ }
+ })).call();
+ }
+
+ javaBase.refresh();
+ moduleBootOnJDK8 = ClassPathSupport.createClassPath(javaBase);
+ }
+
+ return moduleBootOnJDK8;
+ }
+
+ private static class JFMImpl extends ForwardingJavaFileManager<JavaFileManager> {
+ private final FileObject output;
+ private final FileObject sink;
+
+ public JFMImpl(JavaFileManager fileManager, FileObject output, FileObject sink) {
+ super(fileManager);
+ this.output = output;
+ this.sink = sink;
+ }
+
+ @Override
+ public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ List<JavaFileObject> result = new ArrayList<>();
+ FileObject pack = output.getFileObject(packageName.replace('.', '/'));
+
+ if (pack != null) {
+ Enumeration<? extends FileObject> c = pack.getChildren(recurse);
+
+ while (c.hasMoreElements()) {
+ FileObject file = c.nextElement();
+ if (!file.hasExt("class"))
+ continue;
+ result.add(new InferableJavaFileObject(file, JavaFileObject.Kind.CLASS));
+ }
+ }
+
+ return result;
+ }
+ return super.list(location, packageName, kinds, recurse);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, javax.tools.FileObject sibling) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ String relPath = className.replace('.', '/') + ".class";
+ try {
+ return new SimpleJavaFileObject(new URI("mem://" + relPath), kind) {
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return new ByteArrayOutputStream() {
+ @Override
+ public void close() throws IOException {
+ super.close();
+ FileObject target = FileUtil.createData(sink, relPath);
+ try (OutputStream out = target.getOutputStream()) {
+ out.write(toByteArray());
+ }
+ }
+ };
+ }
+ };
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ }
+ return super.getJavaFileForOutput(location, className, kind, sibling);
+ }
+
+ @Override
+ public String inferBinaryName(Location location, JavaFileObject file) {
+ if (file instanceof InferableJavaFileObject) {
+ return ((InferableJavaFileObject) file).className;
+ }
+ return super.inferBinaryName(location, file);
+ }
+
+ private class InferableJavaFileObject extends SimpleJavaFileObject {
+
+ private final String className;
+ public InferableJavaFileObject(FileObject file, Kind kind) {
+ super(file.toURI(), kind);
+ String relPath = FileUtil.getRelativePath(output, file);
+ className = relPath.substring(0, relPath.length() - ".class".length()).replace('/', '.');
+ }
+ }
+
+ }
+
+}
diff --git a/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java b/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
index 202f548..98c80ce 100644
--- a/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
+++ b/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
@@ -56,13 +56,14 @@ import javax.swing.text.Document;
import javax.tools.Diagnostic;
import junit.framework.Assert;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertFalse;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.JavaClassPathConstants;
import org.netbeans.api.java.lexer.JavaTokenId;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.java.queries.SourceForBinaryQuery.Result;
@@ -97,8 +98,10 @@ import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
+import org.netbeans.modules.java.hints.test.BootClassPathUtil;
import org.netbeans.modules.java.hints.test.Utilities.TestLookup;
import org.netbeans.modules.java.source.JavaSourceAccessor;
+import org.netbeans.modules.java.source.parsing.JavacParser;
import org.netbeans.modules.parsing.api.indexing.IndexingManager;
import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
@@ -261,6 +264,7 @@ public class HintTest {
sourcePath = ClassPathSupport.createClassPath(sourceRoot);
Main.initializeURLFactory();
+ JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
}
/**Bootstraps the test framework.
@@ -664,51 +668,18 @@ public class HintTest {
}
- private static List<URL> bootClassPath;
-
private static Logger log = Logger.getLogger(HintTest.class.getName());
- private static synchronized List<URL> getBootClassPath() {
- if (bootClassPath == null) {
- try {
- String cp = System.getProperty("sun.boot.class.path");
- List<URL> urls = new ArrayList<URL>();
- String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
-
- for (String path : paths) {
- File f = new File(path);
-
- if (!f.canRead())
- continue;
-
- FileObject fo = FileUtil.toFileObject(f);
-
- if (FileUtil.isArchiveFile(fo)) {
- fo = FileUtil.getArchiveRoot(fo);
- }
-
- if (fo != null) {
- urls.add(fo.getURL());
- }
- }
-
- bootClassPath = urls;
- } catch (FileStateInvalidException e) {
- if (log.isLoggable(Level.SEVERE))
- log.log(Level.SEVERE, e.getMessage(), e);
- }
- }
-
- return bootClassPath;
- }
-
private class TestProxyClassPathProvider implements ClassPathProvider {
public ClassPath findClassPath(FileObject file, String type) {
try {
if (ClassPath.BOOT == type) {
- // XXX simpler to use JavaPlatformManager.getDefault().getDefaultPlatform().getBootstrapLibraries()
- return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
+ return BootClassPathUtil.getBootClassPath();
+ }
+
+ if (JavaClassPathConstants.MODULE_BOOT_PATH == type) {
+ return BootClassPathUtil.getModuleBootPath();
}
if (ClassPath.SOURCE == type) {
diff --git a/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java b/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java
index a910d70..22a9970 100644
--- a/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java
+++ b/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java
@@ -302,4 +302,22 @@ public class HintTestTest {
Assert.assertEquals("6\n7\n", doc.getText(0, doc.getLength()));
}
+ @Test
+ public void testModuleBootPath() throws Exception {
+ HintTest.create()
+ .sourceLevel("9")
+ .input("module-info.java",
+ "module m1 {}\n")
+ .run(ModuleBootPath.class)
+ .assertWarnings("0:0-0:12:verifier:Test");
+ }
+
+ @Hint(displayName="testModuleBootPath", description="testModuleBootPath", category="test")
+ public static final class ModuleBootPath {
+ @TriggerTreeKind(Kind.MODULE)
+ public static ErrorDescription hint(HintContext ctx) {
+ return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), "Test");
+ }
+ }
+
}
diff --git a/java.hints/nbproject/project.xml b/java.hints/nbproject/project.xml
index 04e5500..a328b25 100644
--- a/java.hints/nbproject/project.xml
+++ b/java.hints/nbproject/project.xml
@@ -544,6 +544,9 @@
<compile-dependency/>
</test-dependency>
<test-dependency>
+ <code-name-base>org.netbeans.modules.java.j2seplatform</code-name-base>
+ </test-dependency>
+ <test-dependency>
<code-name-base>org.netbeans.modules.java.source.base</code-name-base>
<compile-dependency/>
<test/>
diff --git a/java.source.base/test/unit/src/org/netbeans/modules/java/source/BootClassPathUtil.java b/java.source.base/test/unit/src/org/netbeans/modules/java/source/BootClassPathUtil.java
new file mode 100644
index 0000000..7ea0fde
--- /dev/null
+++ b/java.source.base/test/unit/src/org/netbeans/modules/java/source/BootClassPathUtil.java
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.netbeans.modules.java.source;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.spi.java.classpath.PathResourceImplementation;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileSystem;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.BaseUtilities;
+
+import static junit.framework.TestCase.assertFalse;
+import org.openide.filesystems.MultiFileSystem;
+import org.openide.filesystems.Repository;
+
+/** Note this is duplicated in:
+ * java.hints.test/src/org/netbeans/modules/java/hints/test/BootClassPathUtil.java
+ *
+ * @author lahvac
+ */
+public class BootClassPathUtil {
+
+ public static ClassPath getBootClassPath() {
+ String cp = System.getProperty("sun.boot.class.path");
+ if (cp != null) {
+ List<URL> urls = new ArrayList<>();
+ String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
+ for (String path : paths) {
+ File f = new File(path);
+
+ if (!f.canRead())
+ continue;
+
+ FileObject fo = FileUtil.toFileObject(f);
+ if (FileUtil.isArchiveFile(fo)) {
+ fo = FileUtil.getArchiveRoot(fo);
+ }
+ if (fo != null) {
+ urls.add(fo.toURL());
+ }
+ }
+ return ClassPathSupport.createClassPath((URL[])urls.toArray(new URL[0]));
+ } else {
+ try {
+ Class.forName("org.netbeans.ProxyURLStreamHandlerFactory").getMethod("register")
+ .invoke(null);
+ } catch (ClassNotFoundException | NoSuchMethodException |
+ SecurityException | IllegalAccessException |
+ IllegalArgumentException | InvocationTargetException ex) {
+ throw new IllegalStateException(ex);
+ }
+ final List<PathResourceImplementation> modules = new ArrayList<>();
+ final File installDir = new File(System.getProperty("java.home"));
+ final URI imageURI = getImageURI(installDir);
+ try {
+ final FileObject jrtRoot = URLMapper.findFileObject(imageURI.toURL());
+ final FileObject root = getModulesRoot(jrtRoot);
+ for (FileObject module : root.getChildren()) {
+ modules.add(ClassPathSupport.createResource(module.toURL()));
+ }
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ assertFalse(modules.isEmpty());
+ return ClassPathSupport.createClassPath(modules);
+ }
+ }
+
+ public static ClassPath getModuleBootPath() {
+ if (System.getProperty("sun.boot.class.path") != null) {
+ try {
+ //JDK 8:
+ return getModuleBootOnJDK8();
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ } else {
+ return getBootClassPath();
+ }
+ }
+
+ private static final String PROTOCOL = "nbjrt"; //NOI18N
+
+ private static URI getImageURI(@NonNull final File jdkHome) {
+ try {
+ return new URI(String.format(
+ "%s:%s!/%s", //NOI18N
+ PROTOCOL,
+ BaseUtilities.toURI(jdkHome).toString(),
+ ""));
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException();
+ }
+ }
+
+ @NonNull
+ private static FileObject getModulesRoot(@NonNull final FileObject jrtRoot) {
+ final FileObject modules = jrtRoot.getFileObject("modules"); //NOI18N
+ //jimage v1 - modules are located in the root
+ //jimage v2 - modules are located in "modules" folder
+ return modules == null ?
+ jrtRoot :
+ modules;
+ }
+
+ //create fake "system module path" while running on JDK 8
+ //java.base contains rt.jar and exports all java.* packages:
+ private static ClassPath moduleBootOnJDK8;
+
+ private static ClassPath getModuleBootOnJDK8() throws Exception {
+ if (moduleBootOnJDK8 == null) {
+ List<FileSystem> roots = new ArrayList<>();
+
+ FileSystem output = FileUtil.createMemoryFileSystem();
+ FileObject sink = output.getRoot();
+
+ roots.add(output);
+
+ Set<String> packages = new HashSet<>();
+ for (FileObject r : getBootClassPath().getRoots()) {
+ FileObject javaDir = r.getFileObject("java");
+
+ if (javaDir == null)
+ continue;
+
+ roots.add(r.getFileSystem());
+
+ Enumeration<? extends FileObject> c = javaDir.getChildren(true);
+
+ while (c.hasMoreElements()) {
+ FileObject current = c.nextElement();
+
+ if (!current.isData() || !current.hasExt("class")) continue;
+
+ String rel = FileUtil.getRelativePath(r, current.getParent());
+
+ packages.add(rel.replace('/', '.'));
+ }
+ }
+
+ FileSystem outS = new MultiFileSystem(roots.toArray(new FileSystem[0])) {
+ {
+ setSystemName("module-boot");
+ }
+ };
+
+ Repository.getDefault().addFileSystem(outS);
+
+ StringBuilder moduleInfo = new StringBuilder();
+
+ moduleInfo.append("module java.base {\n");
+
+ for (String pack : packages) {
+ moduleInfo.append(" exports " + pack + ";\n");
+ }
+
+ moduleInfo.append("}\n");
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ FileObject javaBase = outS.getRoot();
+
+ try (JavaFileManager fm = compiler.getStandardFileManager(null, null, null);
+ JFMImpl fmImpl = new JFMImpl(fm, javaBase, sink)) {
+ compiler.getTask(null, fmImpl, null, Arrays.asList("-proc:none"), null,
+ Arrays.asList(new SimpleJavaFileObject(new URI("mem:///module-info.java"), javax.tools.JavaFileObject.Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return moduleInfo.toString();
+ }
+ })).call();
+ }
+
+ javaBase.refresh();
+ moduleBootOnJDK8 = ClassPathSupport.createClassPath(javaBase);
+ }
+
+ return moduleBootOnJDK8;
+ }
+
+ private static class JFMImpl extends ForwardingJavaFileManager<JavaFileManager> {
+ private final FileObject output;
+ private final FileObject sink;
+
+ public JFMImpl(JavaFileManager fileManager, FileObject output, FileObject sink) {
+ super(fileManager);
+ this.output = output;
+ this.sink = sink;
+ }
+
+ @Override
+ public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ List<JavaFileObject> result = new ArrayList<>();
+ FileObject pack = output.getFileObject(packageName.replace('.', '/'));
+
+ if (pack != null) {
+ Enumeration<? extends FileObject> c = pack.getChildren(recurse);
+
+ while (c.hasMoreElements()) {
+ FileObject file = c.nextElement();
+ if (!file.hasExt("class"))
+ continue;
+ result.add(new InferableJavaFileObject(file, JavaFileObject.Kind.CLASS));
+ }
+ }
+
+ return result;
+ }
+ return super.list(location, packageName, kinds, recurse);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, javax.tools.FileObject sibling) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ String relPath = className.replace('.', '/') + ".class";
+ try {
+ return new SimpleJavaFileObject(new URI("mem://" + relPath), kind) {
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return new ByteArrayOutputStream() {
+ @Override
+ public void close() throws IOException {
+ super.close();
+ FileObject target = FileUtil.createData(sink, relPath);
+ try (OutputStream out = target.getOutputStream()) {
+ out.write(toByteArray());
+ }
+ }
+ };
+ }
+ };
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ }
+ return super.getJavaFileForOutput(location, className, kind, sibling);
+ }
+
+ @Override
+ public String inferBinaryName(Location location, JavaFileObject file) {
+ if (file instanceof InferableJavaFileObject) {
+ return ((InferableJavaFileObject) file).className;
+ }
+ return super.inferBinaryName(location, file);
+ }
+
+ private class InferableJavaFileObject extends SimpleJavaFileObject {
+
+ private final String className;
+ public InferableJavaFileObject(FileObject file, Kind kind) {
+ super(file.toURI(), kind);
+ String relPath = FileUtil.getRelativePath(output, file);
+ className = relPath.substring(0, relPath.length() - ".class".length()).replace('/', '.');
+ }
+ }
+
+ }
+
+}
diff --git a/java.source.base/test/unit/src/org/netbeans/modules/java/source/TestUtil.java b/java.source.base/test/unit/src/org/netbeans/modules/java/source/TestUtil.java
index cf658e7..8245627 100644
--- a/java.source.base/test/unit/src/org/netbeans/modules/java/source/TestUtil.java
+++ b/java.source.base/test/unit/src/org/netbeans/modules/java/source/TestUtil.java
@@ -405,65 +405,7 @@ public class TestUtil {
}
public static ClassPath getBootClassPath() {
- String cp = System.getProperty("sun.boot.class.path");
- if (cp != null) {
- List<URL> urls = new ArrayList<>();
- String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
- for (String path : paths) {
- File f = new File(path);
-
- if (!f.canRead())
- continue;
-
- FileObject fo = FileUtil.toFileObject(f);
- if (FileUtil.isArchiveFile(fo)) {
- fo = FileUtil.getArchiveRoot(fo);
- }
- if (fo != null) {
- urls.add(fo.toURL());
- }
- }
- return ClassPathSupport.createClassPath((URL[])urls.toArray(new URL[0]));
- } else {
- ProxyURLStreamHandlerFactory.register();
- final List<PathResourceImplementation> modules = new ArrayList<>();
- final File installDir = new File(System.getProperty("java.home"));
- final URI imageURI = getImageURI(installDir);
- try {
- final FileObject jrtRoot = URLMapper.findFileObject(imageURI.toURL());
- final FileObject root = getModulesRoot(jrtRoot);
- for (FileObject module : root.getChildren()) {
- modules.add(ClassPathSupport.createResource(module.toURL()));
- }
- } catch (MalformedURLException e) {
- throw new IllegalStateException(e);
- }
- assertFalse(modules.isEmpty());
- return ClassPathSupport.createClassPath(modules);
- }
+ return BootClassPathUtil.getBootClassPath();
}
- private static final String PROTOCOL = "nbjrt"; //NOI18N
-
- private static URI getImageURI(@NonNull final File jdkHome) {
- try {
- return new URI(String.format(
- "%s:%s!/%s", //NOI18N
- PROTOCOL,
- BaseUtilities.toURI(jdkHome).toString(),
- ""));
- } catch (URISyntaxException e) {
- throw new IllegalStateException();
- }
- }
-
- @NonNull
- private static FileObject getModulesRoot(@NonNull final FileObject jrtRoot) {
- final FileObject modules = jrtRoot.getFileObject("modules"); //NOI18N
- //jimage v1 - modules are located in the root
- //jimage v2 - modules are located in "modules" folder
- return modules == null ?
- jrtRoot :
- modules;
- }
}
--
To stop receiving notification emails like this one, please contact
geertjan@apache.org.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists