The answer to my own question follows.
(Responses from those who understand the VM's initialization rules better than I are
most welcome.)
By adding the following bit of debugging code:
static {
System.out.println("### Code ### Initializing class");
for(int i=0;i<PRIVATE_VALUES.length;i++) {
System.out.println("### Code ### PRIVATE_VALUES["+i+"] = " +
PRIVATE_VALUES[i] );
}
}
I observed this on the client side:
### Code ### Initializing class
### Code ### PRIVATE_VALUES[0] = null
### Code ### PRIVATE_VALUES[1] = null
### Code ### PRIVATE_VALUES[2] = null
"Ah-ha," says I...
The static attributes in the outer class, namely:
public static final Code EXCEPTION = new Code(0,"EXCEPTION");
public static final Code FILTER_DENY = new Code(1,"FILTER_DENY");
public static final Code NOT_EMPTY = new Code(2,"NOT_EMPTY");
are "partially" evaluated by the time the following line in the static inner class is
hit:
private static final Code[] PRIVATE_VALUES = { EXCEPTION, FILTER_DENY,
NOT_EMPTY };
I say "partially" because, when the constants are encountered in the above line,
1) They do not cause a compile-time or run-time exception
2) They result in the array being initialized with the correct number of
elements
but...
3) The constants have not been assigned values.
By the time they are fully initialized, it is too late, and our array, PRIVATE_VALUES,
is stuck with nulls as its elements.
Once the problem was understood, the fix was trivial: move the three constant
declaration lines down into the inner class, and (to avoid public API changes) put the
following lines in their place.
public static final Code EXCEPTION = Code.EXCEPTION;
public static final Code FILTER_DENY = Code.FILTER_DENY;
public static final Code NOT_EMPTY = Code.NOT_EMPTY;
In the hopes that someone may benefit from my fumblings,
Ken
> -----Original Message-----
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] On Behalf Of Kenneth Sizer
> Sent: Saturday, June 12, 2004 11:01 PM
> To: [EMAIL PROTECTED]
> Subject: [Juglist] Q: Static inner class and Serialization
>
>
> The context:
> > I have a serializable class. It has 3 attributes. When
> deserialized
> > on the other end of an RMI connection, 2 of the attributes
> are intact,
> > one is null. The one that is lost is a typesafe enum (al la Bloch)
> > and a static inner class.
> >
> I'm assuming that either:
> (a) I'm simply ignorant of something obvious and stupid
> (e.g., a private instance variable with a name ending in "e"
> is implicitly transient), or
> (b) There is something clever and subtle about the
> combination of serialization, typesafe enums and static inner classes.
>
> Either way, if anyone out there has fallen into this same
> pit, I'd appreciate a word of wisdom about now.
>
> Thanks,
> Ken
>
> P.S.
> Sample code follows...
>
> > public class OperationResult implements Serializable {
> // constants
> > public static final Code EXCEPTION = new Code(0,"Exception");
> > public static final Code FILTER_DENY = new
> Code(1,"Filter Deny");
> > public static final Code NOT_EMPTY = new Code(2,"Not Empty");
> >
> // attributes
> private String myPathUrlStr; // works fine
> > private Code myCode; // is always null on
> deserialization!
> > private Exception myException; // works fine
> > :
> // getters, toString and such
> > :
> // typesafe enum inner class
> > public static final class Code implements Serializable {
> >
> > private static final Code[] PRIVATE_VALUES = {
> EXCEPTION,
> > FILTER_DENY, NOT_EMPTY };
> >
> > private final int myIndex;
> > private final String myValue;
> :
> :
> > private Object readResolve() throws
> java.io.ObjectStreamException {
> > Object retVal =
> PRIVATE_VALUES[myIndex];
> > return retVal;
> > }
> > }
> > }
> >
> >
>
> _______________________________________________
> Juglist mailing list
> [EMAIL PROTECTED]
> http://trijug.org/mailman/listinfo/juglist_tri> jug.org
>
_______________________________________________
Juglist mailing list
[EMAIL PROTECTED]
http://trijug.org/mailman/listinfo/juglist_trijug.org