Find out dependencies for a any .jar bundle - java

I am developing OSGi bundles using Eclipse. I test the code, using an Eclipse OSGi runtime configuration.
The code works fine there, but when I export the bundles as jars and try to use them in another environment (pax-runner, for instance) I get ClassNotFound exceptions at runtime. The bundles are installed fine, with no errors. I execute the command on equinox: "diag bundle-number" and it says: "No unresolved constraints" for every bundle.
I would like to know if there is a tool/method to know, for a given .jar bundle if it needs any external library, which is not described in the manifest.mf.

Your bundle will resolve if all the packages listed in Import-Package (and the bundles listed in Require-Bundle) are found at runtime. If you get ClassNotFoundException or NoClassDefFoundError after resolving, it means that the content of Import-Package was wrong.
Take a look at the Bnd tool by Peter Kriens. This performs static inspection of the bytecode compiled from your classes to discover the exact dependencies, and it generates the Import-Package statement for you. In general if you use Bnd, you should never see ClassNotFound/NoClassDefFound unless dynamically load classes by name, e.g. with Class.forName().

JBoss has just release a fantastic Open Source diagnostic tool about dependencies : http://jboss.org/tattletale
One of the features is to analyse the jar files by introspection, to find all lacking dependencies.

I've done something like this a while back (I was cross compiling Java to .NET via IKVM, but needed the dependencies between Jars) I used JarAnalyzer to create a graph of dependencies.

I've had success with SpringSource's bundlor-shell tool. There are instructions for using it here. You give it a JAR, along with a name and version for the new bundle you want to create from that JAR. It then analyses the class files inside the JAR and produces a template manifest that imports any packages it finds references to.
The hard part is then working out which dependencies are optional, and what version of each package to depend on. You have to read the web site, release notes, etc. for the library to figure this out.
You will get "No unresolved constraints" if the bundle doesn't actually import any packages or require other bundles; as far as the OSGi runtime is concerned, the bundle will be usable. But as soon as it accesses an external class, as in your case, you'll get the dreaded ClassNotFoundException.

The Eclipse Plug-In Development environment (PDE) will give you compile errors if your code uses classes which aren't listed in the MANIFEST.MF. ClassNotFound exceptions at runtime are often caused by incorrectly marking package imports as optional - the bundles resolve, but they won't work. Compiling against a different version of a bundle or package than you're running against could also cause this kind of error.

Related

Java Gradle Missing libraries Modue that exists or have been imported - > Task :compileJava

So I have been facing these issues in so many JavaFX Gradle based projects in Intelli J Idea IDE. This has pushed me to the point where I had to manually download library files and make them part of my projects as a workaround.
The gradle projects I have they keeping failing when ever i run the > Task :compileJava in the IDE, for example in this particular that made me create the issue is that i have successfully imported the socket io lib from maven implementation 'io.socket:socket.io-client:2.0.1' , i have managed to import it and write a bit of sample code for it and i have added
requires engine.io.client;
requires socket.io.client;
in the module info file . So when its time to run this fails stating that
error: module not found: socket.io.client
requires socket.io.client;
error: module not found: engine.io.client
requires engine.io.client;
I have tried on JDK 13,16,17 to see if I am missing something but keeps on failing to run , so I have noticed now as a trend in my previous JavaFX project in which i managed to get away with.
So if there is anyone who understands what's wrong with Gradle set up please help.
This answer outlines an approach rather than a concrete solution.
socket.io.client and engine.io.client are not module names.
The socket.io-client library is not Java platform modularized (as far as I can tell), so it will be an automatic module.
The name of the module will be derived from the jar name. I don't know the exact translation as the jar name has . and - characters which may be remapped (or not) to make the module name valid. Try first the exact jar file name. There can be only one module per jar.
Additionally to requiring the right name, the jar needs to be on the module path. Maven will do this automatically for automatic modules, Gradle will not. I am not a Gradle expert, so will not provide advice on how to do that for Gradle.
If you use the right name in module-info and ensure the jar is on the module path, then it may work, or it may be incompatible with the Java module system in ways that are not easily fixable by you (i.e. the broken module must be fixed by the module maintainers).
You can raise an issue for the library maintainer for them to create module-info.java files for the modules and update their documentation on how to use their libraries in a Java module environment.
If the library you are trying to use is incompatible with the Java module system when used as a module, then you could try making your project non-modular by deleting module-info.java from your project and adding appropriate command-line switches. To understand how to do this, refer to documentation on non-modular projects at openjfx.io.

Classloader to isolate a jar (class identity crisis)

I'm using jarX that has embedded dependencies that conflict with my own dependencies, so I'm creating a classloader to isolate jarX's dependencies from my main classloader.
jarX is outside my app's classpath, but my classes that use jarX's classes are in my classpath, so when I instantiate my classes loaded via the custom classloader, I run into the class identity crisis in the form of ClassCastException as the JVM's version of my classes are considered different from those loaded by my custom classloader.
I found this blog post where they solved a similar problem by only interacting with the custom classloader loaded classes via reflection, which seems to solve this problem.
It just feels like it should be easier than this. Does anyone know a better way to handle this problem?
The easiest way is to open jarX, remove the offending classes, and done. It is a bad practice to embed dependencies in a JAR unless that is JAR is meant to be used only as a standalone runnable fat-jar. JARs that are meant to be used as libraries should not embed dependencies.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
Can you post which jar is it and what are the classes that it overlaps, with the full stacktrace? Have a look at this tool I wrote to generate a list of duplicate classes in the WAR, there is an option to exclude duplicates of the same size.
These are some measures that can be done to solve this:
Try to reduce the number of duplicates by doing a case by case analysis of why the overlap exists. Add maven exclusions for jars that are complete duplicates.
Check if there is a version of the same jar without the dependencies that you could use, which jar is it, xerces, etc?
If there is no jar without dependencies, you can you exclude the other jar that overlaps jarX and see if the application still works. This means all components that need the jar have a compatible version of the jarX library
Separate the application into two WARs each with the version of the library you need. This will reduce the number of libraries in which
These where measures that are likelly to be more maintainable long-term
If the previous measures do not work:
open the jar, delete the duplicate classes and publish in the maven repository with a different name jarX-patched
you can configure nexus to serve a patched jar instead of an unpatched jar transparently
If your container supports OSGI that would be even better, but if you don't use a OSGI container for development as well, then the application would not work in development.

How to package a library as an eclipse plugin for use by another plugin

I'm trying to build an Eclipse plugin that depends on a library which has to be distributed separate to it. The reasons for that are:
It's a commercial library, while the plugin will be distributed freely. Also, most people won't need it and we don't want to confuse users.
There are currently at least two versions of the library in use and we don't want to build two different versions of the plugin. The interface is compatible, so we can ship just one version of the plugin.
The plugin is for an Eclipse-based development environment and the purpose is to provide our library's functionality within that environment. The library itself depends on other free components, which I can bundle with it without a problem.
Since I don't know if I'm allowed to say exactly which library it is, but I must keep this unambiguous, let's call the library "L" and the plugin I'm trying to develop "P".
I'm using the bnd tool for this and so far I've tried both packaging L as a standalone plugin, and as a plugin fragment.
As a standalone plugin, it was accepted by the host eclipse environment and I could list it as a dependency of P and successfully build that. However, at runtime the P plugin didn't see resources from the L library on its classpath. Mainly those in META-INF/services are needed.
Next, I tried packaging L as a plugin fragment for P. I hoped this would work, since the specs say, that a fragment's classpath is merged with its host plugin's. This didn't work, because I couldn't use the classes from L as build dependencies of P - putting L in eclipse's plugins directory didn't result in it being recognised as an installed plugin.
So I'm stuck. I need L's jars as part of P's runtime and build classpath, while at the same time having them in a separate plugin. Is what I'm trying to do even possible?
For P to have visibility of L's resources, L must export the containing folders as 'packages' and P must import them. This looks a bit inelegant but does allow folders like META-INF/services to be on P's classpath.
Alternatively, for META-INF/services in particular, you could look at new function in release 5 of the Enterprise OSGi spec in the area of ServiceLoaders. A good blog explaining the idea is http://coderthoughts.blogspot.co.uk/2011/08/javautilserviceloader-in-osgi.html, and Apache Aries has an early implementation.
Eclipse plug-in dependencies on other plugins can be defined as Optional. If the user does not have it you can use Class.forName to check if the dependent class has been loaded.
Apparently you didn't list the 'library' plugin as an OSGI import of the 'main' plugin. Without seeing your manifests it's impossible to tell for sure.
As per my understanding,You want to add Jar as plugin dependency.
The best way to do so Go to Plugin View--> Copy your jar file to plugin directory -->Import it as a source project in your workspace.
Plugin.xml-->dependency tab-->add it as a dependency.
If you want to package it in the plugin,use dynamic library loading mechanism.

Why make my project an OSGI bundle as opposed to a standard JAR package?

For what reasons would I want to make my project an OSGI bundle as opposed to just a standard JAR package? Does it only make sense if it is going to be used by an application that uses an OSGI framework (eg: Equinox/Eclipse)? Or is it also useful from a development point of view, ie: being able to easily reuse my OSGI bundle by other projects during Eclipse development?
OSGi provides support for modules, you could control the dependencies. Each module may include and exclude packages from other bundles. You can also replace bundles during runtime. Making a whole project a single bundle has none of these benefits. I would only wrap a jar like a jdbc driver as bundle if it is not available as an OSGi bundle.
First check whether your project would have a benefit. Then identify which modules should be a bundle.
If your project is a public or open source library, then please do make it an OSGi bundle. This will be of great help to OSGi developers who may want to use your library.
On the other hand if your library is private then the benefits of OSGifying it are limited. Mostly it will be an advantage if you decide to adopt OSGi strategically later. You may also derive some benefit from the explicit dependencies, i.e. you can look into the bundle to work out exactly what it depends on.
There is no runtime cost of doing this. The OSGi data in the manifest is simply ignored by non-OSGi runtimes.
You will have to generate the OSGi manifest though as part of your build step. The best tool to use for this is Bnd, which can be easily integrated into any ANT build -- use it as a replacement for the "JAR" task. If you are building with Maven, then use the Maven Bundle Plugin (which uses Bnd internally).
This is useful only if it's going to be used from within an OSGi container as you mentioned.
If you are searching an answer on why it is useful in general is something you can find a lot just by googling - start from Wikipedia:
http://en.wikipedia.org/wiki/OSGi
In general, I'd say OSGi's main benefits are encapsulation/versioning, solving JAR hell and management provided by the framework, which may or may not be interesting to you depending on your project.
I definitively suggest reading about OSGi if you haven't already - it's very interesting technology. I would suggest reading Neil Bartlett's articles on EclipseZone - this is the first one:
http://www.eclipsezone.com/eclipse/forums/t90365.html
There are a bunch of them, so google them - very interesting read, which will also give you an idea whether this is something you should consider.
SpringSource is a big proponent of OSGi, so it's worth taking a look there, too:
http://www.springsource.org/osgi
If you ever plan on using it in an OSGi context then you might as well make it a bundle. I don't know that there are any negative affects to making it a bundle, whereas if you don't make it a bundle and find out later on that you need it to be then you may have to go back and fix it. Aside from that I personally don't know of anything other than OSGi which uses the manifest meta information - but like I said; I don't think it will hurt.
OSGIfying a project will allow OSGI to be used for dependency management in Eclipse instead of the standard Eclipse project build mechanism, or an external dependency management tool such as Ivy or Maven. Making a project into an OSGI bundle allows you to express that project's package dependencies as bundle dependencies (if a bundle exists for the package dependency) which will be handled by the OSGI framework instead of those other mechanisms (standard Eclipse project build/Ivy/Maven).
Standard Eclipse project dependencies are established by specifying other projects and libraries on your project's build path. Converting to OSGI would replace your build path references with MANIFEST.MF import-package or required-bundles declarations.
Advantages of using OSGI for dependency management over the standard eclipse mechanism are:
re-export dependences: your bundle can re-export their dependent packages which means code relying on your bundle doesn't also have to rely on your bundle's dependants if it also uses them
version management: so you can specify the minimum and maximum expected version of a dependency.
See also Should I use Eclipse plug-ins (or OSGi Bundles) as a plain dependency management tool?

OSGI - handling 3rd party JARs required by a bundle

I'm just getting started with OSGI development and am struggling to understand how best to handle dependant JARs.
i.e. if I'm creating a bundle the likelyhood is that I will need to use a few 3rd party JARs. When I create my bundle JAR to deploy to OSGI, obviously these 3rd party JARs are not included and thus the bundle will not run.
I understand that one option is to turn these JARs into bundles and also deploy them to the OSGI container. However if they only need to be used by the one bundle this doesn't seem ideal.
What is the best solution to this? Can the JARs be embedded within the bundle JAR and if so is this a reasonable approach?
You can include a third party jar inside your bundle by adding the third party jar to the root directory of the bundle jar file and then adding a bundle classpath header to the bundle's manifest, e.g.:
Bundle-ClassPath: .,my3rdparty.jar
If you want to place third party jar to subdirectory, specify the path without using heading ./, e.g
Bundle-ClassPath: .,lib/my3rdparty.jar # (not ./lib/my3rdparty.jar)
I would almost always bundle each jar separately. OSGi itself is meant for modularization and you take the whole system ad absurdum by not doing this.
If you want to convert JARs into bundles you might want to use the BND Tool written by Peter Kriens. But first I would suggest you look for the bundle in the SpringSource Enterprise Bundle Repository if they haven't already done the work for you.
It is possible to embed non-OSGi dependencies into the bundle.
An easy way to do this is to use Maven to manage your dependencies and Maven Bundle Plugin to build your bundle. Take a look at the <Embed-Dependency> and <Embed-Transitive> instructions of the Maven Bundle Plugin described in the section Embedding dependencies of the plug-in documentation page.
As Roland pointed out this is not an ideal solution with respect to the intentions of OSGi, i.e. modularization and reuse of individual modules. However it might be pragmatic solution for time being until the 3rd-party dependencies can be converted into OSGi bundles.
This thread is a bit old, but I wanted to point out one of the limitations of embedding dependencies. Recall that dependencies are at the jar level, but when you export packages some may need to come from the embedded dependencies. If this happens, you will end up with duplicate classes, one set inline in the top level bundle and another in the embedded jar. Of course, you can inline the entire embedded jar, but before you know it this propagates across your entire dependency chain. This is just one of the problems that Roland and others refer to.
Here is an example if you are using the Maven Bundle Plugin.
Note: This plugin automatically imports packages that your dependencies need. This may or may not be a problem for you. Thankfully, you can suppress the packages you don't really need to import (see below).
<Import-Package>
<!-- this was imported by one of the dependencies; I don't really need it -->
!org.apache.jackrabbit.test,
*
</Import-Package>
<Include-Resource>
lib/concurrent-1.3.4.jar,
lib/jackrabbit-core-2.6.5.jar,
lib/jackrabbit-spi-2.6.5.jar,
lib/jackrabbit-spi-commons-2.6.5.jar,
lib/lucene-core-3.6.0.jar,
lib/tika-core-1.3.jar
</Include-Resource>
<Bundle-ClassPath>
.,
concurrent-1.3.4.jar,
jackrabbit-core-2.6.5.jar,
jackrabbit-spi-2.6.5.jar,
jackrabbit-spi-commons-2.6.5.jar,
lucene-core-3.6.0.jar,
tika-core-1.3.jar
</Bundle-ClassPath>
Can we use OSGI to override the bootstrap classloader jars loaded during runtime, like if we wanted to override JAXP1.4.5 available with Java7 to JAXP1.6, there is -Dendorese feature to override the default API to upgraded API. Can we able to do this thing with the help of OSGI.

Categories