-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to find implementation classes in OSGi #578
Comments
@cziegeler thanks for the issue - I really appreciate it. Some questions: Did this problem happen to you when using 0.10.x or earlier? Could it be that we're not exporting the OSGi metadata correctly? This is the only thing we have for maintaining OSGi bundle data: Lines 485 to 503 in c09deaa
(This is in Thoughts? cc @bdemers |
Hi @cziegeler! |
@lhazlewood Yes, this happended with the 10.x version as well; but I only tested with the latest 10.x release. |
Just some more information: the first official release supporting OSGi is 0.11.0 (which has the same problem). |
I've also created a simple sample project which currently references 0.12.0-SNAPSHOT and can be used to reproduce the problem: jjwt-test |
Thanks @cziegeler! It’s a little older at this point, but any thoughts on that technique? |
@bdemers There are currently two problems - first one is that the API bundle is not finding the classes from the implementation bundle using class loading, second one is that the API bundle is not finding services from the implementation or extension bundles when service loader is used. |
@bdemers / @lhazlewood Any chance to get that patch applied? Today it's impossible to use these libraries out of the box in OSGi; with the patch this is finally doable |
Good day to all! For version 0.11.1 in OSGi environment (on the example Karaf 4.2.8) got a similar problem. I use instructions So I switched to another dependency: |
Right, we use a similar repackaging solution at the moment as well - which is basically taking all the different libraries (api, impl, serializer) and putting them in a single jar. With the proposed patch this extra work downstream can be avoided |
I don't think that |
@hlavki what would you recommend instead? I also wouldn’t say separating the interfaces from the implementation packaging is a bad practice. It’s commonly found in many libraries. IIRC OSGi has build in support for this, but the vanilla Java/Android world doesn’t, and mechanisms like ServiceLoader are used. |
Of course, I am not talking about API/Impl separation. It's generally good approach used almost everywhere. And yes, OSGi supports it too. public static JwtBuilder builder() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder");
} vs. e.g. jackson's module system: return new ObjectMapper()
.registerModule(new JavaTimeModule()); You can have DefaultJwtBuilder that implements JwtBuilder interface, but you don't need to instantiate it using java reflection API and also you don't need separated jar file. |
Hello, I am having this exact same issue with version 0.11.2. Was this fix included in 0.11.2? |
@lexsoto it was. Can you tell us about your environment and classloader? (and which jars do you have on your classpath?) |
Thanks, @bdemers, It is not working for me with Karaf 4.2.9, unless I specify the Serializer explicitly, as in:
|
@lexsoto can you include your stacktrace, and the list of JJWT modules that you are using? |
@lexsoto It works for me with the JacksonSerializer if I include these bundles: (Not testing in Karaf though, but that shouldn't be a difference) |
These are the bundles I am loading (Karaf 4.2.9):
I am also seeing this other variation of the same issue, but during validation:
|
Even when I tried to provide my own Compression Codec Resolver it would fail.
But it is of no use when class
Here is the relevant stack trace:
It would be nice if the https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html |
@lexsoto that seems reasonable, we do something similar with the Any chance you want to try to hack it up and see if it works for you? |
I worked around the problem by doing this: 1- Shade the Json Web Token libraries:
2- Avoid importing JSON Web packages in the bundle headers because it is all now in your own Uber Jar.
3- Add bundle header to be able to find Json serializers (in my case Jackson):
4- Add bundle headers to automatically register services (CompressionCodec, Serializer, and Deserializer):
5- Create OSGi friendly Compression Codec Resolver:
6- Put it all together in your client OSGi component:
Not exactly simple but it works, avoiding the Service Lookup and using OSGi lookup instead. Now, I think the shading can be removed if |
…wtParserBuilder This removes a potential service loader issue with OSGi runtimes. Fixes: #578
@lexsoto can you take a look at #611 and see if that makes your life any easier? I'm not a regular OSGi user, is there something better we can do in our ServiceLoader logic to make it play better with OSGi environments? Do OSGi runtimes ignore the ServiceLoader metadata? If we defined a |
Above @lexsoto referenced this: https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html That article indicates how, via metadata only ( Since we control both the 'provider' .jars (the Jackson, Gson, etc implementations) and the 'consumer' jar (the @lexsoto and @cziegeler - would either of you be able to help us set up Karaf in an Unless we have an automated repeatable solution, this problem is likely to surface repeatedly. |
Metadata will definitely help, but the code change in #611 is necessary, in my opinion, since without it, the logic loading the services is executed eagerly, even when our intent is to provide our own Compression Codec Resolver; besides, I don't think that change affects non OSGi users either. The referenced article explains the nuances with service loader and class loaders, but I am afraid the issue I encountered is more related to the use of Fragment Bundles. I am not sure fragment bundles are the best choice here, regular bundles with the metadata to let the OSGi framework register the services automatically would be cleaner IMO. Providing an OsgiCompressionCodecResolver, like the one I pasted before would be nice as well. About providing IT, I could set something up, but I am not very familiar with this project and how to contribute, etc. but I could do it in my repo and you guys can take it from there. |
That is a great starting point! |
I agree, this is necessary (to load lazily), but it doesn't address the underlying issue that discovery is not working in an OSGi environment:
My point was that if we got the MANIFEST.MF records correct per the blog article, you shouldn't need to have an
That would be so helpful! We'd really appreciate it 😅 What I think we're hoping for is something that sets up Karaf in an |
Reopening - 901048a was only part of the solution. |
Thanks @lhazlewood! I forgot that that linked PR would close the issue automatically |
@bdemers Regarding your question about "module-info" , apart from the Java 9+ problem, it wouldn't help as OSGi is not using these things out of the box. |
@cziegeler Is the needed metadata something we can just add to: https://github.com/jwtk/jjwt/blob/master/impl/bnd.bnd |
I worked on an integration test for this using Karaf, you can find it here: https://github.com/lexsoto/jwt-karaf-itest Feel free to copy and adapt. A funny thing happened, though, and it is that I expected to fail, but it is working! |
@lexsoto no worries! Your project might have more complex classloading, which is what we would like make sure we capture in the test. Keep us posted! |
Finally I was able to reproduce the error with a minimal project. Please check: https://github.com/lexsoto/jwt-karaf-itest This is new version is a multi module project. The issue shows up when invoking from a Servlet. See servlet in the client subproject. I hope this helps in solving this issue. Thanks! |
Great! |
I am not sure how to, but it may be possible; however, I suspect it may be more related to threads, because when I tried different bundles (each has its own class loader), I could not reproduce; only when JJWT is invoked in the context of a Servlet (which runs in a web server thread (Jetty) is when I was able to reproduce. |
This issue has been automatically marked as stale due to inactivity for 60 or more days. It will be closed in 7 days if no further activity occurs. |
Closed due to inactivity. |
This issue has been automatically marked as stale due to inactivity for 60 or more days. It will be closed in 7 days if no further activity occurs. |
Closed due to inactivity. |
At least since the removal of the service loader for loading implementations, the library does not work in OSGi anymore. The reason is that the api bundle does not have access to classes from the impl bundle as class loading across bundles only works if those classes are exported (and imported).
I'm not sure how to solve this; clearly it would be wrong to export implementation classes and import them in the api.
Creating a single bundle with api and impl would work, with the expense of creating another artifact.
This is the exception I get with latest 0.11.1 :
io.jsonwebtoken.lang.UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.DefaultJwtBuilder] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found. Have you remembered to include the jjwt-impl.jar in your runtime classpath?
at io.jsonwebtoken.lang.Classes.forName(Classes.java:92)
at io.jsonwebtoken.lang.Classes.newInstance(Classes.java:136)
at io.jsonwebtoken.Jwts.builder(Jwts.java:141)
at de.osoco.cziegeler.test.jjwt.Test.start(Test.java:12)
The text was updated successfully, but these errors were encountered: