SLF4J / SLF4J-586 [Open]
MANIFEST.MF exports a package with a former version number

==============================

Here's what changed in this issue in the last few minutes.


There is 1 comment.


View or comment on issue using this link
https://jira.qos.ch/browse/SLF4J-586

==============================
 1 comment
------------------------------

Hannes Wellmann on 29/Mar/23 20:15

TL;DR: It looks like org.ops4j.pax.logging.pax-logging-api is to blame for the 
problems you encountered because they have incorrect OSGi metadata.


> >... it depends how 'greedy' the resolver of your OSGi runtime

> To my knowledge, there are only two OSGi runtimes implementation: Apache 
> Felix and Eclipse Equinox, so it should be tested in both environments.

According to Wikipedia there are more, but the ones you mentioned are probably 
the most relevant ones (AFAIK). Nevertheless even in Equinox we use the Felix 
Resolver: 
https://github.com/eclipse-equinox/equinox/tree/master/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver


Thank you @frederic.fays for the details.

In order to verify that from slf4j side everything works as expected I created 
a little Eclipse application (using the Equinox OSGi framework) which, besides 
the basics for the Eclipse Platform and lockback 1.2 and 1.3 
bindings/providers, has mainly two Bundles A and B with the following 
MANIFEST.MF files:
{code:java}
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: bundle.a
Bundle-Version: 1.0.0.qualifier
Import-Package: org.slf4j;version="[1.7.0,2.0.0)"{code}
 
{code:java}
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: bundle.b
Bundle-Version: 1.0.0.qualifier
Import-Package:
 org.slf4j;version="[1.7.0,2.0.0)",
 org.slf4j.spi;version="[1.7.0,2.0.0)" {code}
 

Within the launched application I used the Felix GoGo Shell to analyse the 
resulting wiring within the Framework:

 
{code:java}
g! p org.slf4j
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; 
bundle-version:Version="2.0.7"; version:Version="1.7.36"; 
osgi.wiring.package="org.slf4j"; 
uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi"<slf4j.api_2.0.7 [319]>
  bundle.a_1.0.0.qualifier [4] imports
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; 
bundle-version:Version="1.7.36"; version:Version="1.7.36"; 
osgi.wiring.package="org.slf4j"<slf4j.api_1.7.36 [320]>
  bundle.b_1.0.0.qualifier [5] imports
  ch.qos.logback.classic_1.2.12 [7] imports
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; 
bundle-version:Version="2.0.7"; version:Version="2.0.7"; 
osgi.wiring.package="org.slf4j"; 
uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi"<slf4j.api_2.0.7 [319]>
  ch.qos.logback.classic_1.3.6 [6] imports
  org.apache.httpcomponents.client5.httpclient5_5.1.3.v20221013-1742 [45] 
imports
  org.eclipse.jetty.util_10.0.13 [206] imports
  ...
{code}
 


This shows that Bundle A, which only imports the package {{org.slf4j}} below 2, 
is wired to the {{org.slf4j}} package from bundle {{slf4j.api}} version 2, 
while Bundle B, which imports {{org.slf4j}} and {{org.slf4j.spi}} below version 
2, is wired to the {{org.slf4j}} package from the {{slf4j.api}} bundle in 
version 1.7.
So in this case, when only the official {{slf4j.api}} bundle is used, 
everything works fine as expected and intended.

Good for me, but the question remains why it does not work for you and after 
looking into the Manifest.MF in the jar of pax-logging-api:2.2.2 I noticed the 
following Export-Package entry:
{code:java}
Export-Package:
 
org.slf4j;version="2.0.6";provider=paxlogging;uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi",
 org.slf4j;version="1.7.36";provider=paxlogging,
 org.slf4j;version="1.6.6";provider=paxlogging,
 org.slf4j;version="1.5.11";provider=paxlogging,
 org.slf4j;version="1.4.3";provider=paxlogging,
 org.slf4j.event;version="1.7.36";provider=paxlogging,
 
org.slf4j.event;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.helpers",
 org.slf4j.helpers;version="1.7.36";provider=paxlogging,
 org.slf4j.helpers;version="1.6.6";provider=paxlogging,
 org.slf4j.helpers;version="1.5.11";provider=paxlogging,
 org.slf4j.helpers;version="1.4.3";provider=paxlogging,
 
org.slf4j.helpers;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.event,org.slf4j.spi",
 org.slf4j.spi;version="1.7.36";provider=paxlogging,
 org.slf4j.spi;version="1.6.6";provider=paxlogging,
 org.slf4j.spi;version="1.5.11";provider=paxlogging,
 org.slf4j.spi;version="1.4.3";provider=paxlogging,
 
org.slf4j.spi;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.event,org.slf4j.helpers",
 ...{code}
 

It looks like pax-logging-api is doing something similar like slf4j-api, but 
the metadata are incorrect respectively insufficient. First of all as we have 
discussed in SLF4J-579 only the package org.slf4j is backwards compatible. So 
given that the embedded class files are shaded/copied from slf4j.api 2.0.6, 
exporting org.slf4j.event/helpers/event in any version below 2 is wrong, since 
some classes/methods are binary incompatible. This is the reason, why the 
slf4j.api bundles does not export them and I think that is the root of the 
problem here.
In general it is not a problem in OSGi to re-bundle packages from other 
Bundles/Plugins as long as all packages are versioned correctly (following 
SemVer rules) have uses-constriaints and consumers only use Import-Package and 
not Require-Bundle. Then the actual bundle is just an exchangeable hull (which 
is even one design-goal of the Import/Export-Package mechanism if not OSGi). To 
quote a stackoverflow answer 
([https://stackoverflow.com/a/7476016):|https://stackoverflow.com/a/7476016)]
{code:java}
An OSGi application will not throw ClassNotFoundExceptions and 
NoClassDefFoundErrors if your manifest is correct. That is, you need to tell 
OSGi which packages your bundle uses; if you don't do this correctly or 
honestly, then OSGi cannot help you. In other words: GIGO (Garbage In, Garbage 
Out).{code}
And in my opinion at least the metadata of pax-logging-api are wrong.

However after skimming over your linked issue, 
[https://github.com/ops4j/org.ops4j.pax.logging/issues/518] respectively 
[https://github.com/ops4j/org.ops4j.pax.logging/issues/519] it looks like the 
pax-logging devs are aware of what they are doing and they are doing it on 
purpose and since I believe they are reasonable people they probably do it for 
a reason. I'm not familiar with the exact Karaf/Pax/Container environment and 
did read the discussion in detail and therefore cannot assess their decision. 
But my naive first attempt would be, instead of shading/repacking the api 
classes from all supported facades into a own bundle, use the original 
(multiple) api bundles and provide a custom logging 
implementation/binding/provider that is wired to all the facades and does the 
redirection magic to whatever target or other logging-backend is intended. 
Basically just like all the other logging-backends and bridges work. But 
probably the pax-logging devs have considered that as well and had a reason to 
not do that.

So to solve your issue I suggest you do what was suggested in 
[https://github.com/ops4j/org.ops4j.pax.logging/issues/518#issuecomment-1488132088]
 and simply not include the slf4j.api in your application. As far as I 
understand it, in your scenario it is not wanted any way and the 
pax-logging-api is intended as replacement for the slf4j.api bundle.

Nevertheless I'm still not sure if that would change something for you, because 
with the latest pax-logging-api:2.2.2 you have a bundle that exports the 
{{org.slf4j}} package in multiple versions above and below two too and even the 
other {{org.slf4j.X}} packages in multiple versions. So even without slf4j.api, 
you would be in a similar scenario. Sorry, that is probably frustrating for you.
Can you try the pax-logging 2.2.2 api and logback with slf4j.api 2.0.5? Version 
2.0.5 export the package org.slf4j package only in version 2.0.x.
If you have a Felix GoGo shell in your app, it would probably also be 
interesting to see the OSGi wires of the org.slf4j package. You can use the 
command I used above ({{{}g! p org.slf4j{}}}). Maybe the karaf runtime has 
something similar built in.

But again, I'm convinced that the slf4j.api metadata are correct and work as 
intended as shown above and that you face the problems because of the 
specialities of pax-logging.


==============================
 This message was sent by Atlassian Jira (v9.6.0#960000-sha1:a3ee8af)

_______________________________________________
slf4j-dev mailing list
slf4j-dev@qos.ch
https://mailman.qos.ch/cgi-bin/mailman/listinfo/slf4j-dev

Reply via email to