Using -noimport with @Export annotation

I want to use the @Export annotation in a project but BND als generates a corresponding import.

Because the OSGi Spec suggest:

“In practice, importing exported packages can only be done with clean API-implementation separation.”

So the question is how to disable this without an Export-Package header in the BND file?

Well, read the documentation of the @Export :slight_smile: (I always love it when I can say this!)

The @Export annotation has a substitution method. There you can set the rules for the substitution: CONSUMER, PRODUCER, NOIMPORT, and CALCULATED. The last one is the default and bnd does a good job of that.

So you can do:

@Export(substitution=Substitution.NOIMPORT)

That said, it is in all cases I am aware of not good practice. The bnd calculation is very good and there are very few cases where you need to override it. Package substitution is one of the cornerstones of OSGi.

I’d be interested to know why you need this.

I’m glad I can make you happy :slight_smile:

It is a bit unclear what this means and I assumed I can somehow influence it by a setting, e.g. how do BND calculates “clean API-implementation separation” (I can tell for my example it is most likely NOT clean separation…) from experiments with that is that BND simply always exports the package, and I like to disable this instead of hard coding this on every export annotation and more explicitly enable it on demand :sweat_smile:

That’s something state here and there but for > 10 years I never found any real use for it except for the case where an bundle also includes foreign(!) API packages (that is something I generally avoid), so the question is more why should I ever want this?

  1. bnd will not import the package if this would become unsafe or there is no need to. A pure API that is not referenced inside the bundle will, for example, not be imported
  2. Packages are imported with different ranges based on their consumer/provider role. There is quite a lot of theory behind this.

It gives the runtime more leeway to wire up bundles. If you do not allow this you increase the number of times you get unresolveable systems and/or multiple class spaces in the runtime. You just make the runtime much more complex by removing many compatible constellations.

It is of course your choice, but unless you got very messy packages and you know exactly what you’re doing, I think you just safe yourself a lot of misery using calculate :slight_smile:

I am curious, did you experience actual problems with this or just suspicious it might not work? :slight_smile:

Anyway, you can also control the exports with the Export-Package instruction in the bnd file, you can then add the -noimport:=true directive and use wildcards but that will probably not work very well with the @Export annotation. I do not think there is a global flag for this and a I can’t find it with a quick search. Since the default CALCULATE works so well, I guess there never was a need for such control.

But it also gives harder times to debug things, and I suspect most of the time no one really will use substitution packages, e.g. just the usual “add OSGi headers to this library please” no one will really ever want to provide an alternative package variant.

Yep that’s why I wanted to to switch to @Export annotation

It depends on what what one qualifies as an “issue”, from a technical POV this all will work but:

  1. If I add OSGi metadata to a library, I most often try to find the smallest possible increment, that is, the less I add compared to the current library state, the more likely it is that my change will be accepted by a maintainer knowing not much about OSGi
  2. Enabling features (here package substitution) for there is no real need (e.g most of the time no one really likes to substitute anything) always have the risk of adding complexity or maybe side-effects hard to understand, so less features are generally better in terms of maintaining by a non OSGi-Expert

So these are more soft-facts than hard technical issues, but often it is better to have less sophisticated support than full-fledged support that makes people feel it is “to complex” for a library that is not primarily used in OSGi and maintained by people with zero knowledge about all the fancy stuff from OSGi.

Well, it is up to you but imho not using the defaults will cause more pain in the long run than you trying to be cleverer than bnd and its 23 year history in these matters. But you won’t be the first one if that comforts you :slight_smile:

Just found this discussion here after hanging around here and learning how stuff actually works.

And I discovered the prescious -noimport:=true

My initial reaction was like "Why is -noimport:=true not the default? Like perspective of @laeubi in Using -noimport with @Export annotation - #5 by laeubi

What about we promote the more prominently to use something like -noimport:=true on the Exports when “just” adding OSGi meta data?

-exportcontents: *;-noimport:=true

This would reflect the default-behavior which is expected by @laeubi , the github issue and myself somehow (throwing in a buzzword*: principle of least surprise*). Then the substitution use-case could be documented as an alternative.

Given that the default behavior won’t change (that is what I took from discussion and github) I would like to ask

  1. how we could do a better job of documenting it?
  2. and maybe give better advice to library authors who just want to add OSGi metadata, but do not have OSGi knowledge?

A real life example of the pain it causes is the origin github Issues with 2024-06 and gson library used by lsp4j v0.22 · Issue #3236 · eclipse-jdtls/eclipse.jdt.ls · GitHub

The problem, as you’ve noted, is that both gson bundles import just “com.google.gson.annotations” (implied >= 0.0.0) leaving the door open for resolution between different versions of the same library :neutral_face: gson 2.10.1 should import with a range of [2.10.1,2.11.0) and gson 2.11.0 should import with a range of [2.11.0,2.12.0) to be safe.

com.google.gson_2.10.1.jar
Import-Package = sun.misc;resolution:=optional,com.google.gson.annotations;version="[2.10.1,2.11.0)"

com.google.gson_2.11.0.jar
Import-Package = sun.misc;resolution:=optional,com.google.gson.annotations;version="[2.11.0,2.12.0)"

This problem resulted in multiple other github issues in different projects (gson, bnd, eclipse…) and seems to be a real-world issue only a few people are able to debug.
This makes me think “What could we do about it?”

I am willing to contribute documentation but not sure if and where to start. So feedback is welcome.

As a starting point

I see the following docs pages:

Adding a comment from 183595 – org.w3c.css.sac seems to import and export the same thing which has statement by Thomas Watson:

As a general rule I do not see a need to have “library” bundles, like the ones in orbit, export AND import the packages they provide as API. If you don’t want multiple exports of a package available then you should not install multiple versions of that bundle.

As a best practice I would recommend that library bundles do not import the packages they export. Bundles should only import a package if they are willing to get that package from an unknown source and omit their own export from the framework. I don’t think orbit bundles fall into this catagory.

IMHO it supports the sentiment of @laeubi

Question: Could this be a recommendation to library-authors using bnd / bndtools too in our documentation? (hand in hand with -noimport:=true on Exports)

I think we should because:

  • most libraries out there could be considered API (somehow)
  • they are usually no OSGi-aware, meaning they never expect substitution use-cases (quote:

Bundles should only import a package if they are willing to get that package from an unknown source and omit their own export from the framework.

)

I would claim only end-products build on OSGi (talking AEM, Liveray) have the OSGi-knowledge and could want to have advanced package substitution use-cases.

For anybody coming here:
There have been two recent additions to bnd (to be released with upcoming 7.1. and currently in SNAPSHOT) related to this topic:

  1. Remove imports of exports without a version range by chrisrueger · Pull Request #6270 · bndtools/bnd · GitHub
  2. RepoView: Add to Clipboard: Bundles with substitution packages / self-imports by chrisrueger · Pull Request #6263 · bndtools/bnd · GitHub

Both of them should help to improve the situation. 1. removes imports (from exports) without a version (would help in the gson case) and 2. helps to identify bundles in a bnd repository which have unversioned imports (from exports), so that e.g. a fix/PR could be provided to the upstream project e.g. by helping them upgrade to latest bnd gradle/maven pluging which uses bnd 7.1.x or by adding the -noimport:true)

1 Like