From ed150ca5c43e5e322ac819b5c9efa0ef4367a216 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 5 Sep 2024 09:23:18 +0200 Subject: [PATCH] Roots (and directories) containing multi-file launcher sources should respond to ClassPath queries. --- .../queries/MultiSourceRootProvider.java | 38 +++++++++++---- .../queries/Bundle_registerroots.properties | 17 +++++++ .../queries/MultiSourceRootProviderTest.java | 48 ++++++++++++++++++- 3 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/Bundle_registerroots.properties diff --git a/java/java.file.launcher/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProvider.java b/java/java.file.launcher/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProvider.java index 0bfc6bfbc23d..316d8bdc0569 100644 --- a/java/java.file.launcher/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProvider.java +++ b/java/java.file.launcher/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProvider.java @@ -94,16 +94,33 @@ public class MultiSourceRootProvider implements ClassPathProvider { private Map file2ClassPath = new WeakHashMap<>(); private Map file2ModulePath = new WeakHashMap<>(); - static boolean isSupportedFile(FileObject file) { - return SingleSourceFileUtil.isSingleSourceFile(file) - // MultiSourceRootProvider assumes it can convert FileObject to - // java.io.File, so filter here - && Objects.equals("file", file.toURI().getScheme()); + boolean isSupportedFile(FileObject file) { + // MultiSourceRootProvider assumes it can convert FileObject to + // java.io.File, so filter here + if (!Objects.equals("file", file.toURI().getScheme())) { + return false; + } + + if (SingleSourceFileUtil.isSingleSourceFile(file)) { + return true; + } + + if (!registerRoots()) { + return false; + } + + for (FileObject existingRoot : root2SourceCP.keySet()) { + if (file.equals(existingRoot) || FileUtil.isParentOf(existingRoot, file)) { + return true; + } + } + + return false; } @Override public ClassPath findClassPath(FileObject file, String type) { - if (! isSupportedFile(file)) { + if (!isSupportedFile(file)) { return null; } switch (type) { @@ -150,7 +167,7 @@ private ClassPath getSourcePath(FileObject file) { return root2SourceCP.computeIfAbsent(root, r -> { ClassPath srcCP = ClassPathSupport.createClassPath(Arrays.asList(new RootPathResourceImplementation(r))); - if (registerRoot(r)) { + if (registerRoots()) { GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {srcCP}); } return srcCP; @@ -272,7 +289,7 @@ private ClassPath attributeBasedPath(FileObject file, Map @Messages({ "SETTING_AutoRegisterAsRoot=false" }) - private static boolean registerRoot(FileObject root) { + private static boolean registerRoots() { return "true".equals(Bundle.SETTING_AutoRegisterAsRoot()); } @@ -355,7 +372,10 @@ private void doUpdateDelegates() { for (File expanded : expandedPaths) { URL u = FileUtil.urlForArchiveOrDir(expanded); if (u == null) { - throw new IllegalArgumentException("Path entry looks to be invalid: " + piece); // NOI18N + LOG.log(Level.INFO, + "While parsing command line option '{0}' with parameter '{1}', path entry looks to be invalid: '{2}'", + new Object[] {currentOption, parsed.get(i + 1), piece}); + continue; } newURLs.add(u); newDelegates.add(ClassPathSupport.createResource(u)); diff --git a/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/Bundle_registerroots.properties b/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/Bundle_registerroots.properties new file mode 100644 index 000000000000..d13c21373f31 --- /dev/null +++ b/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/Bundle_registerroots.properties @@ -0,0 +1,17 @@ +# 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. +SETTING_AutoRegisterAsRoot=true diff --git a/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProviderTest.java b/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProviderTest.java index ff7245d3af48..5f600dd97dbe 100644 --- a/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProviderTest.java +++ b/java/java.file.launcher/test/unit/src/org/netbeans/modules/java/file/launcher/queries/MultiSourceRootProviderTest.java @@ -19,7 +19,9 @@ package org.netbeans.modules.java.file.launcher.queries; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.Writer; import java.net.URI; import java.nio.file.Files; import java.util.Arrays; @@ -37,6 +39,7 @@ import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; import org.openide.util.Lookup; +import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; @@ -254,9 +257,10 @@ public void testMultiSourceRootProviderOnlySupportedForLocalFiles() throws IOExc supportedFile = Files.createTempFile("dummy", ".java").toFile(); FileObject realFileSource = FileUtil.createData(supportedFile); FileObject inMemorySource = FileUtil.createMemoryFileSystem().getRoot().createData("Ahoj.java"); + MultiSourceRootProvider provider = new MultiSourceRootProvider(); - assertFalse(MultiSourceRootProvider.isSupportedFile(inMemorySource)); - assertTrue(MultiSourceRootProvider.isSupportedFile(realFileSource)); + assertFalse(provider.isSupportedFile(inMemorySource)); + assertTrue(provider.isSupportedFile(realFileSource)); } finally { if(supportedFile != null && supportedFile.exists()) { supportedFile.delete(); @@ -264,6 +268,46 @@ public void testMultiSourceRootProviderOnlySupportedForLocalFiles() throws IOExc } } + public void testMultiSourceRootProviderRespondsForKnownFolders() throws IOException { + File wd = getWorkDir(); + File testDir = new File(wd, "test"); + File packDir = new File(testDir, "pack"); + File testFile = new File(packDir, "Test.java"); + + packDir.mkdirs(); + + try (Writer w = Files.newBufferedWriter(testFile.toPath())) { + w.write("package pack;"); + } + + MultiSourceRootProvider provider = new MultiSourceRootProvider(); + + //before recongizing testDir is a multi-source file root: + assertNull(provider.findClassPath(FileUtil.toFileObject(wd), ClassPath.SOURCE)); + assertNull(provider.findClassPath(FileUtil.toFileObject(testDir), ClassPath.SOURCE)); + assertNull(provider.findClassPath(FileUtil.toFileObject(packDir), ClassPath.SOURCE)); + + //recognize the source file as a multi-source file: + ClassPath cp = provider.findClassPath(FileUtil.toFileObject(testFile), ClassPath.SOURCE); + + assertNotNull(cp); + + //check properties: + assertNull(provider.findClassPath(FileUtil.toFileObject(wd), ClassPath.SOURCE)); + assertNull(provider.findClassPath(FileUtil.toFileObject(testDir), ClassPath.SOURCE)); + assertNull(provider.findClassPath(FileUtil.toFileObject(packDir), ClassPath.SOURCE)); + + String originalBranding = NbBundle.getBranding(); + try { + NbBundle.setBranding("registerroots"); + assertNull(provider.findClassPath(FileUtil.toFileObject(wd), ClassPath.SOURCE)); + assertSame(cp, provider.findClassPath(FileUtil.toFileObject(testDir), ClassPath.SOURCE)); + assertSame(cp, provider.findClassPath(FileUtil.toFileObject(packDir), ClassPath.SOURCE)); + } finally { + NbBundle.setBranding(originalBranding); + } + } + @Override protected void setUp() throws Exception { super.setUp();