Re: WOInject: harmed twice by classloader manipulation
Re: WOInject: harmed twice by classloader manipulation
- Subject: Re: WOInject: harmed twice by classloader manipulation
- From: Joseph Pachod <email@hidden>
- Date: Thu, 14 Jun 2012 00:53:32 +0200
Hi Henrique
Thanks for the feedbacks.
I've been short on time recently, so I quickly tried your fix but I
encounter the following issue:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.resurgences.guice.WOInject.loadClass(WOInject.java:158)
at com.resurgences.guice.WOInject.main(WOInject.java:117)
at com.resurgences.demo.admin.ApplicationAdminDemo.main(ApplicationAdminDemo.java:14)
Caused by: java.lang.LinkageError: loader (instance of
sun/misc/Launcher$AppClassLoader): attempted duplicate class
definition for name: "com/webobjects/foundation/_NSUtilities"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
... 7 more
As I should be sleeping, I don't have much time to investigate right
now, but I'll soon. Line numbers doesn't match your code since there
are the extra guice stuff in there as well. Furthermore, I effectively
have two instances of this class on my classpath (ERExtensions and
JavaFoundations classes), so it doesn't look incorrect.
BTW, are you sure Guice AOP works for binding realized through a
provider? I have the memory it doesn't... If not, just injecting
members after objects creation through _NSUtilities looks like good
enough.
Thanks again for your helpful answers :)
best
joseph
2012/6/10 Henrique Prange <email@hidden>:
> Joseph,
>
> I have created a issue [1] to track this problem.
>
> There is a new commit in the hotfix-classloading branch that tries to solve the problem. It removes the dependency on a custom class loader. It's still very experimental, but I would like to know if this patch solves your problem.
>
> There is one requirement: you have to create a AppRunner class, and start your application from it. Here is an example of a very simple runner:
>
> public class AppRunner {
> public static void main(String[] args) {
> WOInject.init("your.app.Application", args);
> }
> }
>
> I've deployed a new WOInject SNAPSHOT to the WOCommunity repository. Just update to the 1.1-SNAPSHOT version in your pom to download the latest changes.
>
> [1]https://github.com/hprange/woinject/issues/7
>
> Cheers,
>
> Henrique
>
> On 07/06/2012, at 23:30, Henrique Prange wrote:
>
>> Hi Joseph,
>>
>> On 06/06/2012, at 04:04, Joseph Pachod wrote:
>>
>>> Hi all
>>>
>>> We've been using WOInject for a few months and encountered two issues
>>> due to the classloader manipulation done at startup (the one to enable
>>> interception through javassist, in the WOInject class).
>>>
>>
>> You're not alone. I've faced problems because of the classloader manipulation too. Take a look at issue #2 [1]. I've provided a simple fix, but I know it is not a definitive solution.
>>
>>> The first issue is a known Guice 2.0 bug
>>> (http://code.google.com/p/google-guice/issues/detail?id=343). This one
>>> pops up when from Guice grabs some class from another classloader that
>>> the one it was started in. In our case, it meant Guice was grabing
>>> some class from the default class loader instead of the the javassist
>>> one. It appeared in a very unexpected way: suddenly one binding was
>>> causing the whole application to break down. Finally, we had to switch
>>> to Guice 3.0, which incorporates the bug fix and avoids the issue to
>>> show up another time somewhere else. Turned out since that the
>>> woinject repo on github states "Guice 3.0" as a requirement. Was this
>>> bug the reason for it?
>>>
>>
>> In fact, I was not aware of this Guice bug until now. :)
>>
>> The WOInject code responsible for object instantiation was heavily inspired by the AssistedInject module. It requires the bind().toConstructor() method API added in Guice 3.0. To support Guice 2.0, WOInject would not be able to take advantage of the AOP support, for instance.
>>
>>> The second issue is a security exception when trying to encrypt some
>>> file. The issue was boiled down to a classloader one again, the
>>> required class being "on the bootclasspath" instead of the current
>>> classloader (the javassist one). I append the stack trace to the end
>>> of this mail, if some one wants to have a look at it.
>>>
>>
>> This problem seems to be related to the issue #2 mentioned above. Clearly, an alternative is required to the Javassist classloader to solve this problem.
>>
>>> In order to get rid of this bug, we ended removing the classloading
>>> trick and, instead, using our own _NSUtilities where we do the
>>> injector.injectMembers(newInstance) ourselves. In order to make it
>>> possible, we made sure our own version of this class came on top of
>>> the classpath provided to the application (thanks to Maven). Since it
>>> works again.
>>>
>>> What do you think of that ? Could it be done as well in WOInject ?
>>>
>>
>> Yes. It could be done. However, this solution also has some problems:
>>
>> 1) It doesn't scale: that is the same approach employed by Wonder. We can't apply this kind of solution every time, for every framework.
>>
>> 2) It is subject to license issues.
>>
>> 3) It makes the user responsible for the solution of the problem. This problem is an extension of the first problem. In the beginning, ERExtensions should come first in the classpath. Then ERFoundation and ERWebObjects were created and took precedence. With this solution, WOInject must come before those libraries.
>>
>> 4) I'm not sure this solution works in a JEE environment.
>>
>> Changing the behavior of core classes of WebObjects is a general problem that anyone developing WO apps/frameworks face sooner or later. IMHO, we should develop a common solution in Wonder, some kind of ERPatcher framework. This would enable us to solve long-standing problems without violating the Apple license and in an organized manner. I really would like to know what others think about it. I'm really inclined to implement this framework, as soon as I figure out how. :)
>>
>>> Indeed, we were planning to use WOInject once the "WOInjectProposal"
>>> on github would have been incorporated.
>>>
>>
>> I'm planning to add this feature in the next release. I'm really out of time right now, but it is in my TODO list.
>>
>>> Personally, getting rid of classloader manipulations would be a plus
>>> IMHO. It removes a whole bunch of potential issues, from memory leaks
>>> to "classes from the wrong classloader".
>>>
>>
>> Classloader manipulations are complicated and can have side effects. However, it has been widely used in Java frameworks (including Guice). I'll try to produce a better solution. I'll ping you as soon as I have a new version for testing.
>>
>>> For sure, I may miss some good points of javassist, so I'm really
>>> eager to read you back. Alternative solutions are also welcome, but
>>> the few I could make up (using an agent instead of classloader
>>> manipulation for example) don't come for cheap neither: overall class
>>> shadowing and classpath ordering look like the less impacting option.
>>>
>>
>> I also would like to avoid using an agent to solve this problem. IMHO, we have the following alternatives:
>>
>> 1) A better custom classloader: the Javassist classloader is just an example of how to create a Classloader able to load Javassist manipulated classes. We can write a better one that loads only the _NSUtilities class from Javassist and delegates everything else to the parent classloader.
>>
>> 2) Loading the manipulated classes right on the System classloader: the manipulated _NSUtilities could be loaded directly in the System classloader through reflection. I don't know what are the side effects of this solution yet.
>>
>> 3) Classpath ordering: as you mentioned, avoids runtime problems at the cost of delegating the responsibility to the user of the library.
>>
>> I'll try to implement the first solution and send you a new version of WOInject as soon as possible.
>>
>> [1]https://github.com/hprange/woinject/issues/2
>>
>> Cheers,
>>
>> Henrique
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden