Re: subclass and superclass transformation question
Tronje Krop <[email protected]>
| Newsgroups | gmane.comp.java.objectweb.asm |
|---|---|
| Organization | TU-Darmstadt |
| Message-ID | <[email protected]> |
Hi Peter,
Thanks for your reply. That solution fine fine for me. I have
a quite similar solution where I define a wrapping class loader
inherited from URLClassLoader with a function:
protected Class<?> defineClass(String name, byte[] buffer) {
return this.defineClass(name, buffer, 0, buffer.length);
}
What puzzels me is the unreliable and duplicate work of loading
classes by getResourceAsStream() for analysis (of parent classes
and interfaces). For the agent concept it sounds as I cannot be
sure, whether a class will been modified by a different trans-
former before or after I get it.
Thus I can never be sure, whether a class provided by the trans-
former looks the same as the on I get from getResurceAsStream(),
and thus whether my analysis was correct. In effect I have to
face following two drawbacks:
(1) If I ignore the changes, my resulting classes may be in-
correct, or at least incomplete with respect to my designed
transformation.
(2) If I observe the changes, I have to re-analyse all affected
classes and in effect have to retransform them. This makes
the processing much more complex.
For me it seems only possible to go the second path. This makes
my already quite complex bookkeeping and analysis of classes
properties much more complex and requires many changes. Thus, I
think I will stick to the class loader concept for some more
time ;-).
CU Tronje
Peter Veentjer wrote:
> Hi Tronje,
>
> I'm still strugling with the same issues, but I have one answer to
> your questions.
>
> It is about adding new classes to the classloader, I use the following
> code for that:
>
> private final static Method defineClassMethod;
>
> static {
> try {
> defineClassMethod = ClassLoader.class.getDeclaredMethod(
> "defineClass",
> String.class,
> byte[].class,
> int.class,
> int.class);
> defineClassMethod.setAccessible(true);
> } catch (NoSuchMethodException e) {
> throw new RuntimeException(e);
> }
> }
>
> public static Class defineClass(ClassLoader classLoader, String
> className, byte[] bytecode) {
> //System.out.println("definingClass: "+className);
> try {
> return (Class) defineClassMethod.invoke(
> classLoader,
> className.replace("/", "."),
> bytecode,
> 0,
> bytecode.length);
> } catch (IllegalAccessException e) {
> throw new RuntimeException(format("A problem occurred
> while defining class '%s'", className), e);
> } catch (InvocationTargetException e) {
> throw new RuntimeException(format("A problem occurred
> while defining class '%s'", className), e);
> }
> }
>
> This works for me. This code can be called from your Javaagent when it
> wants to create additional classes.
>
> This is good enough for IDE support.. I'm also working on a
> compiletime instrumentation
> for production environments.
>
> On Thu, Feb 25, 2010 at 12:23 AM, Tronje Krop <[email protected]> wrote:
>> Hi all,
>>
>> thanks for the advice from all of you. This discussion has cleared
>> up a view questions I had for some time:
>>
>> In my current rewriter that is directly linked to the class loader,
>> I load all classes by getResourceAsStream. I have managed to do load,
>> analyse, and define all classes in the right order, which was as I
>> must admit quite tricky ... problems with cyclic class loading etc ...
>> but however, in the end it worked.
>>
>> Making it work in parallel will be a challenge, as I have to protect
>> the analysis information on class level in the right way. In addition
>> I have to block multiple requests on the same class until the rewrit-
>> ten and defined class is available - right?
>>
>> The advantage here is, I can test this with the conventional class
>> loader pattern.
>>
>> Now, when I switch to the agent concept, I have to wait for each
>> class until the bytecode is provided to the transformer before I
>> returning the rewritten bytecode. Anyhow, I'm allowed to load all
>> resources needed for analysis from the class loader using
>> getResourceAsStream().
>>
>> The big questions remaining are:
>>
>> (1) How am I supposed to introduce new classes on the fly in the
>> agent concept - may be be defineClass() of the class loader?
>>
>> (2) When it is allowed to use defineClass() of the class loader,
>> what is the difference against loading a class using getResource-
>> AsStream() and defining it in the class loader?
>>
>> (3) Wouldn't the getResourceAsStream() concept fail, if another
>> transformer modifies a class before it is provided to my transformer?
>>
>> Any suggestions how this is best handled?
>>
>> CU Tronje
>>
>> Marcel Patzlaff wrote:
>>> Just load the parent classes/interfaces as resources and analyse them
>>> with ASM. If you have to perform modifications, you should do what
>>> Eugene suggested: Prepare the transformations virtually and apply them
>>> if the classloader eventually loads the parent classes/interfaces.
>>>
>>> Regards,
>>> Marcel
>>>
>>> Tronje Krop schrieb:
>>>> I'm currently not using the java agent, but I like to do son in
>>>> future.
>>>>
>>>> My problem concerning the order of class loading is, that I need
>>>> at least to analyse parent classes and interfaces before trans-
>>>> forming the subclasses.
>>>>
>>>> But how can I do this without forcing the class loader to load
>>>> interfaces and parent classes. Any suggestion?
>>>>
>>>> CU Tronje
>>>>
>>>> Eugene Kuleshov wrote:
>>>>
>>>>> I wouldn't advise loading classes from the agent. Instead you should
>>>>> be able to prepare required transformations "virtually" when
>>>>> analyzing/loading subclasses, save some state and do the actual
>>>>> transformation when parent is actually loaded by JVM.
>>>>>
>>>>> regards,
>>>>> Eugene
>>>>>
>>>>>
>>>>> On Tue, Feb 23, 2010 at 10:01 AM, Rémi Forax <[email protected]> wrote:
>>>>>
>>>>>> Hi Peter,
>>>>>>
>>>>>> Le 23/02/2010 14:49, Peter Veentjer a écrit :
>>>>>>
>>>>>>> I have a question about the details of superclass/subclass
>>>>>>> transformations using a Java agent.
>>>>>>>
>>>>>>> If there is a class Fruit and a subclass Apple, and if a new Apple is
>>>>>>> created before the Fruit class is used in the JVM.
>>>>>>> What is the exact order of classes loaded in the Java agent?
>>>>>>>
>>>>>>> My experience is that the Apple class is transformed before the Fruit
>>>>>>> class is transformed. Is this correct?
>>>>>>>
>>>>>>>
>>>>>> Yes, the VM read the transformed class, find the super class and load it,
>>>>>> so superclass are loaded after class if there aren't loaded before.
>>>>>>
>>>>>> But you can load the superclass in the agent :)
>>>>>> you have the classloader and you can find the superclass in the classfile.
>>>>>> Just be careful about synchronisation, jdk7 classloading is done in
>>>>>> parallele.
>>>>>>
>>>>>>
>>>>>>
>>>>>>> And is there any way to force to load the super class (Fruit) is
>>>>>>> transformed before the subclass Apple is transformed?
>>>>>>>
>>>>>>> I have the impression that the Java agent technology is very limited
>>>>>>> and that the only way to solve these issues is
>>>>>>> to do a static transformation. The big problem is that it makes the
>>>>>>> system much harder to work with from an IDE; normally
>>>>>>> you only need to register some javaagent and you are done. But adding
>>>>>>> a postcompilation step is much harder.
>>>>>>>
>>>>>>>
>>>>>> Rémi
>>>>>>
>>>>>>
>>>>>> --
>>>>>> You receive this message as a subscriber of the [email protected] mailing list.
>>>>>> To unsubscribe: mailto:[email protected]
>>>>>> For general help: mailto:[email protected]?subject=help
>>>>>> OW2 mailing lists service home page: http://www.ow2.org/wws
>>>>>
>>>>
>>>
>>
>
message-footer.txt
(text/plain, 238 B)
-- You receive this message as a subscriber of the [email protected] mailing list. To unsubscribe: mailto:[email protected] For general help: mailto:[email protected]?subject=help OW2 mailing lists service home page: http://www.ow2.org/wws