Why does bnd add a uses directive for a package used only within a method body?
Asked Answered
A

2

8

I have a project with a single source file, listed here in its entirety:

package com.acme.el;

public class ExpressionUtils {
    public static Object evaluate() {
        new org.apache.commons.el.ExpressionEvaluatorImpl();
        return null;
    }
}

The functionality is irrelevant to the question. When I build the project as an OSGi bundle using Gradle, the manifest contains the following instruction:

Export-Package: com.acme.el;uses:="org.apache.commons.el";version="1.0"

What baffles me is that uses directive. As I've understood the directive, it is meant to define dependencies on other packages that need to be propagated to other bundles importing this exported package - if my class definitions or method signatures refer to classes in the org.apache.commons.el package, for instance. But in this class, the dependency on org.apache.commons.el is completely contained within the body of a method. It is not exposed in the API, and no other bundle importing com.acme.el could ever get a hold of the ExpressionEvaluatorImpl instance created in the method. So the dependency shouldn't need to be propagated, right?

Did I misunderstand the meaning of the uses directive, or is its use here unnecessary?

I made a minimal example GitHub repo for reproduction which you can clone and import as a Gradle project in Eclipse.

Ayo answered 2/7, 2013 at 9:20 Comment(6)
I've read section 3.7.5 Package Constraints of the OSGi spec v4.3.0, but it didn't make me much wiser on this. This is all that is said about when to use the uses directive, the rest discusses how the framework should handle these directives: [...] For example, when they extend classes from another package, or these other classes appear in method signatures. It can therefore be said that a package uses other packages. These inter-package dependencies are modeled with the uses directive on the Export-Package header.Ayo
Your understanding of the "uses" constraint is correct, so it's not clear to me why the constraint is being generated by bnd in this case. If you're absolutely sure there are no other references to the package elsewhere, then you may have found a bug; please report it at github.com/bndtools/bnd/issuesEpidemiology
Yes, I'm absolutely sure - I created a minimal example containing only that one class listed in the question, which you can see for yourself at the linked GitHub repo. :)Ayo
Yes I see that now. Thank you. Please reference this github project in your bug report.Epidemiology
I'm not completely sure this is not an issue with the BND-Gradle integration, though. The docs for the OSGi plugin for Gradle only says "The OSGi plugin makes heavy use of Peter Kriens BND tool."...Ayo
Bug reported: github.com/bndtools/bnd/issues/371Ayo
J
10

If, in your bnd file, you set -experiments: true you should get the proper uses: clause, only based on public API references.

The problem is that bnd from the beginning has used all the imports to calculate the uses constraints. This was by far the easiest and nobody, so far, has ever complained about it. However, I did create the code to scan the public API but never felt confident enough to remove it from the experimental phase ... The current model is creating too many uses constraints but that should in general be the safe way.

This code has not been tested enough nor do I feel confident that changing this calculation will not create problems in existing builds. So I am in a bit of a bind here.

Jointer answered 2/7, 2013 at 12:27 Comment(8)
Yeah, I understand it must be much more difficult to do. I'm currently trying to port a 10+ years old enterprise war to OSGi, and there are some legacy dependencies causing conflicts when propagated. I suspect this isn't quite as much a problem if your projects depend on non-discontinued libraries etc. ;DAyo
Any idea off the top of your head how I might enable that flag in a Gradle build? I'll look through the bnd documentation, of course, but if you already know it would be a shame not to share the knowledge, right? :)Ayo
I do not know how gradle uses bnd ... but in maven you would do <_experiments>true</_experiments>. I assume gradle has a similar model for translating bnd's instructions/macros?Jointer
I don't know, I started using Gradle and OSGi a week or two ago, and I haven't needed to work with bnd directly until today. Oh well, I'll probably figure it out sooner or later. I tried running the bnd jar from your CI server on the test project linked above, but even without -experiments: true the output jar didn't have the offending uses clause. I suppose I didn't use it right - it didn't automatically export all packages if I didn't explicitly state Export-Package: *, for instance. Anyhow, this issue isn't highest on my priority list right now, so I might come back to it later.Ayo
The OSGi chapter of the Gradle user guide shows how to set bnd instructions.Builtup
@PeterNiederwieser it shows how to set instructions for adding manifest headers, but not other bnd instructions. I tried with instruction '-source', 'true', for instance, and nothing happened. I also tried 'source' and '_source', and that didn't work either. I suppose there might not be a way to pass this kind of bnd instructions through Gradle at this time - both Gradle and, unless I'm mistaken, the OSGi plugin are very young, after all.Ayo
@PeterKriens I tried again and found that specifying instruction '-nouses', 'true' in Gradle works, causing the generated manifest to not have any uses clauses. However, instruction '-experiments', 'true' has no effect, and all imported packages (except those beginning with "java.") appear in the uses clause. I took a look at the BND source code. It seems the only row where the EXPERIMENTS constant is used is here, and it doesn't look to me like it does anything.Ayo
Seems like the 'experimental' mode has been made default in bnd version 2.1.0 (maybe earlier) - the problem no longer occurs in Gradle 1.7! :DAyo
A
1

Gradle 1.7 uses bnd 2.1.0, instead of bnd 1.50.0 which is used by earlier Gradle distributions. This problem does not occur when using Gradle 1.7, as demonstrated by this GitHub repo.

Ayo answered 5/9, 2013 at 11:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.