Bug 147690 - [1.5][compiler] Incompatible serialversionuid when using covariant in Java 1.5
Summary: [1.5][compiler] Incompatible serialversionuid when using covariant in Java 1.5
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.2.1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-06-19 04:25 EDT by Heiko Zimmermann CLA
Modified: 2006-09-12 03:48 EDT (History)
0 users

See Also:


Attachments
Proposed patch (4.94 KB, patch)
2006-06-20 16:39 EDT, Philipe Mulet CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Heiko Zimmermann CLA 2006-06-19 04:25:37 EDT
We compile using Eclipse JDK compliance 5.0 and have some classes which uses covariant feature in Java 1.5 f.e. for the clone()-Method. Our server components compiled using ant with target=1.5 using external jdk1.5._04 from sun. After deploying server-components to JBoss-Server and starting Client-Application from within Eclipse, we got incompatible serialversionuid exceptions from those classes which were using clone() as an covariant.
After an decompilation and compare of classes from Eclipse and Sun jdk1.5._04 we found the difference in the compiler generated method:

   protected volatile Object clone()
        throws CloneNotSupportedException
    {
        return clone();
    }

which was marked as "protected" from Eclipse-compiler and was "public" from sun's jdk. So the serialversionuid can't be identical, i think the method must be public, is that a bug in Eclipse? 

Thanks in advance,
Heiko
Comment 1 Philipe Mulet CLA 2006-06-20 04:31:59 EDT
If the #clone() declaration is tagged as protected, then it must be generated as such. Also note that 'volatile' is not allowed for methods.

Please provide a complete example reproducing the issue.
Comment 2 Heiko Zimmermann CLA 2006-06-20 04:49:09 EDT
(In reply to comment #1)
> If the #clone() declaration is tagged as protected, then it must be generated
> as such. Also note that 'volatile' is not allowed for methods.
> Please provide a complete example reproducing the issue.

We've not implemented the code snippet (... protected volatile clone()) this was code we've decompiled from the generated class file.
The implemented code looks like:

@Override
	public SEPlatzierung clone() {...}

and compiler adds covariant function:

   protected volatile Object clone()
        throws CloneNotSupportedException
    {
        return clone();
    }




Comment 3 Heiko Zimmermann CLA 2006-06-20 15:38:36 EDT
Here an simple example source:

import java.io.Serializable;
public class MyClass implements Serializable {
	
	private Long member;
	
	public MyClass(){
	}
	
	@Override
	public MyClass clone(){
		MyClass clone = new MyClass();
		clone.setMember(new Long(member));
		return clone();
	}

	public Long getMember() {
		return member;
	}

	public void setMember(Long nValue) {
		member = nValue;
	}
}

After compilation in Eclipse the decompiled code from classfile:

import java.io.Serializable;

public class MyClass
    implements Serializable
{

    public MyClass()
    {
    }

    public MyClass clone()
    {
        MyClass clone = new MyClass();
        clone.setMember(new Long(member.longValue()));
        return clone();
    }

    public Long getMember()
    {
        return member;
    }

    public void setMember(Long long1)
    {
        member = long1;
    }

    protected volatile Object clone()
        throws CloneNotSupportedException
    {
        return (Object)clone();
    }

    private Long member;
}

The same sourcefile compiled with sun jdk1.5.0_04, here the decompiled code:
import java.io.Serializable;

public class MyClass
    implements Serializable
{

    public MyClass()
    {
    }

    public MyClass clone()
    {
        MyClass myclass = new MyClass();
        myclass.setMember(new Long(member.longValue()));
        return clone();
    }

    public Long getMember()
    {
        return member;
    }

    public void setMember(Long long1)
    {
        member = long1;
    }

    public volatile Object clone()
        throws CloneNotSupportedException
    {
        return clone();
    }

    private Long member;
}

Comment 4 Olivier Thomann CLA 2006-06-20 15:55:28 EDT
This method is not volatile. This is a bridge method. ACC_VOLATILE and ACC_BRIDGE are equal, so this is why it is shown as volatile.
javac generates the bridge method as public and we generate it as protected.

Kent,

should we preserve the visibility of the method called by the bridge method?

For the serial version id exception, you should define a serial version UID field for every serializable class. This is highly recommended. If you don't, then your serialized instances are compiler-dependent whatever the current behavior is right or not.
There is no specification for some access emulation with regards to inner classes accesses and these access methods have a side-effect on the serial version uid.
Comment 5 Philipe Mulet CLA 2006-06-20 16:08:29 EDT
We should indeed use the modifiers from the covariant method when generating a bridge method.

class XSuper {
	Object foo() { return null; }
	protected Object bar() { return null; }
}
public class X extends XSuper {
	protected String foo() { return null; }
	public String bar() { return null; }
}
Comment 6 Philipe Mulet CLA 2006-06-20 16:39:57 EDT
Created attachment 44952 [details]
Proposed patch
Comment 7 Philipe Mulet CLA 2006-06-20 16:41:04 EDT
Released fix for 3.2.1 (TARGET_321)
Released fix for 3.3M1 (HEAD)

Added MethodVerifyTest#test090
Comment 8 Olivier Thomann CLA 2006-06-21 11:31:43 EDT
Fixing this doesn't prevent you from defining the serialVersionUID field.
Comment 9 Frederic Fusier CLA 2006-08-08 09:25:30 EDT
Verified for 3.3 M1 using build I20060807-2000.
Comment 10 David Audel CLA 2006-09-12 03:48:18 EDT
Verified for 3.2.1 using build M20060908-1655