Community
Participate
Working Groups
I stumbled over a very peculiar bug: I had refactored a static local class out into a file of its own. In the process eclipse obviously also modified the visibility of the two methods private void writeObject(ObjectOutputStream out) { ... } private void readObject(ObjectInputStream in) { ... } to package visibility, i.e.: void writeObject(ObjectOutputStream out) { ... } void readObject(ObjectInputStream in) { ... } But these two methods are used for (de)serialization and obviously, for proper (de)serialization, the *private* visibility of these methods is important! If the methods are not private, they will not be called at all. I thus ran into the strange problem that fields of a class were null, even though they had NOT been null before serializing them. And the (de-)serialization (at first) did not appear to be the culprit, since it had always worked perfectly before the refactoring. I recall that eclipse popped up a list of possible problems, among them that it was going to change the visibility of the "constructors" writeObject() & readObject() to default, but those warnings were obviously not enough to make me aware of the consequence, that these methods were going to be turned into useless, dead code... Summarizing: the refactoring MUST ABSOLUTELY NOT modify the visibility of these two very special methods! Michael
I guess other refactorings have to be handling this case too. Markus, Tobias can you coordinate?
We can modify this behaviour (changing visibility) for all refactorings in the MemberVisibilityAdjustor by excluding special methods. Other refactorings which probably should be more aware of special methods are: - Rename method - Change method signature Those refactoring could issue a warning since they are not behavior preserving on special methods.
I don't see why moving a class should ever have to change the visibility of these private methods. Michael, could you please post a small example where this occurs and tell exactly which refactoring you applied? Note: there are no static local classes in Java. Either a class is local (declared inside a method, always non-static), or it is static (either top-level or nested), but not both. I filed bug 120836 for Rename Method, Change Method Signature, and Introduce Parameter. Tobias, please also check Pull Up and Push Down.
Please find an example below. To demonstrate the error: compile and run A - you should see: -------------- before: foo after: foo -------------- Then select class B and do a Refactor => Move Member Type to New File. run A again - now you will see: -------------- before: foo after: null <<<<<<<<<<<<<< -------------- <<<<<<<<<<< shows, that the non-private writeObject/readObject methods have not been called! Note, that to demonstrate the effect the class to be serialized has to have one or more transient fields! The default (de-)serialization methods (which are called since the non-private methods are ignored) handle non-transient fields properly and then one would not even notice, that the refactored writeObject/readObject methods are not called any more... /** * @author Michael Moser (mmo@zurich.ibm.com) * @since Dec. 15, 2005 */ package test; import java.io.*; public class A { public static void main(String[] args) throws Exception { B b = new B("foo"); System.out.println("before: " + b); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(baos); os.writeObject(b); os.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream is = new ObjectInputStream(bais); b = (B)is.readObject(); System.out.println("after: " + b); } static class B implements Serializable { final static long serialVersionUID = 1L; transient String str; // note: the transient is important to show the effect! B(String str) { this.str = str; } private void writeObject(final ObjectOutputStream out) throws IOException { out.writeObject(this.str); } private void readObject(final ObjectInputStream in) throws IOException { try { this.str = (String)in.readObject(); } catch (ClassNotFoundException ex) { ex.printStackTrace(); throw new IOException("exception: " + ex); } } public String toString() { return this.str; } } } Hope that helps! Michael
> ... Note: there are no static local classes in Java... You are absolutely right! Pardon my sloppy use of terms. Michael
> Pardon my sloppy use of terms. No problem, I just wanted to make sure we're talking about the same thing ;-) Now, this looks like a dup of bug 97411.
Filed bug 120895 for pull up and push down *** This bug has been marked as a duplicate of 97411 ***