Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] InvalidClassException during load time weaving

Andy,

I changed my aspect so that it does not use thisJoinPoint. The
InvalidClassException is resolved when I use the compile time weaving.
But when I use the load time weaving, I get the same exception again.
It looks like the around advice is inlined while compile time weaving
and not inlined during LTW. Some private inner classes are added after
weaving and they may be changing the generated SUID.

I noticed a post
(http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg02438.html) by
you saying that inlining cannot be forced during LTW. I have a single
aspect to weave a J2SE application. Is there anyway to force the
weaving sequence (to weave the aspect before the application) so that
the advice is inlined? Please check the sample code below.

Regards,
Choudary Kothapalli.

-------------------------------
My abstract aspect:
--------------------------------
package com.maintainj;
abstract public aspect AbstractAspect {
	abstract pointcut allExecutions();

	Object around(): allExecutions(){		
		return proceed();
	}
}
----------------------------------
aop.xml
---------------------------------
<aspectj>
	<aspects>
		<concrete-aspect name="com.maintainj.inst.J2SEAspect"
extends="com.maintainj.AbstractAspect">
			<pointcut name="allExecutions" expression="execution( * *.*(..)) ||
execution( *.new(..))"/>
		</concrete-aspect>
	</aspects>
	<weaver options="-proceedOnError">
		<dump within="test..*"/>
		<include within="test..*"/>
		<exclude within="com.maintainj..*"/>
	</weaver>
</aspectj>
----------------------------------------
Tester class (target application)
-------------------------------------
package test;
import java.io.*;
public class Tester implements Serializable {		
	public String data = "testData";	
	public void write(String file) throws IOException{
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
		oos.writeObject(new Tester());
	}	
	public Tester read(String file) throws IOException, ClassNotFoundException{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
		return (Tester)ois.readObject();
	}	
	public static void main(String[] args) throws IOException,
ClassNotFoundException{
		String fileName = "data.ser";
		Tester tester = new Tester();
		//tester.write(fileName);
		System.out.print(tester.read(fileName).data);
	}
}
------------------------------
The exception when the serialized Tester class is deserialized using
load time weaved Tester class:
---------------------------
Exception in thread "main" java.io.InvalidClassException: test.Tester;
local class incompatible: stream classdesc serialVersionUID =
5068263196426222505, local class serialVersionUID =
2026080278661052040
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:546)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
	at test.Tester.read_aroundBody4(Tester.java:11)
	at test.Tester$AjcClosure5.run(Tester.java:1)
	at com.maintainj.AbstractAspect.ajc$around$com_maintainj_AbstractAspect$1$b63a16ddproceed(AbstractAspect.aj:1)
	at com.maintainj.AbstractAspect.ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(AbstractAspect.aj:6)
	at test.Tester.read(Tester.java:10)
	at test.Tester.main_aroundBody6(Tester.java:17)
	at test.Tester$AjcClosure7.run(Tester.java:1)
	at com.maintainj.AbstractAspect.ajc$around$com_maintainj_AbstractAspect$1$b63a16ddproceed(AbstractAspect.aj:1)
	at com.maintainj.AbstractAspect.ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(AbstractAspect.aj:6)
	at test.Tester.main(Tester.java:14)
-----------------------------
Tester class after load time weaving
------------------------------
package test;
import com.maintainj.AbstractAspect;
import com.maintainj.inst.J2SEAspect;
import java.io.*;
public class Tester implements Serializable{
    public String data;
    public Tester(){
        Object aobj[] = new Object[1];
        aobj[0] = this;
        J2SEAspect.aspectOf().ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(new
AjcClosure1(aobj));
    }

    public void write(String s) throws IOException {
        String s1 = s;
        Object aobj[] = new Object[2];
        aobj[0] = this;
        aobj[1] = s1;
        J2SEAspect.aspectOf().ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(new
AjcClosure3(aobj));
    }

    public Tester read(String s) throws IOException, ClassNotFoundException{
        String s1 = s;
        Object aobj[] = new Object[2];
        aobj[0] = this;
        aobj[1] = s1;
        return (Tester)J2SEAspect.aspectOf().ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(new
AjcClosure5(aobj));
    }

    public static void main(String args[]) throws IOException,
ClassNotFoundException {
        String args1[] = args;
        Object aobj[] = new Object[1];
        aobj[0] = args1;
        J2SEAspect.aspectOf().ajc$around$com_maintainj_AbstractAspect$1$b63a16dd(new
AjcClosure7(aobj));
    }

    static final void init$_aroundBody0(Tester this) {
        this.data = "testData";
    }

    static final void write_aroundBody2(Tester this, String file){
        ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream(file));
        oos.writeObject(new Tester());
    }

    static final Tester read_aroundBody4(Tester this, String file){
        ObjectInputStream ois = new ObjectInputStream(new
FileInputStream(file));
        return (Tester)ois.readObject();
    }

    static final void main_aroundBody6(String args[]){
        String fileName = "data.ser";
        Tester tester = new Tester();
        System.out.print(tester.read(fileName).data);
    }

    private class AjcClosure1 extends AroundClosure{
        public Object run(Object aobj[]){
            Object aobj1[] = super.state;
            Tester.init$_aroundBody0((Tester)aobj1[0]);
            return null;
        }

        public AjcClosure1(Object aobj[]){
            super(aobj);
        }
    }
    private class AjcClosure3 extends AroundClosure{
        public Object run(Object aobj[]){
            Object aobj1[] = super.state;
            Tester.write_aroundBody2((Tester)aobj1[0], (String)aobj1[1]);
            return null;
        }
        public AjcClosure3(Object aobj[]){
            super(aobj);
        }
    }
    private class AjcClosure5 extends AroundClosure{
        public Object run(Object aobj[]){
            Object aobj1[] = super.state;
            return Tester.read_aroundBody4((Tester)aobj1[0], (String)aobj1[1]);
        }
        public AjcClosure5(Object aobj[]){
            super(aobj);
        }
    }
    private class AjcClosure7 extends AroundClosure{
        public Object run(Object aobj[]){
            Object aobj1[] = super.state;
            Tester.main_aroundBody6((String[])aobj1[0]);
            return null;
        }
        public AjcClosure7(Object aobj[]){
            super(aobj);
        }
    }
}

On Tue, Jan 20, 2009 at 12:52 PM, Andy Clement <andrew.clement@xxxxxxxxx> wrote:
> I agree with everything Simone said about really requiring a
> serialVersionUID if implementing serializable - in fact AspectJ will
> generate the serialVersionUID fields for you with:
>
> ajc -XaddSerialVersionUID *.java
>
> (the field is calculated prior to weaving occurring).
>
> But of course that only works if compiling from source though and here
> you are consuming someone elses code.
>
> But your situation intrigued me so I had a dig into it.  You would be
> fine if you didn't reference thisJoinPoint.  This aspect:
>
> package mn
> public aspect TestAspect {
>       pointcut allExecutions():(execution(public * *.*(..))) &&
> !within(mnj.TestAspect);
>
>        Object around(): allExecutions(){
> //                System.out.println(thisJoinPoint);
>                return proceed();
>        }
>  }
>
> will not change the serial version UID.  All new members introduced
> are private and the type structure is unaltered.  The problem is that
> when you reference thisJoinPoint we are likely to add a static
> initializer to the affected type that will initialize the static parts
> of the join point object (so it is done once rather than every time
> the join point is encountered).  The creation of a static initializer
> where there wasn't one changes the serial version UID.  If the target
> type already had a static initializer, then the uid would not have
> changed, but you can't really rely on that...
>
> Andy.
>
>
> 2009/1/19 Choudary Kothapalli <choudary.kothapalli@xxxxxxxxx>
>>
>> Andy,
>>
>> Here is my simple aspect:
>> ----------
>> package mnj;
>> public aspect TestAspect {
>>        pointcut allExecutions():(execution(public * *.*(..))) &&
>> !within(mnj.TestAspect);
>>
>>        Object around(): allExecutions(){
>>                System.out.println(thisJoinPoint);
>>                return proceed();
>>        }
>> }
>> ---------
>> The test class is as follows:
>>
>> package test;
>> import java.io.*;
>> public class Tester implements Serializable{
>>        //private static final long serialVersionUID = 1L;
>>
>>        public String data = "testData";
>>
>>        public void write(String file) throws IOException{
>>                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
>>                oos.writeObject(new Tester());
>>        }
>>        public Tester read(String file) throws IOException, ClassNotFoundException{
>>                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
>>                return (Tester)ois.readObject();
>>        }
>>        public static void main(String[] args) throws IOException,
>> ClassNotFoundException{
>>                String fileName = "data.ser";
>>                Tester tester = new Tester();
>>                //tester.write(fileName);
>>                tester.read(fileName);
>>        }
>> }
>> --------------
>> My scenario is as follows:
>> 1. The application serializes Tester (before aspect weaving). Tester
>> does not define SUID.
>> 2. Tester is weaved with TestAspect and deserialized.  It fails with
>> InvalidClassException. This is obviously because the Tester class
>> definitions differ (and generated SUIDs don't match) before and after
>> weaving.
>> 3. If the SUID is explicitly defined, they match and there is no problem
>>
>> As my product MaintainJ  is generic and should work with different
>> java runtimes, I cannot guess how the SUIDs are generated and avoid
>> affecting those classes. As I said in my first post, I can simply
>> avoid this problem by not weaving Tester class at all, but this
>> solution won't show the calls to those classes in the generated
>> sequence diagrams. Please let me know if you could think of any
>> workarounds.
>>
>> Regards,
>> Choudary Kothapalli.
>>
>> Here is the stack trace:
>> Exception in thread "main" java.io.InvalidClassException: test.Tester;
>> local class incompatible: stream classdesc serialVersionUID =
>> 5068263196426222505, local class serialVersionUID = 489981860994650887
>>        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:546)
>>        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
>>        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
>>        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
>>        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
>>        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
>>        at test.Tester.read_aroundBody2(Tester.java:15)
>>        at test.Tester.read_aroundBody3$advice(Tester.java:109)
>>        at test.Tester.read(Tester.java:1)
>>        at test.Tester.main_aroundBody4(Tester.java:21)
>>        at test.Tester.main_aroundBody5$advice(Tester.java:109)
>>        at test.Tester.main(Tester.java:1)
>>
>> On Sun, Jan 18, 2009 at 9:52 PM, Andy Clement <andrew.clement@xxxxxxxxx> wrote:
>> > Tricky problem.  Are you able to limit what your aspect does such that it
>> > doesn't affect the parts of the classes that contribute to the calculated
>> > SUID?  If you are just using advice and not intertype declarations, I can
>> > imagine it might be possible - but then it would depend on perclauses, use
>> > of around advice and whether that advice can be inlined.  Do you know which
>> > part of your aspect is affecting the SUID?
>> >
>> > cheers,
>> > Andy.
>> >
>> > 2009/1/16 Choudary Kothapalli <choudary.kothapalli@xxxxxxxxx>
>> >>
>> >> My product MaintainJ instruments an application using load time
>> >> weaving to capture the call trace and generate the sequence diagram. I
>> >> am having problems while deserializing classes that do not define a
>> >> SUID. The SUIDs of the original class and the weaved class are not
>> >> matching and InvalidClassException is thrown.
>> >>
>> >> Currently I suggest my users to exclude those classes, but some
>> >> applications serialize too many classes and this solution is not ideal
>> >> for them. Any ideas on how this problem can be solved?
>> >>
>> >> Thanks,
>> >> Choudary Kothapalli.
>> >> _______________________________________________
>> >> aspectj-dev mailing list
>> >> aspectj-dev@xxxxxxxxxxx
>> >> https://dev.eclipse.org/mailman/listinfo/aspectj-dev
>> >
>> >
>> > _______________________________________________
>> > aspectj-dev mailing list
>> > aspectj-dev@xxxxxxxxxxx
>> > https://dev.eclipse.org/mailman/listinfo/aspectj-dev
>> >
>> >
>> _______________________________________________
>> aspectj-dev mailing list
>> aspectj-dev@xxxxxxxxxxx
>> https://dev.eclipse.org/mailman/listinfo/aspectj-dev
> _______________________________________________
> aspectj-dev mailing list
> aspectj-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-dev
>


Back to the top