Bug 170231 - Allow exclusion of packages/classes in classpath
Allow exclusion of packages/classes in classpath
Product: java
Classification: Unclassified
Component: Source
All All
: P2 (vote)
Assigned To: Svata Dedic
: 180429 (view as bug list)
Depends on:
Blocks: 49026
  Show dependency treegraph
Reported: 2009-08-11 20:50 UTC by maxnitribitt
Modified: 2014-05-16 08:00 UTC (History)
8 users (show)

See Also:

Something to be qfold'ed in (17.96 KB, patch)
2009-12-17 17:19 UTC, Jesse Glick
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description maxnitribitt 2009-08-11 20:50:51 UTC
Like NetBeans Modules, OSGi bundles can have public and private packages defined in the Manifest of the JAR. So like in
NetBeans Module projects Code Completion should only display these java classes in codecompletion, fix imports, etc.
that are acually accessible at runtime. I'm trying to add OSGi projects to NetBeans, but it seems that it is currently
impossible to implement this feature. 

The OSGi Maven Archetype which is already included in NetBeans has the same problem. 

For project dependencies there's org.netbeans.spi.java.queries.AccessibilityQueryImplementation to implement this. For
binary dependencies there's currently no way. 

Additional/related usecases for such a feature are also described here:
Comment 1 Jesse Glick 2009-08-11 22:22:33 UTC
The API in ClassPath does permit you to specify that only part of a binary entry should be used, but the Java indexer
simply ignores this information as far as I know, so no one bothers specifying it. (Includes/excludes are currently used
only for ClassPath.SOURCE.)

NetBeans module projects do _not_ offer only "appropriate" classes in code completion, fix imports, etc. due to the lack
of this feature. Public packages are enforced only during the build.

Could also be used to prevent sun.** classes from being used in a project accidentally. I remember there was some effort
to implement this as an editor hint, but I think it would be cleaner for the JavaPlatform.getBootstrapLibraries() to
exclude these classes from the start. That would also leave the decision on which classes to exclude ultimately in the
control of the project's ClassPathProvider, which in the case of BOOT would normally delegate to the JavaPlatform.

AccessibilityQueryImplementation controls only the icons of packages displayed in the Projects node. It currently has no
effect on anything else. (Anyway it would be useless for implementing this feature because the list of packages
"accessible" depends in general on who is doing the accessing, and AQ does not represent the accessor. For example, with
NetBeans module projects, an implementation dependency gives you access to all packages.)

The situation with project dependencies is actually worse than for binary-only dependencies. If you had a dependency
that existed only in binary form, as a hackish workaround at least you could "distill" a public package JAR (akin to
what the module build harness does) and substitute that in the IDE classpath. But when there is a source association
(such as when the JAR is known to be the output of a project), you need to implement SourceForBinaryQueryImplementation
accordingly, and in that case the Java parser would completely ignore the contents of the JAR and just scan the
dependency's source tree.

Summary of request: any parser-aware features which can offer classes found in ClassPath.COMPILE or .BOOT should check
whether the classpath actually includes that class. (For example, you can use
ClassPath.Entry.includes("fully/qualified/Name.class").) If not, treat the class as missing: code completion should not
offer it, Fix Imports should not consider it, usages should be flagged as errors by the background compiler, etc.
Changes to the inclusion set (PROP_INCLUDES) should trigger a rescan of the depending project.

Note: for efficiency you could try to avoid parsing excluded packages when the depending project is opened. But it is OK
to parse them so long as they are not visibly offered, and anyway another depending project might not exclude those
Comment 2 Jesse Glick 2009-09-11 02:41:26 UTC
*** Issue 168906 has been marked as a duplicate of this issue. ***
Comment 3 Jan Lahoda 2009-09-15 19:28:52 UTC
Conceptually not so difficult, IMO, although the practical implications might be non-trivial. Especially possible
performance regressions need to be prevented. In the Java support, the support would be split into (at least) two parts,
-the parser should automatically ignore excluded classes - many features would then get the exclusion support for free,
as they solely use the parser data
-the output from the class index needs to be filtered - not sure if that could be done on the API level, or if the
individual features would need to implement the check themselves.

Also, the PROP_INCLUDES event is insufficient - it does not cover changes that happened while the IDE was not running. A
textual includes/excludes specification needs to be stored persistently in the cache and checked on start-up. This will
require an API change, IMO.
Comment 4 Jesse Glick 2009-09-16 00:33:54 UTC
Not sure if this belongs in java.source or parsing.api.

An incl/excl spec in Ant patternset format may be trivial for some clients, harder for others; the API does not assume
that the incl/excl is computed in any particular way. Are you sure this is necessary? Perhaps just persist the set of
resource paths that were actually included and thus considered whenever doing a scan of a source root (or JAR). When the
IDE is restarted and the same root is activated again, you will already be doing an up-to-date check anyway; if this
results in a different set of resource paths, you know some classes have been added or removed. In fact I would guess
the parser cache already does everything it needs to, since of course files can be added or removed during IDE shutdown
even when there are no excludes. And you already need to be doing something for excludes in ClassPath.SOURCE, right?
Comment 5 David Strupl 2009-09-16 08:56:29 UTC
*** Issue 167848 has been marked as a duplicate of this issue. ***
Comment 6 Jesse Glick 2009-09-17 15:38:35 UTC
According to issue #167848 at least part of this regressed in 6.7.
Comment 7 David Strupl 2009-09-17 15:48:45 UTC
Jan please comment and generally take over this issue from Rasta...
Comment 8 Jan Lahoda 2009-09-21 11:18:12 UTC
Issue #167848 is about excludes on source path, which where supported in 6.0-6.5, and which indeed regressed in 6.7
(fixed in current trunk, AFAIK). Not a true duplicate of this issue: as I understand this issue, it is about excludes on
compile classpath (which was/is not supported by Java infrastructure in any release so far).
Comment 9 Jan Lahoda 2009-12-12 12:01:11 UTC
I have an experimental patch for exclusion support on compile/bootclasspath here:

Comments to the current version of the patch:
-very experimental
-the apisupport.project part is a placeholder only (includes anything that has /api/ or /spi/ in path, nothing else). I probably won't be able to provide correct implementation for apisupport.project. Jesse, it would be awesome if you could provide an impl. for apisupport.project, so I could try to actually use the patch in my daily work. Thanks in advance.
-changes to include/exclude filter do not force rescan/reindex. With the current API, we would (IMO) need to store all included and excluded files used during indexing, and check whether they are still included/excluded on each start, at least. I see several problems with this: a) I currently do not know where to record the includes/excludes (CacheClassPath might be a reasonable place, but I am not sure) b) there may be very many tested files for a big project - the list of these would need to be serialized to disk, deserialized on start and passed to ClassPath.includes. This seems to me like a waste of I/O and CPU power (esp. if no exclude pattern is specified). If we could get a small string token from the SPI, that would somehow identify the exclude pattern, it could save a lot of trouble. Note that for ClassPath.SOURCE the situation is a bit different: we stat all the source files (to check the timestamp), so passing the name to CP.includes is not so big problem (would be better if CP.includes would take CharSequence instead of String, but that hopefully does make a big difference).
-I made a simple extension to the ClassPath SPI to simplify implementation of FilteringPathResourceImplementation, but that is not crucial for the changes in Java parsing infrastructure.
-the patch filters results from ClassIndex to only include the included results automatically. Parser should also only see included classes. No changes to individual features should be necessary (unless the changes in ClassIndex are proven to be too slow). Not quite sure if the filtering of getPackageNames is correct - also depends on implementations of the exclude filter.
-performance is mostly untested. I did a very quick perf. test in ClassIndex (and there was significant perf. hit only in one case, possibly GC). Needs to be tested more deeply.
Comment 10 Jesse Glick 2009-12-14 17:10:22 UTC
Would you mind if I turned the patch into a branch in the prototypes repo as per


? That would make it much easier (I think) to collaborate on its development. If you would rather not, I can try to create a separate patch for apisupport to apply on top of what you have.

Still not sure my comment #4 was answered, specifically why you need to do much work to handle changes in the set of included classes (say for COMPILE). There are three cases I can think of:

1. The entry "prefers sources" (e.g. subproject dependency). You already have some cache which I assume fixes the file stats (size & lastmod?) of all the corresponding **/*.java files. If the includes set changes, this would be no different from sources appearing or disappearing e.g. as after a VCS update - for which you would already be rescanning.

2. The entry does not prefer sources, but is an unpacked dir (probably rare). Essentially the same as #1, but you have stats for **/*.class.

3. The entry does not prefer sources and it is JAR. In this case you do need to store an extra piece of information representing the include set, but it should be of constant size and not need any SPI changes. For example, concatenate the names of all included classes and take the CRC-32; if this hash is different than when the cache was last updated, treat the JAR just like it had been rebuilt.

Perhaps you are worried that in case #3 each class name needs to be passed to the includes(...) method to compute the hash? This method should be very fast (if no special incl/excl configured, just returns true immediately), but you would need to at least read the JAR entry names, which might otherwise have been unnecessary. If this must be avoided, rather than forcing the SPI to supply an Ant patternset (which might be completely inappropriate for some impls), ask it for an opaque hash. This could be as simple as

public interface FilteringPathResourceImplementation2 extends FilteringPathResourceImplementation {
    /** hash of the algorithm used by {@link #includes} */
    long includesHash();

For the API side, ClassPath.Entry.hashCode could incorporate this hash if filter iof FPRI2, so java.source could simply use the CP.E.hC as a key into the index rather than the bare JAR URL as now.
Comment 11 Jan Lahoda 2009-12-15 08:18:56 UTC
Well, the patch queue suits better my needs, but if you prefer a branch on prototypes, I have nothing against it (I think I easily can merge the changes from prototypes to my patch queue).

Regarding the changes in the exclude pattern: I think it should work this way: consider api.progress/src and apisupport.project/src (which depends on a.prog/src). The (Java) cache for api.progress/src should contain classfiles for all Java source files defined in the source root (more precisely, for all classes/files that are included on the source path of api.progress/src). When indexing/compiling apisupport.project/src, only classes that are included on the compile classpath should be visible. When the exclude pattern changes when the IDE is shut down (e.g. the dependency is changed to implementation dependency), there is currently no process that would check whether the include/exclude pattern changed. The exclude pattern for source path of api.progress/src did not change, not timestamp changed, so no Java files "appeared/disappeared". Only the exclude pattern of the compile classpath changed, but to detect that with the current excludes API, it would mean that we would need to check whether classes in the cache of api.progress/src are included or excluded while indexing/compiling apisupport.project/src (+store the list of included/excluded classes, at least the classes that were queries while building the root). I do not think this is desirable, and would not scale well (if there would be 100 modules depending of api.progress/src, we would need to check the include property of the classfiles 100 times).

The idea with the hash would work fine, I think. I would still prefer a string token (format unspecified, could be the RE pattern for J2SE project, and simple constants like "api"/"impl" for apisupport.project), as that would improve debuggability, but that is not so critical.
Comment 12 Jesse Glick 2009-12-17 17:19:06 UTC
Created attachment 92732 [details]
Something to be qfold'ed in
Comment 13 Jan Lahoda 2009-12-18 13:55:49 UTC
Thank you very much for the patch. I have merged it into the existing patch (might make sense to eventually split the patch into three parts - api, apisupport and java). I am currently running a build with this patch, to see if it works reasonably.
Comment 14 Jesse Glick 2010-02-08 08:45:40 UTC
*** Bug 180429 has been marked as a duplicate of this bug. ***
Comment 15 markiewb 2012-12-08 12:57:22 UTC
What is the current state of this old issue? STARTED since 2009-12-14?
Comment 16 Jesse Glick 2012-12-10 15:56:55 UTC
While I initially advocated for this, I have to come to think that it is unnecessary: higher-level approaches are more flexible.

First of all, regardless of what the IDE does, your framework needs to detect private package violations and treat them as build errors, as e.g. nbm-maven-plugin does and MENFORCER-138 [1] will allow—or at least flag them in an analysis tool run after the build, such as JDepend, Lattix, or mvn dependency:analyze.

That said, the IDE’s editor ought to give you early warning of such mistakes, but merely denying the existence of the private packages is rather extreme. org.netbeans.modules.whitelist (*) lets you mark “forbidden” usages in the editor with more finesse: individual methods/fields in a type may be distinguished, overrides may be distinguished from calls (**), and most importantly a textual description can be given rather than just a blank “type not found” error. In the future this API could probably be integrated with the Java editor hints API so that detected violations could actually be resolved by:

- acknowledging the problem and deleting the import/call, perhaps replacing with an alternative where known (e.g. using Jackpot declarative hints)
- requesting friend access, in the case of a NB module (***)
- adding mandatory attributes to an OSGi import declaration (§3.7.7)
- modifying the export policies of the API module, when its source project is known
- explicitly declaring a transitive dependency, when that was the only violation (common in NB module development)
- suppressing the warning (in case the user knows better)

(*) Currently a friend API only but could be promoted.

(**) Not yet implemented but planned for in the API. Useful e.g. for OSGi projects which conventionally distinguish “provider” from “consumer” interfaces: OSGi Core 4.3 spec §3.7.3.

(***) Or in some other way requesting more access, e.g. as proposed [2].

[1] https://jira.codehaus.org/browse/MENFORCER-138
[2] http://wiki.netbeans.org/NbmPackageStability#Marking_stability_of_import
Comment 17 cappicard 2013-01-25 02:47:27 UTC
I have run into an issue involving jBoss AS 7.1.3.Final.

jboss-client.jar contains the JBoss Logging Annotation Processor, namely org.jboss.logging.processor.apt.LoggingToolsProcessor

This annotation processor interferes with NetBeans' annotation processors. 

Is there a way to exclude this class from the classpath?

I'm using this (via Additional Compiler Options) but it seems like a hack: 

-Xlint -Xlint:-serial -processor org.netbeans.modules.openide.windows.TopComponentProcessor,org.netbeans.modules.openide.util.NbBundleProcessor,org.netbeans.modules.openide.awt.ActionProcessor,org.netbeans.modules.settings.convertors.ConvertorProcessor
Comment 18 Jesse Glick 2013-01-25 18:52:39 UTC
@cappicard please use the user list. Your problem is unrelated—you just need to configure the project to not run this AP. Do not discuss more here.

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo