Open GoogleCodeExporter opened 9 years ago
My proposed fix is as follows:
* if the type has the same classloader as the BytecodeGen class we use that
* if the type classloader is already a bridging classsloader we use that
* if enabled and it's not a package-private type we use a bridge classloader
* otherwise we use the type classloader
I'll attach a patch shortly along with a new test for this situation.
Original comment by mccu...@gmail.com
on 3 Mar 2009 at 1:15
Suggested patch along with an update to the BytecodeGen testcases.
Because we now use a bridging classloader when the type classloader is
different to
the Guice classloader I had to change
testSystemClassLoaderIsUsedIfProxiedClassUsesIt
to be testGuiceClassLoaderIsUsedIfProxiedClassUsesIt. This is because in the
testcase
the Guice classloader is different to the system classloader.
Original comment by mccu...@gmail.com
on 3 Mar 2009 at 2:57
Attachments:
This is an enhanced patch that adds the ability to turn on bridge classloading
even
when the type classloader is the same as the Guice classloader. This might be
useful
when you want proxy classes unloaded as eagerly as possible (note because Guice
now
shares proxy classes this is less of an issue than before).
To turn on eager bridge classloading use: -Dguice.custom.loader=eager
Original comment by mccu...@gmail.com
on 3 Mar 2009 at 3:35
Attachments:
FYI, this is the original thread discussing the problem:
http://groups.google.com/group/guice-osgi/browse_thread/thread/a1030d7500a29dec
Original comment by mccu...@gmail.com
on 3 Mar 2009 at 4:38
Latest patch that also wraps the call to getSystemClassLoader in a doPrivileged
block.
Original comment by mccu...@gmail.com
on 3 Mar 2009 at 5:40
Attachments:
I'd like to get this patch into Guice 2.1 if possible.
Original comment by mccu...@gmail.com
on 30 Mar 2009 at 10:57
I'll patch this in.
Original comment by limpbizkit
on 2 Apr 2009 at 6:25
Original comment by limpbizkit
on 26 Apr 2009 at 9:36
Stuart I'm looking at this CL. Wow! I'm still lost on a few things....
Why do we need THREE modes for the guice.custom.loader property? Either you're
in OSGi/J2EE and you want
custom loading, or you're not. When wouldn't these two be sufficient?
Could you write a test? I'm tempted to tidy up the code, but I don't want to
break anything!
Original comment by limpbizkit
on 9 May 2009 at 4:34
Originally we supported just two modes:
<unset>/"true" - only use bridge classloaders where needed (and possible)
"false" - never use bridge classloaders (pre-OSGi behaviour)
but I think it would be useful to support:
"eager" - always use bridge classloaders wherever possible
This is different from the <unset> case because it will still try and use a
bridge
classloader even if Guice and the class being proxied are in the same
classloader.
This means that the proxy class can be eagerly unloaded even while the
application
classloader is still active - without this mode you wouldn't be able to unload
proxy
classes when proxying system types.
Now this is really a "nice-to-have", so if you think it will confuse people we
can
simply drop it :) or we can change it to "false", "lazy", and "true" - with
"lazy"
being the current default.
The other change is to support situations where we can't get the system
classloader
(ie. the classloader equivalent to "null") like on the AppEngine, but we still
want
to represent it as a non-null key in the map so we map it to a placeholder
object.
Feel free to tidy up the patch while I write up a test for this change - you can
always attach the new patch to this issue in case you're finished before I am ;)
Original comment by mccu...@gmail.com
on 10 May 2009 at 12:17
I'd like to make things work with only the two modes. I'll try to tweak your
patch to handle this.
Original comment by limpbizkit
on 13 May 2009 at 7:38
This patch didn't make it into 2.0, so rescheduling it for 2.1
Original comment by mccu...@gmail.com
on 21 May 2009 at 9:02
I'd like to know whether the following is fixed by this patch:
I wrote a custom classloader to speed up the cold startup of LimeWire which is
mostly
bound by file io caused by classloading.
I'm running into the following exception:
SEVERE: Application class org.limewire.ui.swing.mainframe.AppFrame failed to
launch
com.google.inject.CreationException: Guice creation errors:
1) Error injecting method, 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.assistedinject.FactoryProvider2.initialize(FactoryProvider2.ja
va:161)
at
org.limewire.ui.swing.search.LimeWireUiSearchModule.configure(LimeWireUiSearchMo
dule.java:56)
1 error
at
com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.jav
a:358)
at
com.google.inject.internal.InjectorBuilder.injectDynamically(InjectorBuilder.jav
a:174)
at com.google.inject.internal.InjectorBuilder.build(InjectorBuilder.java:114)
at com.google.inject.Guice.createInjector(Guice.java:93)
at com.google.inject.Guice.createInjector(Guice.java:81)
at org.limewire.ui.swing.mainframe.AppFrame.createUiInjector(AppFrame.java:309)
at org.limewire.ui.swing.mainframe.AppFrame.startup(AppFrame.java:153)
at org.jdesktop.application.Application$1.run(Application.java:171)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
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:553)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:419)
at
com.google.inject.internal.CustomConcurrentHashMap$ComputingImpl.get(CustomConcu
rrentHashMap.java:2041)
at com.google.inject.internal.FailableCache.get(FailableCache.java:46)
at
com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore
.java:50)
at
com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingI
mpl.java:62)
at com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:370)
at com.google.inject.internal.BindingProcessor$1$1.run(BindingProcessor.java:164)
at
com.google.inject.internal.BindingProcessor.initializeBindings(BindingProcessor.
java:219)
at
com.google.inject.internal.InjectorBuilder.initializeStatically(InjectorBuilder.
java:121)
at com.google.inject.internal.InjectorBuilder.build(InjectorBuilder.java:106)
at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:137)
at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:144)
at
com.google.inject.assistedinject.FactoryProvider2.getBindingFromNewInjector(Fact
oryProvider2.java:203)
at
com.google.inject.assistedinject.FactoryProvider2.initialize(FactoryProvider2.ja
va:171)
at
com.google.inject.assistedinject.FactoryProvider2$$FastClassByGuice$$9dcdf6d7.in
voke(<generated>)
at com.google.inject.internal.cglib.reflect.FastMethod.invoke(FastMethod.java:53)
at
com.google.inject.internal.SingleMethodInjector$1.invoke(SingleMethodInjector.ja
va:55)
at com.google.inject.internal.SingleMethodInjector.inject(SingleMethodInjector.java:87)
at
com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl
.java:96)
at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:73)
at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:72)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:801)
at
com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorIm
pl.java:71)
at com.google.inject.internal.Initializer$InjectableReference.get(Initializer.java:142)
at com.google.inject.internal.Initializer.injectAll(Initializer.java:89)
at
com.google.inject.internal.InjectorBuilder.injectDynamically(InjectorBuilder.jav
a:172)
... 14 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:553)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:419)
at
com.google.inject.internal.CustomConcurrentHashMap$ComputingImpl.get(CustomConcu
rrentHashMap.java:2041)
at com.google.inject.internal.FailableCache.get(FailableCache.java:46)
at
com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore
.java:50)
at
com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingI
mpl.java:62)
at com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:370)
at
com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.jav
a:642)
at
com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(Injecto
rImpl.java:574)
at
com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(Injecto
rImpl.java:565)
at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:165)
at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:125)
at com.google.inject.internal.InjectorImpl.getInternalFactory(InjectorImpl.java:648)
at
com.google.inject.internal.InjectorImpl.createParameterInjector(InjectorImpl.jav
a:704)
at com.google.inject.internal.InjectorImpl.getParametersInjectors(InjectorImpl.java:692)
at
com.google.inject.internal.ConstructorInjectorStore.createConstructor(Constructo
rInjectorStore.java:65)
at
com.google.inject.internal.ConstructorInjectorStore.access$000(ConstructorInject
orStore.java:29)
at
com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjector
Store.java:37)
at
com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjector
Store.java:35)
at com.google.inject.internal.FailableCache$1.apply(FailableCache.java:35)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:549)
... 40 more
Caused by: com.google.inject.internal.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
at
com.google.inject.internal.cglib.core.AbstractClassGenerator.create(AbstractClas
sGenerator.java:237)
at
com.google.inject.internal.cglib.reflect.FastClass$Generator.create(FastClass.ja
va:64)
at com.google.inject.internal.BytecodeGen.newFastClass(BytecodeGen.java:166)
at
com.google.inject.internal.DefaultConstructionProxyFactory$1.<init>(DefaultConst
ructionProxyFactory.java:52)
at
com.google.inject.internal.DefaultConstructionProxyFactory.create(DefaultConstru
ctionProxyFactory.java:50)
at com.google.inject.internal.ProxyFactory.create(ProxyFactory.java:147)
at
com.google.inject.internal.ConstructorInjectorStore.createConstructor(Constructo
rInjectorStore.java:82)
at
com.google.inject.internal.ConstructorInjectorStore.access$000(ConstructorInject
orStore.java:29)
at
com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjector
Store.java:37)
at
com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjector
Store.java:35)
at com.google.inject.internal.FailableCache$1.apply(FailableCache.java:35)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:549)
... 60 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor2.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(AbstractClas
sGenerator.java:219)
... 71 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:620)
... 76 more
Is this addressed by the patch? Are there other workarounds like having guice be
loaded by the system class loader?
Thanks,
Felix
Original comment by berge...@gmail.com
on 3 Aug 2009 at 6:35
Felix,
That looks like a problem I've run into when one of the classes you are trying
to
have Guice create and inject is package-protected. In an OSGi environment, all
the
classes Guice is going to be creating and wiring up need to be public (including
Providers), otherwise they can't be seen from any classloader but the one
they're
loaded from.
See http://code.google.com/docreader/#p=google-guice&s=google-guice&t=OSGi for
more
info, particularly the "What are the constraints of using Guice's OSGi
support?" section.
Original comment by rwallace...@gmail.com
on 4 Aug 2009 at 11:39
People are seeing this in practice...
Original comment by limpbizkit
on 16 Oct 2009 at 2:08
For interest, here's how I ran into it...
In Guice 1.0, I had a module that did:
bind(Date.class);
and some code that did:
@Inject
Provider<Date> dateProvider;
Hence, the code can do dateProvider.get() (instead of new Date()) to get the
current
time.
Meanwhile, the tests inject a Provider<Date> that returns times from a Queue.
I haven't looked at the code for a while, but I think it was testing periodic
polling
(has the card transaction been processed yet? or have we timed out?), and
(elsewhere)
logging start/end times for a client session.
Original comment by ellis.m.a@gmail.com
on 16 Oct 2009 at 11:00
I'm writing a container-based test at the moment to recreate this bug so it
doesn't
re-appear. Jesse do you still want the patch trimmed down to be an "on/off"
switch?
Or do we want to allow people to force the use of bridge class loaders? ie. some
situations you don't need an extra class loader to bridge between types and so
we
wouldn't create one, but using an extra class loader would let you eagerly
unload
proxy classes... (hence the 'eager' setting in the patch)
Original comment by mccu...@gmail.com
on 16 Oct 2009 at 3:17
Yeah, on/off is all I want. Configurability is the enemy of simplicity,
especially when the
utility of the configurability isn't obvious.
Original comment by limpbizkit
on 16 Oct 2009 at 4:24
Original comment by mccu...@gmail.com
on 31 Oct 2009 at 4:00
Updated patch to use a "class space" abstraction, which makes the code much
clearer
and should also be a little bit faster. Also included changes to switch back to
JDK
reflection when we can't use the CGLIB Fast* approach, which removes some of the
visibility limitations regarding OSGi (only method-intercepted classes need to
be
public/protected with this patch).
If we do find a private method-intercepted class when running in a strict
container
like OSGi then we now report exactly which method was involved, to help the
user.
The other changes are minor fixes to avoid unnecessary synthetic accessors...
[NOTE: issue 443 provides extra tests that check different visibilities in OSGi]
Original comment by mccu...@gmail.com
on 2 Nov 2009 at 8:09
Attachments:
Passing to Jesse for review of the latest patch.
Original comment by mccu...@gmail.com
on 2 Nov 2009 at 8:10
Build of trunk with latest 343 patch applied (in case anyone wants to give it a
spin)
Original comment by mccu...@gmail.com
on 16 Nov 2009 at 4:17
Attachments:
Last patch created more bridge class loaders than absolutely necessary, because
the
weak cache uses identity equality instead of equals. This updated patch goes
back to
using class loaders as keys but with a special bridge class loader for system
types.
I've also attached a build of Guice trunk with this patch applied for people to
test.
Original comment by mccu...@gmail.com
on 18 Feb 2010 at 4:59
Attachments:
guice-customloader-20100218.jar worked like a champ! thanks!
Original comment by holme...@gmail.com
on 18 Mar 2010 at 9:06
Issue 417 has been merged into this issue.
Original comment by sberlin
on 19 Apr 2010 at 2:36
[NOTE: I've split this patch into two parts to (hopefully) make it easier to
digest]
Description (1of2)
==================
The attached patch (GUICE_ISSUE_343_part1of2_20100504.patch) wraps the various
CGLIB
reflection calls in try...catch blocks so that if (for whatever reason) CGLIB
fails
to proxy the client type we can fall back to the slower JDK reflection which
usually
has better luck, given that it's running from the JVM zone.
There are three classes which use CGLIB to proxy client types:
A) ProxyFactory, which uses CGLIB to do method interception - there isn't an
easy JDK
reflection fallback for this, so we do the next best thing and wrap the error
inside
a ProvisionException. This includes a clear message indicating the failing
class,
which is not obvious from the original cause.
B) SingleMethodInjector, which uses CGLIB's FastMethod - if this fails then we
can
simply fall back to JDK reflection. Note that we need to make the method
accessible
if the declaring type is not-public, not just if the method itself is not
public.
C) DefaultConstructionProxyFactory, which uses CGLIB's FastConstructor - first
we
need to pull the creation of the FastConstructor outside of the
ConstructionProxy
constructor, otherwise we don't know if it will fail until it's too late.
Second we
need to add an extra call to make the constructor accessible when falling back
to JDK
reflection (but only if the constructor's declaring class is not public).
Original comment by mccu...@gmail.com
on 4 May 2010 at 12:51
Attachments:
Description (2of2)
==================
This is a hard patch to review as it involves custom classloading, but
hopefully the
OSGi container tests introduced in Issue 443 will increase confidence in this
patch.
We're also using it in installations of Sonatype Nexus 1.6.0 (both standalone
Java
and deployed as a WAR) so it's fair to say it has had a reasonable amount of
testing
in the field.
The attached patch (GUICE_ISSUE_343_part2of2_20100504.patch) fixes a number of
flaws
in the BytecodeGen class utility:
a) it fixes the assumption that types from the system classloader never need to
be
bridged^ because the application must be running in that space and therefore we
can
use the type's classloader. This assumption is incorrect: an application may be
running inside a non-system classloader and wants to proxy a system type. If
Guice is
also running inside a different non-system classloader then it won't be visible
from
the system classloader and bridging will still be required.
[^ bridging is when a new classloader is used to merge two disparate classloaders
into a single view.]
b) it avoids the need for ClassLoader.getSystemClassLoader() which might not be
available on systems that are running with a locked-down security manager.
c) it only creates the weak cache if we're using custom loading (the default
mode)
d) it handles the situation where the JVM suddenly needs access to "sun.reflect"
classes because a limit has been reached internally and it wants to redo the
proxy
Implementation
==============
The patch can be broken down like so:
i) minor visibility changes (make class public, make certain members
package-private
to avoid the cost of synthetic access)
ii) create a singleton bridge classloader (with initialization-on-demand so we
only
create it when we need it) that has the system classloader as parent (ie.
default
constructor). This way we don't need to rely on
ClassLoader.getSystemClassLoader().
iii) *all* classloaders are canonicalized, even the ones cached inside
BytecodeGen
iv) canonicalization maps non-null classloaders to themselves, and null
classloaders
to the parent of our singleton bridge classloader (which may also be null). The
key
thing is that we can test canonicalized classloaders against the singleton
parent.
v) initialize the weak classloader cache based on the "guice.custom.loader"
setting
vi) the following rules are used to decide if bridging is required:
"guice.custom.loader" disabled? -> NO NEED TO BRIDGE
same classloader as Guice? -> NO NEED TO BRIDGE
already a bridge? -> NO NEED TO BRIDGE
visible type and *not* from the system classloader? -> CREATE BRIDGE (cached)
visible type and from the system classloader? -> USE SYSTEM BRIDGE
otherwise -> UNABLE TO BRIDGE
vii) a bridge classloader is a custom classloader that has the type's
classloader as
its parent (or system classloader in the case of the system bridge). Classes
from
"sun.reflect" are always loaded from the system bridge using classic
parent-first
delegation. Internal Guice classes are loaded from the Guice classloader,
unless it's
null in which case we must be able to find them via the system bridge. A new
package-private method called "classicLoadClass" is added so we can call the
classic
loadClass implementation (ie. parent-first delegation) between bridge
classloaders.
This also serves as a replacement for "getParent().loadClass()" which could
cause a
NPE if the parent classloader is null.
Original comment by mccu...@gmail.com
on 4 May 2010 at 4:24
Attachments:
I have one question about part 2 of the patch. (I'm not terribly familiar with
all
the inner workings of classloading, so this may not be the wisest question.)
Prior to the patch, if a class's ClassLoader ('delegate') was the system class
loader, getClassLoader(Class, ClassLoader) just returned the existing
classloader
(the system classloader). The patch changes that so that it returns a
BridgeClassLoader whose parent is the system classloader.
This looks to be a goal of the patch (point 2), so it's clearly not a
mistake... but
I'd like to understand the implications of it. Will this result in objects
whose
getClassLoader method is different than the system classloader, even if the
application doesn't use any other classloaders? What are the implications of
that
(if true)? Could it result in the application having possibly having more than
one
classloader (leading to some Classes not being equal to each other, if one was
constructed by Guice and the other manually)?
Original comment by sberlin
on 8 May 2010 at 3:09
Correct, if the type's classloader is the system classloader and Guice is not
running
in the same classloader then it will create a bridge between the system
classloader
and the Guice classloader. Not creating a bridge for this situation is the
cause of
the original issue, hence this change.
But this doesn't mean it always creates a bridge classloader - if Guice is also
running in the system classloader then this is detected by the following check:
if (delegate == GUICE_CLASS_LOADER || ...
and the (canonicalized) type's classloader will be returned.
Original comment by mccu...@gmail.com
on 9 May 2010 at 5:29
Also note that bridge classloaders never define any classes themselves - they
always
delegate either to the type's classloader or the Guice classloader. So any
non-Guice
classes loaded via the bridge classloader will be equal to the same class
loaded by
the original type classloader (as with any parent-first delegation scheme).
Original comment by mccu...@gmail.com
on 9 May 2010 at 5:52
There is one minor change we could make to reduce the number of bridge
classloaders
even more - check to see if the type is under the "java.*" namespace. If it is
then
we can use the Guice classloader, as this can see both Guice classes and
"java.*"
classes. (Other non-"java.*" classes may be hidden from Guice depending on the
container's class loading model.)
Here's the extra patch to add this check:
Index: src/com/google/inject/internal/BytecodeGen.java
===================================================================
--- src/com/google/inject/internal/BytecodeGen.java (revision 2364)
+++ src/com/google/inject/internal/BytecodeGen.java (working copy)
@@ -128,6 +128,11 @@
return delegate;
}
+ // java.* types can be seen everywhere
+ if (type.getName().startsWith("java.")) {
+ return GUICE_CLASS_LOADER;
+ }
+
delegate = canonicalize(delegate);
// no need for a bridge if using same class loader, or it's already a bridge
Original comment by mccu...@gmail.com
on 9 May 2010 at 7:28
fixed in r1158. thanks very much for the patch, Stuart!
Original comment by sberlin
on 9 May 2010 at 12:52
Hi, I am new to Guice, and currently having problems with the guice 2.0 that i
just
downloaded.
I need the guice2.0, so that i am able to use the guicefruit for smooth jpa
integration
( inject with @PersistenceContext ) --- i have already been able to inject ejb
into
my struts2 action and guice is wonderful ! Now i need guice to support jpa
injection
also.
Can you suggest me on the stable guice2.0 one ?
Here is my stack :
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:553)
at com.google.inject.internal.MapMaker$StrategyImpl.compute(MapMaker.java:419)
Original comment by bambang....@gmail.com
on 4 Jun 2010 at 6:46
BB - suggest you either compile from trunk or perhaps try the patched jar at
http://repo2.maven.org/maven2/org/sonatype/spice/inject/guice-patches/2.1.3/
Original comment by mccu...@gmail.com
on 13 Jun 2010 at 3:34
Original issue reported on code.google.com by
mccu...@gmail.com
on 3 Mar 2009 at 1:06