Bug 118160 - Covariant return type in ITD produces bad class file
Summary: Covariant return type in ITD produces bad class file
Status: RESOLVED INVALID
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: DEVELOPMENT   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 1.5.0RC1   Edit
Assignee: Andrew Clement CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-27 15:54 EST by Ramnivas Laddad CLA
Modified: 2005-11-30 20:44 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ramnivas Laddad CLA 2005-11-27 15:54:17 EST
Using covariant return type feature through ITD causes ajc to produce 
bad code (which then causes reflection based usages, Hibernate in my case, to 
produce serious errors).

Here is a minimal program to reproduce the error:
// Entity.java
import java.io.Serializable;

public interface Entity {
	public Long getId();
}

class AnEntity implements Entity {
	public Long getId() {
		return null;
	}
}

aspect ManageEntity {
	declare parents: Entity implements EntityWithId;

	interface EntityWithId {
		public Serializable getId();
	}
}

> ajc -v
AspectJ Compiler DEVELOPMENT built on Friday Nov 25, 2005 at 18:17:07 GMT

> ajc -1.5 Entity.java

> javap AnEntity
Compiled from "Entity.java"
class AnEntity extends java.lang.Object implements Entity{
    AnEntity();
    public java.lang.Long getId();
    public java.io.Serializable getId();
}

Now there are two getId() methods with only return type difference, 
which is illegal in Java.
Comment 1 Andrew Clement CLA 2005-11-27 17:27:01 EST
I'll take a look tomorrow.
Comment 2 Andrew Clement CLA 2005-11-28 03:21:45 EST
Here is a pure java program:

import java.io.Serializable;

public interface Entity2 {
  public Long getId();
}

class AnEntity implements Entity2,EntityWithId {
  public Long getId() {
    return null;
  }
}

interface EntityWithId {
  public Serializable getId();
}

After compilation, if I 'javap AnEntity':

class AnEntity extends java.lang.Object implements Entity2,EntityWithId{
    AnEntity();
    public java.lang.Long getId();
    public java.io.Serializable getId();
}

You can have two methods that differ purely in return type - one has to be a bridge method that forwards to the other, here is implementation of the 'Serializable getId()' method: 

public java.io.Serializable getId();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokevirtual   #2; //Method getId:()Ljava/lang/Long;
   4:   areturn
  LineNumberTable:
   line 7: 0

It just calls the getId() returning a Long.  AspectJ is doing the same thing.

However ... there is *possibly* a bug that has concerned me for a while to do with how we tag methods as bridge methods.  Either: we aren't tagging them correctly for hibernate or hibernate doesn't understand bridge methods.  Ramnivas, can you try hibernate against a pure java case that results in bridge methods like the one above?
Comment 3 Andrew Clement CLA 2005-11-30 11:36:38 EST
Ramnivas, have you had a chance to try hibernate on the pure Java version of this that includes bridge methods?  We're in danger of missing fixing this for RC1 if there is a real problem lurking...
Comment 4 Ramnivas Laddad CLA 2005-11-30 20:44:20 EST
Good news! It is Hibernate's problem. I tried the same setup in plain Java and
got identical failure.

public interface SerializableEntity {
    public Serializable getId();
}

And then 
public class Entity implements SerializableEntity, Serializable {
	private Long _id;

	public Long getId() {
		return _id;
	}

	@SuppressWarnings("unused")
	private void setId(Long id) {
		_id = id;
	}
}

Therefore, marking this bug as "INVALID".

Thanks Andy for working on this. I will do more investigation and report to
Hibernate.