Reflection doesnt seem to work in OSGI?

1,433 views
Skip to first unread message

Vaishali Mithbaokar

unread,
Jan 13, 2014, 7:45:45 PM1/13/14
to bndtool...@googlegroups.com
I have a 3rd party bundle A which is using reflection to scan packages (for any annotations) from other bundle B. Even though I have exported the package from B and imported the package from A (and also tried DynamicImport package). But package A can not find classes of package B using Reflection.
Are there any known issues about Reflections and OSGI?

Neil Bartlett

unread,
Jan 13, 2014, 8:02:39 PM1/13/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
Reflection works as normal in OSGi. However, "scanning for classes" is not Reflection. There is no API in standard Java to enumerate classes on the classpath.

Libraries that do classpath scanning usually resort to hacks such as mapping the classloader to a JAR file and then reading the JAR file entries. These hacks depend on assumptions about where the classes come from, and those assumptions break down in a modular environment.

So without knowing more about the 3rd party library, it's difficult to say what's going wrong. Better not to use junk libraries!

Regards,
Neil



On 14 January 2014 at 00:45:46, Vaishali Mithbaokar (vaishali....@gmail.com) wrote:

I have a 3rd party bundle A which is using reflection to scan packages (for any annotations) from other bundle B. Even though I have exported the package from B and imported the package from A (and also tried DynamicImport package). But package A can not find classes of package B using Reflection.
Are there any known issues about Reflections and OSGI?
--
You received this message because you are subscribed to the Google Groups "bndtools-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bndtools-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Vaishali Mithbaokar

unread,
Jan 13, 2014, 10:17:52 PM1/13/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
So the 3rd party Framework is taking package name (org.foo.bar) and used Reflection as follows to search for classes within that package (it assumes classpath is set correctly to find this package within the jars from classpath). But looks like its not finding it. I have exported package from bundle B and imported from bundle A. The OSGI console also shows that it is getting wired. See the snippet from 3rd party FW
private Set<Class<?>> getAllClassesUnderPackages (final String... pkgs) {
        final Set<Class<?>> clses = new HashSet<Class<?>>();
        for (final String pkg : pkgs) {
            final Reflections reflections = new Reflections(pkg, new SubTypesScanner(false));
            final Set<Class<? extends Object>> subTypes = reflections.getSubTypesOf(Object.class);
            if (subTypes!=null) {
                for (final Class<? extends Object> cls : subTypes) {
                    if (cls != null) {
                        clses.add(cls);
                    }
                }
            }
            //clses.addAll(subTypes);
        }
        return clses;

Neil Bartlett

unread,
Jan 13, 2014, 10:26:37 PM1/13/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar, Vaishali Mithbaokar
As I said, this is not Java Reflection. The classes "Reflections" and "SubTypesScanner" are not standard Java classes, and you haven't indicated where they are from, so one can only speculate what they might be doing.

Regards,
Neil

Vaishali Mithbaokar

unread,
Jan 14, 2014, 12:32:40 AM1/14/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
Ah ok. Sorry. http://reflections.googlecode.com/svn/trunk/reflections/javadoc/apidocs/index.html?org/reflections/Reflections.html
I will attach remote debugger on it to see if anything obvious.

Vaishali Mithbaokar

unread,
Jan 14, 2014, 3:03:14 AM1/14/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
After remote debugging, it seems org.eclipse.gemini.web.tomcat.internal.loading.BundleWebappClassLoader@485531ae or Default class loader cant load my package B Any idea how to troubleshoot further? How the BundleWebAppClassLoader is set up? Based on bundle-classpath?

Dave Smith

unread,
Jan 14, 2014, 8:26:24 AM1/14/14
to bndtool...@googlegroups.com
More than likely your third party library is in a bundle correct? If so then the library will be using it's bundle classloader and will not find your classes. In order for it to work your library needs to support passing a classloader or using the ThreadContext classloader. If it does then what you need to do is create a Bundle Tracker/Listener and then on each bundle create a custom classloader that calls the underlying bundle.loadClass method and then pass that classloader to your library.

If you are looking for particular annotations on classes I would use bnd to generate a list in the manifest and then have your bundle listener check the manifest for the header and load the classes directly. For example if you are using javax.persistence  I have this in my bnd.bnd file
Hibernate-Db = ${classes;CONCRETE;ANNOTATION;javax.persistence.Entity}

This gives me a list of classes that that have the @Entity annotation. I just then call the bundle.loadClass with each element.

Felix Meschberger

unread,
Jan 14, 2014, 12:36:03 PM1/14/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
Hi

Looking that the source of the Reflections stuff, you will find that they can only scan class paths on URLClassLoaders. Bundle class loaders are not URL ClassLoaders in general. Hence your tool will fail to work unless it is adapted to make use of the Bundle API to read entries from the bundles (but this opens another can of works, be sure).

Regards
Felix

Vaishali Mithbaokar

unread,
Jan 15, 2014, 1:36:08 AM1/15/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
something like BundleWiring.listResources ?
that means I need to make changes to the 3rd party bundle.
Is there a way to achieve the same by e.g. specifying bundle classpath explicitly while wrapping the 3rd party bundle (which uses the Reflections API) so that it can find the classes in my bundle?

Neil Bartlett

unread,
Jan 15, 2014, 1:46:20 AM1/15/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar, Vaishali Mithbaokar
Sorry but no. The library still assumes that the classloader is an instance of URLClassLoader, which is simply not the case in OSGi (and in a lot of other places, e.g. Java EE). Thanks for the investigation work on that Felix.

So this Reflections library is fundamentally broken, and the classpath scanning technique itself is deeply flawed. It only ever works by accident, if it even works at all.

As Dave Smith points out, a far better approach is to scan the classes at build time using bnd, and construct a list of them in the manifest. This list can then be read very simply and very efficiently at runtime. This approach works because at build time we DO know the full list of classes we are putting into the jar.

Regards,
Neil

Andreas Holtz

unread,
Apr 11, 2014, 3:23:33 AM4/11/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
@Vaishal: In version 0.9.9-RC1 the reflection library uses org.eclipse.core.runtime.FileLocator to load bundles. Make sure the plugins org.eclipse.osgi and org.eclipse.equinox.common are not only in the class path but also properly started.
The handling exception handling of createDir()-method in org.reflections.vfs.DefaultUrlTypes.bundle is less then optimal.

@Neil Bartlett: Saying this reflection library is fundamentally broken is not just plain wrong but also disrespectful. Surely the createDir()-method is not a piece of art, but it works.

Neil Bartlett

unread,
Apr 11, 2014, 3:30:32 AM4/11/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
No myt statement was not wrong, but agree it was disrespectful and intentionally so.

How can you say the createDir() method works, when Vaishali's mails clearly show that it does not?

--
You received this message because you are subscribed to the Google Groups "bndtools-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bndtools-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andreas Holtz

unread,
Apr 11, 2014, 3:50:03 AM4/11/14
to bndtool...@googlegroups.com, Vaishali Mithbaokar
I can say this because I was fighting for several days with this method.
Problem is, that it returns null in any case, be it org.eclipse.equinox.common not in the class path or org.eclipse.equinox.common not started or any problem with org.eclipse.core.runtime.FileLocator.resolve()
See yourself from
org.reflections.vfs.DefaultUrlTypes.bundle:

public Dir createDir(URL url) throws Exception {
  try {
    return fromURL((URL) ClasspathHelper.contextClassLoader().loadClass("org.eclipse.core.runtime.FileLocator").getMethod("resolve", URL.class).invoke(null, url));
  }
  catch (Throwable ex) {
    return null;
  }
}

After loading and starting the
org.eclipse.equinox.common-bundle/plugin properly, it works at least for me in Eclipse PDE.
If Vaishali didn't put org.eclipse.equinox.common.jar in the class path and didn't start it properly, this method will always return null. (I don't know if he did it or not.)
And one has no chance besides debugging it, to find the problem.

For me its not fundamentally broken, it's just too broad exception handling.

Regards

Andreas
Reply all
Reply to author
Forward
0 new messages