Peaberry and service import problem

21 views
Skip to first unread message

Richard Wallace

unread,
Apr 15, 2009, 12:44:23 AM4/15/09
to guice-osgi
Hello,

I've got a situation where I have one OSGi bundle that doesn't use
Peaberry. It simply registers a single service using the
BundleContext like so
bundleContext.registerService(MyService.class.getName(), new
MyService(), new Hashtable<String, Object>());

I've got another, more complex bundle, that does use Guice and
Peaberry to wire things up and import OSGi services. It has a line in
a Guice Module that looks like
bind(MyService.class).toProvider(service(MyService.class).single());

The imported service is then injected into a Provider of another
object. When this bundle starts up, I get the following exception

org.osgi.framework.BundleException: Activator start error in bundle
my-bundle [25].
at org.apache.felix.framework.Felix.startBundle(Felix.java:1506)
at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:984)
at org.apache.felix.framework.StartLevelImpl.run(StartLevelImpl.java:263)
at java.lang.Thread.run(Thread.java:619)
Caused by: com.google.inject.internal.ComputationException:
com.google.inject.internal.ComputationException:
com.google.inject.internal.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:538)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:404)
at com.google.inject.internal.CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2031)
at com.google.inject.internal.FailableCache.get(FailableCache.java:46)
at com.google.inject.InjectorImpl$LateBoundConstructor.bind(InjectorImpl.java:457)
at com.google.inject.ClassBindingImpl.initialize(ClassBindingImpl.java:52)
at com.google.inject.InjectorImpl.initializeBinding(InjectorImpl.java:347)
at com.google.inject.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:639)
at com.google.inject.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:584)
at com.google.inject.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:179)
at com.google.inject.InjectorImpl.getBindingOrThrow(InjectorImpl.java:139)
at com.google.inject.InjectorImpl.getInternalFactory(InjectorImpl.java:645)
at com.google.inject.BoundProviderFactory.notify(BoundProviderFactory.java:47)
at com.google.inject.BindingProcessor.runCreationListeners(BindingProcessor.java:215)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:131)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
at com.threelevers.trinket.catalog.ui.Activator.start(Activator.java:37)
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:589)
at org.apache.felix.framework.Felix.startBundle(Felix.java:1458)
... 3 more
Caused by: com.google.inject.internal.ComputationException:
com.google.inject.internal.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:538)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:404)
at com.google.inject.internal.CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2031)
at com.google.inject.ProxyFactory.get(ProxyFactory.java:68)
at com.google.inject.ConstructorInjector.<init>(ConstructorInjector.java:52)
at com.google.inject.InjectorImpl$5.create(InjectorImpl.java:753)
at com.google.inject.InjectorImpl$5.create(InjectorImpl.java:749)
at com.google.inject.internal.FailableCache$1.apply(FailableCache.java:35)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:534)
... 24 more
Caused by: com.google.inject.internal.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
at com.google.inject.internal.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at com.google.inject.internal.cglib.reflect.FastClass$Generator.create(FastClass.java:64)
at com.google.inject.internal.BytecodeGen.newFastClass(BytecodeGen.java:147)
at com.google.inject.DefaultConstructionProxyFactory$2.<init>(DefaultConstructionProxyFactory.java:73)
at com.google.inject.DefaultConstructionProxyFactory.get(DefaultConstructionProxyFactory.java:71)
at com.google.inject.ProxyFactory.createConstructionProxy(ProxyFactory.java:85)
at com.google.inject.ProxyFactory$1.apply(ProxyFactory.java:62)
at com.google.inject.ProxyFactory$1.apply(ProxyFactory.java:60)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:534)
... 32 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.inject.internal.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at com.google.inject.internal.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
... 40 more
Caused by: java.lang.NoClassDefFoundError:
com/google/inject/internal/cglib/reflect/FastClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
... 45 more
Caused by: java.lang.ClassNotFoundException:
com.google.inject.internal.cglib.reflect.FastClass
at org.apache.felix.framework.searchpolicy.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:565)
at org.apache.felix.framework.searchpolicy.ModuleImpl.access$100(ModuleImpl.java:59)
at org.apache.felix.framework.searchpolicy.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1434)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)

As I wrote this I just noticed the last 2 parts of the stack trace,
mentioning the NoClassDefFoundError for FastClass. The thing that is
really confusing me is that I know this should be working, because I
have another bundle that does use Peaberry to export services and one
that uses Peaberry to import those services and that works fine. I'm
wondering if it has something to do with the exporting bundle not
using Peaberry (which seems rather silly). Or is it maybe that the
imported service is being used by a Provider in the 2nd bundle?

What am I doing wrong? Any ideas?

Thanks,
Rich

Stuart McCulloch

unread,
Apr 15, 2009, 1:16:19 AM4/15/09
to guice...@googlegroups.com
2009/4/15 Richard Wallace <rwalla...@gmail.com>

this exception typically occurs when Guice is unable to create a bridge classloader

which build of Guice are you using? - because the one shipped with peaberry 1.1
contains a patch for the bridging logic that hasn't been applied to the official trunk
(it should be applied in time for Guice 2.0)

if you're using guice-customloader-20090412.jar and still see this exception then
you should check that the type "MyService" is not package-protected, ie. it should
either be marked protected or public

this is because package-protected types aren't visible outside of their defining
classloader, and therefore we cannot use the bridging classloader technique
which is required in OSGi.

see http://code.google.com/p/google-guice/wiki/OSGi for more discussion of this

if you still get the exception after making sure the service interface is visible and
can boil this down to a recreatable testcase that you don't mind sharing then I'd
be happy to investigate

[ btw, there's at least one testcase in peaberry where a bundle exports a service
  without using/importing peaberry and another bundle imports it with peaberry
  so missing peaberry imports is probably not the issue ]

also if you enable "FINE" level logging in JCL then you should get messages from
Guice about what classloaders it uses for proxies, which should help narrow down
the problem

What am I doing wrong? Any ideas?

Thanks,
Rich

--
Cheers, Stuart

Stuart McCulloch

unread,
Apr 15, 2009, 1:17:45 AM4/15/09
to guice...@googlegroups.com
2009/4/15 Stuart McCulloch <mcc...@gmail.com>

^ that should read '... not package-private' :)
 
either be marked protected or public

this is because package-protected types aren't visible outside of their defining
classloader, and therefore we cannot use the bridging classloader technique
which is required in OSGi.

see http://code.google.com/p/google-guice/wiki/OSGi for more discussion of this

if you still get the exception after making sure the service interface is visible and
can boil this down to a recreatable testcase that you don't mind sharing then I'd
be happy to investigate

[ btw, there's at least one testcase in peaberry where a bundle exports a service
  without using/importing peaberry and another bundle imports it with peaberry
  so missing peaberry imports is probably not the issue ]

also if you enable "FINE" level logging in JCL then you should get messages from
Guice about what classloaders it uses for proxies, which should help narrow down
the problem

What am I doing wrong? Any ideas?

Thanks,
Rich

--
Cheers, Stuart



--
Cheers, Stuart

Richard Wallace

unread,
Apr 16, 2009, 2:12:55 AM4/16/09
to guice...@googlegroups.com
I just tried with the updated packages from peaberry 1.1 and I'm still
seeing this problem and the MyService interface is definitely public.
I'll see if I can break it down into a smaller test case tomorrow. If
I can't, I won't be able to for a while as I'm going on a much needed
vacation next week.

Thanks for the help,
Rich

Stuart McCulloch

unread,
Apr 16, 2009, 2:23:18 AM4/16/09
to guice...@googlegroups.com
2009/4/16 Richard Wallace <rwalla...@gmail.com>
I just tried with the updated packages from peaberry 1.1 and I'm still
seeing this problem and the MyService interface is definitely public.
I'll see if I can break it down into a smaller test case tomorrow.

thanks, I'll need a testcase or access to the current code
to debug this in detail ( send it to me privately if you like )

If I can't, I won't be able to for a while as I'm going on a much needed
vacation next week.

Thanks for the help,
Rich

--
Cheers, Stuart

Richard Wallace

unread,
Apr 17, 2009, 12:46:46 AM4/17/09
to guice...@googlegroups.com
Ok, so I think I figured out that problem. It seems that the
exception is only thrown if the Provider I'm trying to inject my
imported service into is a private class. Once I made the class
public, I get past that exception and things seem to be working as
they should. Before you said that "MyService" should not be
package-private, which seemed silly as that's the public interface
that is going to be used. Did you maybe mean that the Provider that
I'm injecting MyService into shouldn't be package-private?

Thanks,
Rich

Stuart McCulloch

unread,
Apr 17, 2009, 4:03:48 AM4/17/09
to guice...@googlegroups.com
2009/4/17 Richard Wallace <rwalla...@gmail.com>

Ok, so I think I figured out that problem.  It seems that the
exception is only thrown if the Provider I'm trying to inject my
imported service into is a private class.  Once I made the class
public, I get past that exception and things seem to be working as
they should.  Before you said that "MyService" should not be
package-private, which seemed silly as that's the public interface
that is going to be used.  Did you maybe mean that the Provider that
I'm injecting MyService into shouldn't be package-private?

actually it's wherever Guice decides to use a proxy - the proxied type
must not be package-private for the OSGi bridge classloading to work

unfortunately Guice sometimes seems rather eager to proxy classes
(ie. not just for AOP) - it uses proxies to break up circular references,
and uses CGLIB functionality (ie. FastClass, etc.) in other areas.

so it would seem that Guice is applying CGLIB to your Provider, but
I can't say for sure why it's doing this without seeing your code - also
note this would probably still happen even without using peaberry

Thanks,
Rich

On Wed, Apr 15, 2009 at 11:23 PM, Stuart McCulloch <mcc...@gmail.com> wrote:
> 2009/4/16 Richard Wallace <rwalla...@gmail.com>
>>
>> I just tried with the updated packages from peaberry 1.1 and I'm still
>> seeing this problem and the MyService interface is definitely public.
>> I'll see if I can break it down into a smaller test case tomorrow.
>
> thanks, I'll need a testcase or access to the current code
> to debug this in detail ( send it to me privately if you like )
>
>> If I can't, I won't be able to for a while as I'm going on a much needed
>> vacation next week.
>>
>> Thanks for the help,
>> Rich
>
> --
> Cheers, Stuart
>
> >
>





--
Cheers, Stuart
Reply all
Reply to author
Forward
0 new messages