Skip to content

Serialization FAQ

Andrei Pangin edited this page Sep 2, 2016 · 7 revisions

Q: Which classes can be serialized and which can not?

A: All classes implementing either Serializable, Externalizable, Collection or Map interface can be serialized. Technically all other classes also could be, but the limitation is introduced intentionally to decrease the possibility of mistakes.


Q: What if an object has non-serializable type of a field, e.g. java.lang.Object?

A: The type of the field does not matter. What makes sense is the type of the specific object residing in this field. If it is serializable, then everything is OK.


Q: Do I need to specify serialVersionUID? What does it affect?

A: serialVersionUID is simply ignored in one-nio. It can be safely removed.


Q: How is the unique ID of the class calculated then?

A: Unique ID (UID) is given not to the class, but to the serializer. One class can have multiple serializers: one native (built from the local version of the class), and any number of external serializers (received from other servers with different version of this class).

UID is calculated as a hash function of names, types and the order of instance fields.


Q: Which fields are serialized?

A: All non-static and non-transient fields, just like in standard Java serialization.


Q: Does a class need to have a public constructor or a default constructor in order to be deserializable?

A: No. No constructor is called during deserialization, except for collections and maps (see below).


Q: Is custom serialization via readObject/writeObject supported?

A: There is limited support for readObject/writeObject. These methods will be called, but they should not work with the stream directly. The only stream methods they may call are defaultReadObject and defaultWriteObject. Other calls will result in exception.

readObject/writeObject may be used for data preparation, e.g. for filling transient fields after deserialization. For more flexible serialization use Externalizable interface.


Q: Is custom serialization via readExternal/writeExternal supported?

A: Yes. Externalizable is completely supported.


Q: I get java.lang.NoSuchMethodError: sun.misc.Unsafe.copyMemory.

A: Please update JDK to version 6u26 or newer.


Q: I’ve got problems with serialization of java.sql.Date and java.sql.Time instances.

A: All fields of these classes are transient, therefore our serialization does not work. Please use java.util.Date or java.sql.Timestamp which have dedicated serializers in one-nio.


Q: Is there much difference between serializing primitives and wrappers?

A: There difference in footprint is minimal: wrappers have one extra byte for the header. For example, long occupies 8 bytes while Long will take 9 bytes. There will be a slight difference in speed, so, if you don’t expect nulls, the primitives are preferred.


Q: What kind of field modifications in a class are backward compatible?

A:

  1. Addition of a new field (which will be initialized with 0 or null);
  2. Field removal (received value for this field will be ignored);
  3. Field reordering;
  4. Field type changes (see below);
  5. Field renaming (when annotated with @Renamed).

Q: How to rename a field of a serializable class correctly?

A:

class MyClass {
    @Renamed(from = "oldName")
    String newName;
}

(!) It is not recommended to mix field renaming with other modifications in a single software release deployment.

(i) After successful deployment of a new version, as soon as all servers and clients obtain the class with the field renamed, this annotation can be removed.


Q: I want to rename a class involved in serialization.

A: You can do this, if you add @Renamed annotation with the fully qualified old name:

package one.comp.somepackage;
 
@Renamed(from = "one.comp.somepackage.OldClass")
class NewClass { ... }

(!) Do not rename classes occuring in signatures of remote methods. Otherwise there will be no backward compatibility of the remote service.

(i) After successful deployment of a new version, as soon as all servers and clients obtain the class with the field renamed, this annotation can be removed.


Q: Is it possible to move a class to a different package?

A: Yes. The @Renamed annotation is required in this case.

package one.comp.newpackage;
 
@Renamed(from = "one.comp.oldpackage.MovedClass")
class MovedClass { ... }

Q: Is it allowed to change the class hierarchy? Will the old class MyClass be compatible with the new MyClass extends NewParent or MyClass implements NewInterface?

A: Yes, these kinds of changes are allowed.


Q: Do the changes in class methods affect its serialization?

A: No. It is possible to add, remove and rename methods without losing backward compatibility in respect to serialization.


Q: What happens if I change a name or a signature of a remote method?

A: The new method will be incompatible with an old one. In order to do such kind of refactoring, create a new method (with different name or signature) without removing an old one. After an successful deployment of a new version, when the old method is not used any more, it can be safely removed. We will probably add @Renamed annotation support for methods in the future.


Q: Can I change the return type of a remote method?

A: You can do so in two cases:

  1. if the method was void, or if it always returned null;
  2. if the new type and the old type belong to the same class hierarchy, i.e. one is the parent of another.

Q: One side has started to send newly added class over remoting. Will it work fine?

A: Yes, it is possible to add a field of a new class. While it is null, both sides can communicate well, even if one side has no this class locally. However as soon as the real instances of the new class start to travel over remoting, ClassNotFoundException will be thrown.


Q: The type of the field has changed and the name remained the same. How this will affect serialization?

A: It depends. The old type will be automatically converted to the new type in the following cases:

  1. The new type is the parent of the old type. No conversion is needed.
  2. The new type is inherited from the old type. The type cast will occur. If the type cast fails, ClassCastException will be thrown.
  3. A primitive type -> another primitive type. The value will be converted according to general Java language rules, e.g. (long) intValue, (byte) shortValue etc. boolean can also be converted to integer types: false <-> 0, true <-> 1.
  4. A primitive type -> the wrapper (e.g. long -> Long). This is a special case of #7: Long.valueOf(long).
  5. The wrapper -> a primitive (e.g. Integer -> int). This is a special case of #8: Integer.intValue().
  6. Number -> Number (e.g. Integer -> Long). The value will be converted through the intermediate primitive type.
  7. Invocation of public static NewClass valueOf(OldClass), if the method exists.
  8. Invocation of public NewClass anyMethodName(), if the method exists.

(i) If none of the rules above can be applied, no conversion is made. The changed field will be initialized with the default value: 0 or null.


Q: Is it possible to move a field from a parent class to a child or vice versa?

A: Yes, this is a compatible change. Anyway make sure there are no two fields with the same name.


Q: I want to move one or more fields fields to an auxiliary class Holder. What do I need to do?

A: There is a special trick for such a case. You need to call the method Repository.addInlinedClass("full.name.of.Holder") at the application initialization time. Then all fields of the Holder class will be inlined directly to the stream, so that the binary representation remains unchanged. Therefore the refactoring will be backward compatible.


Q: How is enum serialized? Is it allowed to change constant names, add, remove or reorder constants?

A: enums are encoded with 2-byte integer during serialization. one-nio does its best to resolve possible modifications:

  1. if a client and a server have enum constants reordered, the correct values will be matched by the constant names;
  2. if a constant is renamed but its position remained the same, the values will also be matched correctly;
  3. if one side receives a constant which it does not know, it will be silently replaced with null.

(!) To avoid conflicts, do not rename and reorder constants together within a single new release deployment.


Q: What is special about serialization of collections?

A: Classes implementing Collection interface are serialized like an array. The fields of the class do not matter.

The class should have a public default constructor in order to be deserialized. If there is no such a constructor, the class will be deserialized as an ArrayList, LinkedList, HashSet or a TreeSet, depending on implemented interfaces.


Q: What is special about serialization of maps?

A: Classes implementing Map interface are serialized as key-value pairs. The fields of the class do not matter.

The class should have a public default constructor in order to be deserialized. If there is no such a constructor, the class will be deserialized as a HashMap or a TreeMap, depending on whether it implements SortedMap interface.


Q: Where do I find if there are any serialization problems related to different versions of my application classes?

A: All detected version conflicts are printed to one.nio.serial.Repository logger. Look for the messages like

WARN  [one.nio.serial.Repository] [11d88aa11ca2e665] Local field is missed in stream: java.lang.Long one.comp.spam.ClientInfoMetadataImpl.currentUserId
WARN  [one.nio.serial.Repository] [13f21415e8cd1dd3] Stream field is missed locally: int odkl.index.query.ResultItem.audience
WARN  [one.nio.serial.Repository] Missed local enum constant one.image.server.persistence.ImageType.PROFILE_320
WARN  [one.nio.serial.Repository] Trying to serialize anonymous class: one.comp.groupphoto.dcache.DGroupPhotoCache$1

There is also serialization statistics available through JMX MBean one.nio.serial:type=Serialization


Q: How to print the serializer’s generated bytecode?

A: Run the JVM with the option -Done.nio.gen.dump=/path/to/generated/files

You’ll find the generated .class files in the given directory.


Q: Where to look further?

A: Slides - http://www.slideshare.net/AndreiPangin/pangin-highload

Presentation - http://www.youtube.com/watch?v=gIh0X-RkftY

Clone this wiki locally