You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by lk...@apache.org on 2020/10/23 01:10:50 UTC

[netbeans] 03/18: Annotation processors may generate class files: -that have a name different from any source file in the source roots -even while running in the editor

This is an automated email from the ASF dual-hosted git repository.

lkishalmi pushed a commit to branch release122
in repository https://gitbox.apache.org/repos/asf/netbeans.git

commit 5c2f2f275c0e0192449d31955d7db4ada705fd6d
Author: Jan Lahoda <jl...@netbeans.org>
AuthorDate: Sun Oct 18 10:06:55 2020 +0200

    Annotation processors may generate class files:
    -that have a name different from any source file in the source roots
    -even while running in the editor
    
    But neither of these seems to be working - fixing.
---
 .../java/source/parsing/OutputFileManager.java     |  48 ++--
 .../parsing/WriteArbitraryClassFileAPTest.java     | 269 +++++++++++++++++++++
 2 files changed, 288 insertions(+), 29 deletions(-)

diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/OutputFileManager.java b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/OutputFileManager.java
index 65bf36e..146ead0 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/OutputFileManager.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/OutputFileManager.java
@@ -21,14 +21,12 @@ package org.netbeans.modules.java.source.parsing;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -116,22 +114,28 @@ public class OutputFileManager extends CachingFileManager {
             File activeRoot = getClassFolderForSource(l, sibling, baseName);
             if (activeRoot == null) {
                 activeRoot = getClassFolderForApt(l, sibling, baseName);
+            }
+            if (activeRoot == null && siblings.hasSibling()) {
+                URL siblingURL = siblings.getSibling();
+                activeRoot = getClassFolderForSourceImpl(siblingURL);
                 if (activeRoot == null) {
-                    //Deleted project
-                    if (this.scp.getRoots().length > 0) {
-                        LOG.log(
-                            Level.WARNING,
-                            "No output for class: {0} sibling: {1} srcRoots: {2}",    //NOI18N
-                            new Object[]{
-                                className,
-                                sibling,
-                                this.scp
-                            });
-                    }
-                    throw new InvalidSourcePath ();
+                    activeRoot = getClassFolderForApt(siblingURL);
                 }
             }
-            assertValidRoot(activeRoot, l);
+            if (activeRoot == null) {
+                //Deleted project
+                if (this.scp.getRoots().length > 0) {
+                    LOG.log(
+                        Level.WARNING,
+                        "No output for class: {0} sibling: {1} srcRoots: {2}",    //NOI18N
+                        new Object[]{
+                            className,
+                            sibling,
+                            this.scp
+                        });
+                }
+                throw new InvalidSourcePath ();
+            }
             baseName = className.replace('.', File.separatorChar);       //NOI18N
             String nameStr = baseName + '.' + FileObjects.SIG;
             final File f = new File (activeRoot, nameStr);
@@ -166,7 +170,6 @@ public class OutputFileManager extends CachingFileManager {
                 throw new InvalidSourcePath ();
             }
         }
-        assertValidRoot(activeRoot, l);
         final String path = FileObjects.resolveRelativePath(pkgName, relativeName);
         final File file = FileUtil.normalizeFile(new File (activeRoot,path.replace(FileObjects.NBFS_SEPARATOR_CHAR, File.separatorChar)));
         return tx.createFileObject(l, file, activeRoot,null,null);
@@ -461,17 +464,4 @@ public class OutputFileManager extends CachingFileManager {
             return ModuleLocation.cast(l).getModuleRoots();
         }
     }
-
-    private void assertValidRoot(
-            final File activeRoot,
-            final Location l) throws IOException {
-        final Collection<? extends URL> roots = getLocationRoots(l);
-        if (!roots.contains(BaseUtilities.toURI(activeRoot).toURL())) {
-            throw new IOException(String.format(
-                    "Wrong cache folder: %s, allowed: %s, location: %s",    //NOI18N
-                    activeRoot,
-                    roots,
-                    l));
-        }
-    }
 }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/parsing/WriteArbitraryClassFileAPTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/parsing/WriteArbitraryClassFileAPTest.java
new file mode 100644
index 0000000..586c925
--- /dev/null
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/parsing/WriteArbitraryClassFileAPTest.java
@@ -0,0 +1,269 @@
+/*
+ * 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.parsing;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import junit.framework.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.element.TypeElement;
+import javax.swing.event.ChangeListener;
+import javax.tools.StandardLocation;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.JavaClassPathConstants;
+import org.netbeans.api.java.queries.AnnotationProcessingQuery;
+import org.netbeans.api.java.queries.AnnotationProcessingQuery.Result;
+import org.netbeans.api.java.queries.AnnotationProcessingQuery.Trigger;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.source.TestUtil;
+import org.netbeans.modules.java.source.usages.IndexUtil;
+import org.netbeans.spi.java.classpath.ClassPathProvider;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
+import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
+import org.openide.filesystems.FileLock;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+public class WriteArbitraryClassFileAPTest extends NbTestCase {
+
+    private FileObject src1;
+    private FileObject src2;
+    private FileObject data;
+
+    static {
+        WriteArbitraryClassFileAPTest.class.getClassLoader().setDefaultAssertionStatus(true);
+        System.setProperty("org.openide.util.Lookup", WriteArbitraryClassFileAPTest.Lkp.class.getName());
+        Assert.assertEquals(WriteArbitraryClassFileAPTest.Lkp.class, Lookup.getDefault().getClass());
+    }
+
+    public static class Lkp extends ProxyLookup {
+
+        private static Lkp DEFAULT;
+
+        public Lkp () {
+            Assert.assertNull(DEFAULT);
+            DEFAULT = this;
+            ClassLoader l = Lkp.class.getClassLoader();
+            this.setLookups(
+                 new Lookup [] {
+                    Lookups.metaInfServices(l),
+                    Lookups.singleton(l),
+                    Lookups.singleton(ClassPathProviderImpl.getDefault()),
+                    Lookups.singleton(SourceLevelQueryImpl.getDefault()),
+                    Lookups.singleton(new APQImpl()),
+            });
+        }
+
+    }
+
+
+    public WriteArbitraryClassFileAPTest(String testName) {
+        super(testName);
+    }
+
+    protected void setUp() throws Exception {
+        clearWorkDir();
+        File workDir = getWorkDir();
+        File cacheFolder = new File (workDir, "cache"); //NOI18N
+        cacheFolder.mkdirs();
+        IndexUtil.setCacheFolder(cacheFolder);
+        FileObject wd = FileUtil.toFileObject(this.getWorkDir());
+        assertNotNull(wd);
+        this.src1 = wd.createFolder("src1");
+        this.data = src1.createData("Test","java");
+        this.src2 = wd.createFolder("src2");
+        FileLock lock = data.lock();
+        try {
+            PrintWriter out = new PrintWriter ( new OutputStreamWriter (data.getOutputStream(lock)));
+            try {
+                out.println ("public class Test {}");
+            } finally {
+                out.close ();
+            }
+        } finally {
+            lock.releaseLock();
+        }
+        ClassPathProviderImpl.getDefault().setClassPaths(TestUtil.getBootClassPath(),
+                                                         ClassPathSupport.createClassPath(new URL[0]),
+                                                         ClassPathSupport.createClassPath(new FileObject[]{this.src1, this.src2}),
+                                                         ClassPathSupport.createClassPath(System.getProperty("java.class.path")));
+    }
+
+    public void testWriteArbitraryClassFile() throws Exception {
+        final JavaSource js = JavaSource.forFileObject(data);
+        assertNotNull(js);
+
+        js.runUserActionTask(new Task<CompilationController>() {
+            public void run(CompilationController parameter) throws IOException {
+                parameter.toPhase(Phase.RESOLVED);
+                List<String> messages = parameter.getDiagnostics()
+                                                 .stream()
+                                                 .map(d -> d.getMessage(null))
+                                                 .map(m -> firstLine(m))
+                                                 .collect(Collectors.toList());
+                assertEquals(Collections.emptyList(), messages);
+            }
+        },true);
+    }
+
+    private String firstLine(String m) {
+        int newLine = m.indexOf('\n');
+        if (newLine == (-1)) return m;
+        return m.substring(0, newLine);
+    }
+
+    private static class ClassPathProviderImpl implements ClassPathProvider {
+
+        private static ClassPathProviderImpl instance;
+
+        private ClassPath compile;
+        private ClassPath boot;
+        private ClassPath src;
+        private ClassPath processorPath;
+
+        private ClassPathProviderImpl () {
+
+        }
+
+        public synchronized ClassPath findClassPath(FileObject file, String type) {
+            if (ClassPath.COMPILE.equals(type)) {
+                return compile;
+            }
+            else if (ClassPath.BOOT.equals(type)) {
+                return boot;
+            }
+            else if (ClassPath.SOURCE.equals(type)) {
+                return src;
+            }
+            else if (JavaClassPathConstants.PROCESSOR_PATH.equals(type)) {
+                return processorPath;
+            }
+            else {
+                return null;
+            }
+        }
+
+        public synchronized void setClassPaths (ClassPath boot, ClassPath compile, ClassPath src, ClassPath processorPath) {
+            this.boot = boot;
+            this.compile = compile;
+            this.src = src;
+            this.processorPath = processorPath;
+        }
+
+        public static synchronized ClassPathProviderImpl getDefault () {
+            if (instance == null) {
+                instance = new ClassPathProviderImpl ();
+            }
+            return instance;
+        }
+    }
+
+    private static class SourceLevelQueryImpl implements SourceLevelQueryImplementation {
+
+        private static SourceLevelQueryImpl instance;
+
+        private SourceLevelQueryImpl() {}
+
+        @Override
+        public String getSourceLevel(FileObject javaFile) {
+            return "8";
+        }
+
+        public static synchronized SourceLevelQueryImpl getDefault () {
+            if (instance == null) {
+                instance = new SourceLevelQueryImpl();
+            }
+            return instance;
+        }
+    }
+
+    private static class APQImpl implements AnnotationProcessingQueryImplementation {
+
+        private final Result result = new Result() {
+            public @NonNull Set<? extends Trigger> annotationProcessingEnabled() {
+                return EnumSet.allOf(Trigger.class);
+            }
+
+            public @CheckForNull Iterable<? extends String> annotationProcessorsToRun() {
+                return Arrays.asList(TestAP.class.getName());
+            }
+
+            public @CheckForNull URL sourceOutputDirectory() {
+                return null;
+            }
+
+            public @NonNull Map<? extends String, ? extends String> processorOptions() {
+                return Collections.emptyMap();
+            }
+
+            public void addChangeListener(@NonNull ChangeListener l) {}
+
+            public void removeChangeListener(@NonNull ChangeListener l) {}
+        };
+        @Override
+        public AnnotationProcessingQuery.Result getAnnotationProcessingOptions(FileObject file) {
+            return result;
+        }
+
+    }
+
+    @SupportedAnnotationTypes("*")
+    public static class TestAP extends AbstractProcessor {
+        int round = 0;
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            if (round++ == 0) {
+                try {
+                    processingEnv.getFiler().createClassFile("any.Name");
+                    processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "any", "Name.class");
+                } catch (IOException ex) {
+                    throw new AssertionError(ex);
+                }
+            }
+            return false;
+        }
+    }
+
+    static {
+        System.setProperty("SourcePath.no.source.filter", "true");
+    }
+}


---------------------------------------------------------------------
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