Community
Participate
Working Groups
The aspect below won't compile ('The return type is incompatible') using the latest from CVS as of 27-7-05 public aspect ReturnTypeTest { private interface Test { Object getId(); } class StringTest { public String getId() { return null; } } declare parents : StringTest implements Test; } from Andy Clement: note that this pure Java version of the program doesn't compile with ajc but compiles with javac: public class ReturnTypeTest { private interface Test { Object getId(); } class StringTest implements Test { public String getId() { return null; } } } which tells us it is probably occurring because we haven't upgraded to the final version of the 3.1 eclipse JDT compiler.
tagging as something that will be fixed when we upgrade to the 3.1 final compiler.
The pure java scenario is fixed now we have moved to the final 3.1 JDT compiler. The AspectJ variant that uses declare parents still doesnt work: K:\ws\aspectj_ws\A\ReturnTypeTest.java:1 [error] The return type is incompatible with ReturnTypeTest$Test.getId() (no source information available) 1 error thats with the build dated 20050824100440 it might possibly be fixed by another change I'm about to put in...
for M4
finally fixed! At the last hurdle, the test for assignability of return types in binary weaving of declare parents was the wrong way round. Fix commited in tree and will be available in published build from AspectJ downloads page later on today.
fix now available in latest published build
I have verified that covariance in return types now generates no compiler errors; thank you. However, the aspect below compiles, but loading the ReturnTypeTester class results in a java.lang.AbstractMethodError when the Object Test.getId() is called inside int Test.hashCode() (see stack trace at bottom) Thanks, Reid /* * ReturnTypeTest.java * * Created on September 1, 2005, 3:26 PM * */ public aspect ReturnTypeTest { private interface Test { Object getId(); int hashCode(); } public int Test.hashCode() { return getId().hashCode(); } declare parents : ReturnTypeTester implements Test; } /* * ReturnTypeTester.java * * Created on September 1, 2005, 3:28 PM * */ import java.util.HashSet; import java.util.Set; public class ReturnTypeTester { static Set<ReturnTypeTester> set = new HashSet<ReturnTypeTester>(); static { ReturnTypeTester tester = new ReturnTypeTester(); set.add(tester); } public String getId() { return "id"; } } stack trace: java.lang.AbstractMethodError: ReturnTypeTester.getId()Ljava/lang/Object; at ReturnTypeTest.ajc$interMethod$ReturnTypeTest$ReturnTypeTest$Test$hashCode(ReturnTypeTest.java:16) at ReturnTypeTester.hashCode(ReturnTypeTester.java:1) at java.util.HashMap.hash(HashMap.java:264) at java.util.HashMap.put(HashMap.java:382) at java.util.HashSet.add(HashSet.java:194) at ReturnTypeTester.<clinit>(ReturnTypeTester.java:15)
I haven't been able to reproduce this bug this morning, I've tried variants both with all types in the same file, and with the types declared in separate files. Here's my test program, based on your input: import java.util.HashSet; import java.util.Set; aspect ReturnTypeTest { private interface Test { Object getId(); int hashCode(); } public int Test.hashCode() { System.out.println("in Test.hashCode()"); return getId().hashCode(); } declare parents : ReturnTypeTester implements Test; } class ReturnTypeTester { static Set<ReturnTypeTester> set = new HashSet<ReturnTypeTester>(); static { ReturnTypeTester tester = new ReturnTypeTester(); set.add(tester); } public String getId() { return "id"; } } public class pr105479part2 { public static void main(String[] args) { ReturnTypeTester rtt = new ReturnTypeTester(); rtt.hashCode(); System.out.println(rtt.getId()); if (rtt.hashCode() != "id".hashCode()) throw new RuntimeException("dispatch failure"); } } and the test specification: <ajc-test dir="bugs150" pr="105479" title="override and covariance with decp - runtime"> <compile files="pr105479part2.aj" options="-1.5"/> <run class="pr105479part2"> <stdout> <line text="in Test.hashCode()"/> <line text="in Test.hashCode()"/> <line text="id"/> <line text="in Test.hashCode()"/> </stdout> </run> </ajc-test> Is there anything else present in your application that could be contributing to triggering the bug? Some advice applying to one of the methods involved perhaps? Does the program in this comment compile and run for you successfully giving the expected output? Thanks, Adrian.
We'd like to get a fix for this into 1.5.0 RC1 if we can, but need to be able to reproduce the failure first. Are you doing any binary weaving in this scenario perhaps??
Sorry I've not had more time to address this. I do compile-time binary weaving. I will send more info after I make sure no other advice affects this class, but in the meantime here is a new version of the test class (the advice is unchanged) and the resulting output. public class ReturnTypeTester { static Set<ReturnTypeTester> set = new HashSet<ReturnTypeTester>(); public static void main(String[] args ) { ReturnTypeTester tester = new ReturnTypeTester(); Class[] classes = tester.getClass().getInterfaces(); for(Class clas : classes) { System.out.println("clas " + clas); } Method[] methods = tester.getClass().getMethods(); for(Method method : methods) { System.out.println("method " + method); } Field[] fields = tester.getClass().getFields(); for(Field field : fields) { System.out.println("field " + field); } System.out.println("here"); tester.hashCode(); System.out.println(tester.getId()); if (tester.hashCode() != "id".hashCode()) throw new RuntimeException("dispatch failure"); set.add(tester); } public String getId() { return "id"; } } clas interface ReturnTypeTest$Test method public int ReturnTypeTester.hashCode() method public static void ReturnTypeTester.main(java.lang.String[]) method public java.lang.String ReturnTypeTester.getId() method public final native java.lang.Class java.lang.Object.getClass() method public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException method public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException method public final void java.lang.Object.wait() throws java.lang.InterruptedException method public boolean java.lang.Object.equals(java.lang.Object) method public final native void java.lang.Object.notify() method public final native void java.lang.Object.notifyAll() method public java.lang.String java.lang.Object.toString() method public abstract java.lang.Object aspects.ReturnTypeTest$Test.getId() here java.lang.AbstractMethodError: ReturnTypeTester.getId()Ljava/lang/Object; at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:172) at org.apache.tools.ant.taskdefs.Java.run(Java.java:705) at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:178) at org.apache.tools.ant.taskdefs.Java.execute(Java.java:84) at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275) at org.apache.tools.ant.Task.perform(Task.java:364) at org.apache.tools.ant.Target.execute(Target.java:341) at org.apache.tools.ant.Target.performTasks(Target.java:369) at org.apache.tools.ant.Project.executeTarget(Project.java:1214) at org.apache.tools.ant.Project.executeTargets(Project.java:1062) at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:234) at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:242) at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:125) Caused by: java.lang.AbstractMethodError: ReturnTypeTester.getId()Ljava/lang/Object; at aspects.ReturnTypeTest.ajc$interMethod$aspects_ReturnTypeTest$aspects_ReturnTypeTest$Test$hashCode(ReturnTypeTest.java:20) at ReturnTypeTester.hashCode(ReturnTypeTester.java:1) at ReturnTypeTester.main(ReturnTypeTester.java:35) 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:585) at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:193) at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:130) ... 12 more --- Nested Exception --- java.lang.AbstractMethodError: ReturnTypeTester.getId()Ljava/lang/Object; at aspects.ReturnTypeTest.ajc$interMethod$aspects_ReturnTypeTest$aspects_ReturnTypeTest$Test$hashCode(ReturnTypeTest.java:20) at ReturnTypeTester.hashCode(ReturnTypeTester.java:1) at ReturnTypeTester.main(ReturnTypeTester.java:35) 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:585) at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:193) at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:130) at org.apache.tools.ant.taskdefs.Java.run(Java.java:705) at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:178) at org.apache.tools.ant.taskdefs.Java.execute(Java.java:84) at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275) at org.apache.tools.ant.Task.perform(Task.java:364) at org.apache.tools.ant.Target.execute(Target.java:341) at org.apache.tools.ant.Target.performTasks(Target.java:369) at org.apache.tools.ant.Project.executeTarget(Project.java:1214) at org.apache.tools.ant.Project.executeTargets(Project.java:1062) at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:234) at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:242) at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:125)
Created attachment 28941 [details] jar containing aspect and test class rtt.jar with just test class and aspect produces the exception for me when using the ant target below. <target name="run" description="run"> <java classname="com.imageworks.ejb.ReturnTypeTester"> <classpath> <path refid="aspectj.jars"/> <pathelement location="rtt.jar" /> </classpath> </java> </target>
Ok. This appears to be a missing bridge method. Because the signature of getId in the subtype is 'String getId()' and yet the signature on the interface was 'Object getId()' then we need to create a forwarding bridge method in the subtype called 'Object getId()' that simply delegates to 'String getId()'. If I disassemble the class file attached in the zip at the end of the bug, I find these set of methods in the type: public class com.imageworks.ejb.ReturnTypeTester extends java.lang.Object implem ents com.imageworks.ejb.aspects.rtt.ReturnTypeTest$Test{ static java.util.Set set; public com.imageworks.ejb.ReturnTypeTester(); public static void main(java.lang.String[]); public java.lang.String getId(); static {}; public int hashCode(); } with no bridge method. If I disassemble my version of the scenario, I get: public class ReturnTypeTester extends java.lang.Object implements ReturnTypeTest $Test{ static java.util.Set set; static {}; public ReturnTypeTester(); public java.lang.String getId(); public static void main(java.lang.String[]); public java.lang.Object getId(); <<<<<<<<<<<<<<<<<< here public int hashCode(); } see the extra bridge method for getId(). So... can I ask, what level of the compiler are you currently seeing the problem on (or what did you use to build your .class files for the zip?) also, you say you are doing 'compile-time binary weaving' - I'm not quite sure what that means. Are you binary weaving the aspect after compiling the two source files separately? If you are then I know why it fails - as this scenario fails for me exactly as you describe: javac ReturnTypeTester.java ajc ReturnTypeTest.java ajc -inpath . -d output then running the .class files in output: D:\temp\pr105479\poo>java ReturnTypeTester Exception in thread "main" java.lang.AbstractMethodError: ReturnTypeTester.getId ()Ljava/lang/Object; at ReturnTypeTest.ajc$interMethod$ReturnTypeTest$ReturnTypeTest$Test$has hCode(ReturnTypeTest.java:8) at ReturnTypeTester.hashCode(ReturnTypeTester.java:1) at java.util.HashMap.hash(HashMap.java:264) at java.util.HashMap.put(HashMap.java:382) at java.util.HashSet.add(HashSet.java:194) at ReturnTypeTester.<clinit>(ReturnTypeTester.java:8) and the reason it does is covered in bug 108101 case #3.
I've checked in a fix for the binary weaving case. We now correctly create the bridge method and it all works fine.
I have verified the bridge methods supporting covariance are inserted by ajc when weaving 'decp' relationships into javac-produced .class files. I usually do it this way--is there an advantage to building and weaving entirely with ajc? I usually do daily check out and builds of the ajc, and then 'test' it by building my applications. It's not a lot of support, but I deeply appreciate the oustanding work you guys are doing. Thanks, Reid. P.S. The signature of the bridge 'Object getId()' method is: method public volatile java.lang.Object com.imageworks.ejb.ReturnTypeTester.getId() What does volatile as a return-type modifier mean?
Some of the modifier flags are 'reused' here and there - the volatile is likely to be appearing as it clashes with the bridge modifier which I suspect has the same number (i dont have the spec to hand to check). So far sorting this out hasnt become urgent...so I haven't done it. If the compiler gets full control from the start from source through to woven .class files then it will make far fewer mistakes (bugs!) creating bridge methods. However it's very useful that you run the way you do since it highlights all the bugs in binary weaving ;) thanks for checking the fix.