ClassNotFoundException for a class on the bnd classpath

844 views
Skip to first unread message

Attila Sragli

unread,
Jan 7, 2013, 10:13:54 AM1/7/13
to bndtool...@googlegroups.com
Hi,

I tried to create a bundle that depends on the package javax.annotation, but I got ClassNotFoundException for javax.annotation.Nonnull in the packaging phase:

java.lang.ClassNotFoundException: javax.annotation.Nonnull
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:244)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:230)
    at aQute.lib.osgi.Annotation.getAnnotation(Annotation.java:63)
    at aQute.bnd.component.AnnotationReader.annotation(AnnotationReader.java:136)
    at aQute.lib.osgi.Clazz.doAnnotations(Clazz.java:1083)
    at aQute.lib.osgi.Clazz.doAttribute(Clazz.java:769)
    at aQute.lib.osgi.Clazz.doAttributes(Clazz.java:751)
    at aQute.lib.osgi.Clazz.parseClassFile(Clazz.java:516)
    at aQute.lib.osgi.Clazz.parseClassFile(Clazz.java:369)
    at aQute.lib.osgi.Clazz.parseClassFileWithCollector(Clazz.java:359)
    at aQute.bnd.component.AnnotationReader.getDef(AnnotationReader.java:66)
    at aQute.bnd.component.AnnotationReader.getDefinition(AnnotationReader.java:50)
    at aQute.bnd.component.DSAnnotations.analyzeJar(DSAnnotations.java:36)
    at aQute.lib.osgi.Analyzer.analyze(Analyzer.java:130)
    at aQute.lib.osgi.Builder.analyze(Builder.java:306)
    at aQute.lib.osgi.Analyzer.calcManifest(Analyzer.java:301)
    at aQute.lib.osgi.Builder.build(Builder.java:73)
    at org.apache.felix.bundleplugin.BundlePlugin.buildOSGiBundle(BundlePlugin.java:547)
    ...

It is strange because this class resides in a jar that is on the bnd classpath:

-classpath:\
 /home/sragli/.m2/repository/gov/nasa/jpf/jpf-core-annotations/6.0/jpf-core-annotations-6.0.jar,\
...

and

$ jar tvf /home/sragli/.m2/repository/gov/nasa/jpf/jpf-aprop-annotations/6.0/jpf-aprop-annotations-6.0.jar
   ...
   292 Thu Jun 28 10:31:00 CEST 2012 javax/annotation/Nonnull.class

What did I do wrong?

Thanks,

--
Attila Sragli

Peter Kriens

unread,
Jan 7, 2013, 10:46:43 AM1/7/13
to bndtool...@googlegroups.com
My guess this is not an error in bnd but in Maven. It seems to printout this exception since the caller getAnnotation is catching this exception and ignoring it, it is just probing the class path to see if it can find it. Since this is not an annotation bnd is aware of, it can ignore it.

Notice that this annotation is searched on the maven class path since it is a bnd.jar dependency. By definition, classes on the user classpath must be ignored since they are a potential way to execute code by unintended parties.

Hope this helps, kind regards,

Peter Kriens

Attila Sragli

unread,
Jan 7, 2013, 5:39:44 PM1/7/13
to bndtool...@googlegroups.com
Helped a lot, thanks. I did not identify the cause of the error yet, but I could work around it using -failok. Now the jar is created successfully as well as the manifest and DS descriptor.

Regards,

Attila Sragli

Peter Kriens

unread,
Jan 8, 2013, 4:22:04 AM1/8/13
to bndtool...@googlegroups.com
Hmm, you should not have to do -fail ok ... what version are you using?

Kind regards,

Peter Kriens



On 7 jan. 2013, at 16:13, Attila Sragli wrote:

Attila Sragli

unread,
Jan 8, 2013, 7:51:18 AM1/8/13
to bndtool...@googlegroups.com
It is considered as a temporary workaround until I figure out what the real problem is. I use version 1.50.0.

Martin Ellis

unread,
Jan 8, 2013, 6:28:43 PM1/8/13
to bndtool...@googlegroups.com
Hi Attila,

It seems like the problem is with this line in bnd:
Class<T> c = (Class<T>) getClass().getClassLoader().loadClass(cname);
https://github.com/bndtools/bnd/blob/master/biz.aQute.bndlib/src/aQute/bnd/osgi/Annotation.java#L66

That is, it's trying to load the annotation from the ClassLoader that
bnd itself is running under. I'm not sure why it does that. I don't
follow Peter's explanation that this avoids inadvertently running
unintended code: it seems possible to create a ClassLoader (or use one
in such a way) that it never initialises any classes. If this were
combined with reflection, bnd could use the annotations on the bundle
classpath, rather than on it's own classpath.

However, there seems to be a workaround that doesn't involve using
-fail ok: you can add the javax.annotation as a plugin dependency so
that it's present the same ClassLoader that bnd is loaded under. Ugly,
but it seems to work.

Here's an example:

<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<_dsannotations>*</_dsannotations>
</instructions>
</configuration>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</plugin>

Martin

Attila Sragli

unread,
Jan 9, 2013, 3:24:38 AM1/9/13
to bndtool...@googlegroups.com, mar...@ellis.name
Hi Martin,

Thank you for your nice explanation. I did some debugging yesterday and I noticed the same. I also tried the workaround you suggested, it works, but it is not feasible to use in production, since all the embedded jars should be unpacked and added as a dependency.

--
Attila

Peter Kriens

unread,
Jan 9, 2013, 4:06:33 AM1/9/13
to bndtool...@googlegroups.com
Am I missing something? The exception is caught and ignored in bnd's code, so how can this exception cause bnd to fail?

And to be clear, bnd does NOT run user code, the annotation is loaded from the classpath, i.e. its own code. It needs the annotations to create components. If you do not have components, remove the Service-Component:* header. Any user code that is run I consider an error in bnd.

Kind regards,

Peter Kriens

Attila Sragli

unread,
Jan 9, 2013, 5:10:37 AM1/9/13
to bndtool...@googlegroups.com
Hi Peter,

I think I was not clear enough, sorry. I used _dsannotations instead of Service-Component with the maven-bundle-plugin, this caused the exception. Using Service-Component, everything works as intended.

--
Attila

Peter Kriens

unread,
Jan 9, 2013, 1:16:05 PM1/9/13
to bndtool...@googlegroups.com
Still do not get it, even with the dsannotations you the exception should NOT fail the bnd run. I silently ignore it, the exception must be thrown lower in the chain. Or ... 1.50 did not catch the exception but that sounds not like me ...

Kind regards,

Peter Kriens

Attila Sragli

unread,
Jan 9, 2013, 2:15:43 PM1/9/13
to bndtool...@googlegroups.com
I happily provide you any kind of config and debug info if you would like, but my problem is solved using Service-Component instead of _dsannotations.

Thanks again,

--
Attila

Martin Ellis

unread,
Jan 9, 2013, 3:48:48 PM1/9/13
to bndtool...@googlegroups.com
I don't see any tags in the public bnd repo, but the code I see in the
source attachment for bndlib 1.50.0 is:

@SuppressWarnings("unchecked") public <T extends
java.lang.annotation.Annotation> T getAnnotation() throws Exception {
String cname = Clazz.objectDescriptorToFQN(name);
Class<T> c = (Class<T>) getClass().getClassLoader().loadClass(cname);
return getAnnotation(c);
}

These line numbers match up with Attila's stack trace (the loadClass
call is on line 63), so it seems like the correct source.

Looks like it's fixed in master though.

Martin

Peter Kriens

unread,
Jan 11, 2013, 2:25:23 AM1/11/13
to bndtool...@googlegroups.com
It is bnd that needs the annotation (ds annotations and bnd Service Component annotations) so to make this work I must rely on my own classes ...

Again, the current code catches the exception so I really still curious how bnd can fail???

Kind regards,

Peter Kriens

On 9 jan. 2013, at 00:28, Martin Ellis wrote:

Reply all
Reply to author
Forward
0 new messages