Advanced optimizations

By design Externalizer4J automatically optimizes the serialization logic of any existing class. Automatically here means without any additional coding effort or meta-data.

Externalizer4J is capable of more advanced optimization. By design these optimizations must be enabled explicitly through the ‘externalizer4j.properties’ file. Depending on the optimization the option can be enable using:

  • a global settings
  • annotation fields

Enable advanced optimizations

No-arg constructor generation

#
# To be Externalizable a class should have a no-arg constructor. Externalizaer4j can safely generate the bytecode for a
# no-arg constructor for classes that do not provide one. This is safe even for classes with final fields as long as all
# the fields get set during deserialization.
#
# In some rare cases this new no-arg constructor may interfere with frameworks which use reflection and function
# incorrectly with the no-arg constructor. If this case set this to false.
#
# default: true
#
canCreateNoArgConstructor=true

The ObjectOuputStream implementation in JDK requires that classes that implement the Externalizable interface provide a no-argument constructor. This constructor is used to instantiate new objects during deserialization.

Externalizer4j can generate a no-argument constructor for classes that do not provide one. This constructor will only appear in the bytecode and it won’t contain any logic. It will be visible through the reflection API. If this cause problems one can disable to by setting canCreateNoArgConstructor to false.

Additional speed optimizations

Externalizer4J provides additional optimizations that favour the serialization speed. Note that these optimizations can, in some cases, result in a slight increase in serialized size.

Given the very specific nature of these optimizations Externalizer4J has chosen for a declarative approach based on annotations. Making applications dependent on an Externalizer4J specific API  is not what one wants. Instead Externalizer4J can optimize classes using externally defined annotations.

In other words Externalizer4J does not come with predefined annotations! You must configure Externalizer4J to look for specific annotations. This is done simple by listing the fully qualified class name of the annotation(s) in the externalizer4j.properties file. Several annotations can be defined using a comma seperated list.

Note that you don’t necessarily need to define your own annotations. In some cases you can for example piggyback on annotations of existing frameworks. You can configure Externalizer4J to use JPA or Hibernate @Id annotations to optimize the serialization of such primary fields for instance. Please read the section about Object Uniqueness below.

Declaring annotations

If you prefer to declare you own annotations there are a few constraints for these annotations. The annotations should be:

  • present in the bytecode, i.e. define with either @Retention(RetentionPolicy.CLASS) [email protected](RetentionPolicy.RUNTIME)
  • Put on fields. Externalizer4J will ignore the annotation(s) when put on other elements (class, parameters)
  • listed in the externalizer4j.properties using the fully qualified class name

Object Uniqueness

The advanced optimizations focus on improving the speed. This is in part achieved by avoiding the object deduplication performed by ObjectOutputStream.writeObject(). If the optimizations are applied incorrectly this may result in a larger serialized output and more likely stack overflows during serialization! In other words do not annotate a field which refers to a object which gets shared by several objects.

The optimizations rely on the fact that the optimized objects are unique. Definition of an unique object:

An object is unique when there is only one reference to in the object graph.

When an object is unique it will not introduce cycles in the object graph. In other words it only be visited once during serialization. Therefore there will be no risk of stack overflows.

Optimize unique objects

 

#
# List of comma-separated fully qualified class name of annotations. These are used to further optimize the
# serialization speed of individual fields.
#
# When placed on fields these annnotations tell the optimization that the value of a field is a unique instance. When
# possible the optimization will safely avoid the costly lookup of previous references to the same instance.
#
# Optimizations exist for: String, Collection(*), Set(*), HashSet(*), List(*), ArrayList(*), Date
#
# (*) these instance must contain primitive type wrappers or classes that implement Externalizable
#
# One can define custom annotations but one can also used existing ones. Possible candidates are the JPA and Hibernate
# @Id and @EmbeddedId annotations for instance.
#
# IMPORTANT note: custom annotations should at least have RetentionPolicy.CLASS !!!
#
# IMPORTANT note: Externalizer4j does NOT provide default annotations for this purpose. This to avoid introducing a
# dependency in your code.
#
# default: none
# Example:
# uniquenessAnnotations=demo.serialization.UniqueObject
#
# class C {
# @UniqueObject Date d;
# @UniqueObject String name;
# @UniqueObject Collection flags;
# }
#
uniquenessAnnotations=demo.serialization.UniqueObject

A comma-separated list of fully qualified class names of annotations that will be used to indicate that a field is unique. Externalizer4J will use type specific optimizations for fields annotated with those annotations.

These optimizations include

  • Faster serialization of class of the Collection API:
    • Externalizer4J uses information of the generic parameter type to use the best optimization when available
    • Special optimizations for primitive wrappers are used. For example Externalizer4J will used a different optimization for List<Integer> than for List<Long>
    • Collections of Externalizable classes will be serialized using the writeExternal() method
  • Faster serialization of arrays
    • Arrays primitive serialized using type specific methods
    • Arrays of primitves wrappers are also serialized using type specific methods
    • Arrays of Externalizable classes will be serialized using the writeExternal() method

Optimize arrays of primitives

#
# Optimize the serialization speed of ALL arrays of primitives types like int[], short[], byte[], char[], ...
#
# This setting is equivalent to defining a uniquenessAnnotation (see above) and annotating all primitive array
# fields in all classes with it.
#
# default: false
#
alwaysOptimizePrimitiveArrays=false

Set to true all primitive arrays are serialized using a optimized implementation. The avoid the need to annotate primitive array fields. USE THIS OPTION WITH CARE

Nullness

#
# Annotations which indicates that the annotated field 
# will never be null
#
nonNullAnnotations=

A field which is never null does not need a null check during serialization. Externalizer4J will avoid generating such a check making things even faster. Incorrect use of this feature may result in NullPointException during serialization. USE THIS OPTION WITH CARE

#
# Annotations should be put on Collection fields only to indicate
# that the element within the collection are guaranteed to be
# never null
#
nonNullElementAnnotations=

During serialization each element in a Collection has to be checked for null. If a Collection field is annotated with such a Externalizer4J will avoid generating such checks to maximize performance. Incorrect use of this feature may result in NullPointException during serialization. USE THIS OPTION WITH CARE

Optimize Collection

#
# Optimize the serialization speed and size. of ALL Collection instance that contain primitive wrappers. For instance:
# Collection or List, ArrayList, Set<character&>, HashSet
#
# This setting is equivalent to defining a uniquenessAnnotation (see above) and annotating all Collection 
# fields in all classes with it.
#
# default: false
#
alwaysOptimizePrimitiveCollections=false

Set to true all Collections containing primitive wrapper classes are serialized using an optimized implementation. This avoid the need to annotate all fields refering to Collections of primitive wrapper classes. USE THIS OPTION WITH CARE

Optimize Date serialization

#
# Optimize the serialization speed of ALL Date fields.
#
# This setting is equivalent to defining a uniquenessAnnotation (see above) and annotating all Date fields in all
# classes with it.
#
# default: false
#
alwaysOptimizeDatesForSpeed=false

Externalizer4J can optimized the serialization of JDK Date implementations. This is restricted to java.util.Date, java.sql.Date and java.sql.Timestamp. If the Date field is not one of the JDK supplied subclass the default serialization will be used.