Binary incompatible serializer changes

- If the field type is fixed and the type is final, Class info can be omitted
- Annotations serializer to use optimization based on the fact Map<String, String> and non-null key/value
- Reduce number of Map copy required for ImmutableMap serializer
- Reduce number of array copy behind Immutable{List, Set} serializer

Change-Id: Ie467a943a33fbfb43b289b8b71ad91ee5890bfb0
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/AnnotationsSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/AnnotationsSerializer.java
index bcb81a4..3082a28 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/AnnotationsSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/AnnotationsSerializer.java
@@ -21,24 +21,48 @@
 import com.esotericsoftware.kryo.Serializer;
 import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
+import com.esotericsoftware.kryo.serializers.DefaultSerializers;
+import com.esotericsoftware.kryo.serializers.DefaultSerializers.StringSerializer;
+import com.esotericsoftware.kryo.serializers.MapSerializer;
 
 import java.util.HashMap;
+import java.util.Map;
 
 public class AnnotationsSerializer extends Serializer<DefaultAnnotations> {
 
+    private static final StringSerializer STR_SERIALIZER
+        = new DefaultSerializers.StringSerializer();
+
+    private static final MapSerializer MAP_SERIALIZER = stringMapSerializer();
+
+    /**
+     * Returns a MapSerializer for {@code Map<String, String>} with
+     * no null key or value.
+     *
+     * @return serializer
+     */
+    private static MapSerializer stringMapSerializer() {
+        MapSerializer serializer = new MapSerializer();
+        serializer.setKeysCanBeNull(false);
+        serializer.setKeyClass(String.class, STR_SERIALIZER);
+        serializer.setValuesCanBeNull(false);
+        serializer.setValueClass(String.class, STR_SERIALIZER);
+        return serializer;
+    }
+
     public AnnotationsSerializer() {
         super(false, true);
     }
 
     @Override
     public void write(Kryo kryo, Output output, DefaultAnnotations object) {
-        kryo.writeObject(output, object.asMap());
+        kryo.writeObject(output, object.asMap(), MAP_SERIALIZER);
     }
 
     @Override
     public DefaultAnnotations read(Kryo kryo, Input input, Class<DefaultAnnotations> type) {
         DefaultAnnotations.Builder b = DefaultAnnotations.builder();
-        HashMap<String, String> map = kryo.readObject(input, HashMap.class);
+        Map<String, String> map = kryo.readObject(input, HashMap.class, MAP_SERIALIZER);
         map.forEach((k, v) -> b.set(k, v));
 
         return b.build();
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultApplicationIdSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultApplicationIdSerializer.java
index 45e90c4..a930d07 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultApplicationIdSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultApplicationIdSerializer.java
@@ -36,14 +36,14 @@
 
     @Override
     public void write(Kryo kryo, Output output, DefaultApplicationId object) {
-        kryo.writeObject(output, object.id());
-        kryo.writeObject(output, object.name());
+        output.writeShort(object.id());
+        output.writeString(object.name());
     }
 
     @Override
     public DefaultApplicationId read(Kryo kryo, Input input, Class<DefaultApplicationId> type) {
-        short id = kryo.readObject(input, Short.class);
-        String name = kryo.readObject(input, String.class);
+        short id = input.readShort();
+        String name = input.readString();
         return new DefaultApplicationId(id, name);
     }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/DeviceIdSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/DeviceIdSerializer.java
index 65f5695..063b82b 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/DeviceIdSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/DeviceIdSerializer.java
@@ -27,6 +27,12 @@
 */
 public final class DeviceIdSerializer extends Serializer<DeviceId> {
 
+    private static final DeviceIdSerializer INSTANCE = new DeviceIdSerializer();
+
+    public static final DeviceIdSerializer deviceIdSerializer() {
+        return INSTANCE;
+    }
+
     /**
      * Creates {@link DeviceId} serializer instance.
      */
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableListSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableListSerializer.java
index b5bd490..95aa4ad 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableListSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableListSerializer.java
@@ -20,7 +20,6 @@
 import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
 
 /**
  * Creates {@link ImmutableList} serializer instance.
@@ -44,12 +43,19 @@
 
     @Override
     public ImmutableList<?> read(Kryo kryo, Input input,
-            Class<ImmutableList<?>> type) {
+                                 Class<ImmutableList<?>> type) {
         final int size = input.readInt();
-        Builder<Object> builder = ImmutableList.builder();
-        for (int i = 0; i < size; ++i) {
-            builder.add(kryo.readClassAndObject(input));
+        switch (size) {
+        case 0:
+            return ImmutableList.of();
+        case 1:
+            return ImmutableList.of(kryo.readClassAndObject(input));
+        default:
+            Object[] elms = new Object[size];
+            for (int i = 0; i < size; ++i) {
+                elms[i] = kryo.readClassAndObject(input);
+            }
+            return ImmutableList.copyOf(elms);
         }
-        return builder.build();
     }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableMapSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableMapSerializer.java
index 87d9064..c527683 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableMapSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableMapSerializer.java
@@ -15,24 +15,20 @@
  */
 package org.onosproject.store.serializers;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Map.Entry;
 
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.Serializer;
 import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
-import com.esotericsoftware.kryo.serializers.MapSerializer;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 
 /**
 * Kryo Serializer for {@link ImmutableMap}.
 */
 public class ImmutableMapSerializer extends Serializer<ImmutableMap<?, ?>> {
 
-    private final MapSerializer mapSerializer = new MapSerializer();
-
     /**
      * Creates {@link ImmutableMap} serializer instance.
      */
@@ -43,16 +39,31 @@
 
     @Override
     public void write(Kryo kryo, Output output, ImmutableMap<?, ?> object) {
-        // wrapping with unmodifiableMap proxy
-        // to avoid Kryo from writing only the reference marker of this instance,
-        // which will be embedded right before this method call.
-        kryo.writeObject(output, Collections.unmodifiableMap(object), mapSerializer);
+        output.writeInt(object.size());
+        for (Entry<?, ?> e : object.entrySet()) {
+            kryo.writeClassAndObject(output, e.getKey());
+            kryo.writeClassAndObject(output, e.getValue());
+        }
     }
 
     @Override
     public ImmutableMap<?, ?> read(Kryo kryo, Input input,
                                     Class<ImmutableMap<?, ?>> type) {
-        Map<?, ?> map = kryo.readObject(input, HashMap.class, mapSerializer);
-        return ImmutableMap.copyOf(map);
+        final int size = input.readInt();
+        switch (size) {
+        case 0:
+            return ImmutableMap.of();
+        case 1:
+            return ImmutableMap.of(kryo.readClassAndObject(input),
+                                   kryo.readClassAndObject(input));
+
+        default:
+            Builder<Object, Object> builder = ImmutableMap.builder();
+            for (int i = 0; i < size; ++i) {
+                builder.put(kryo.readClassAndObject(input),
+                            kryo.readClassAndObject(input));
+            }
+            return builder.build();
+        }
     }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableSetSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableSetSerializer.java
index 814f988..66251e1 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableSetSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableSetSerializer.java
@@ -15,14 +15,10 @@
  */
 package org.onosproject.store.serializers;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.Serializer;
 import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
-import com.esotericsoftware.kryo.serializers.CollectionSerializer;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -30,26 +26,37 @@
 */
 public class ImmutableSetSerializer extends Serializer<ImmutableSet<?>> {
 
-    private final CollectionSerializer serializer = new CollectionSerializer();
-
     /**
      * Creates {@link ImmutableSet} serializer instance.
      */
     public ImmutableSetSerializer() {
         // non-null, immutable
         super(false, true);
-        serializer.setElementsCanBeNull(false);
     }
 
     @Override
     public void write(Kryo kryo, Output output, ImmutableSet<?> object) {
-        kryo.writeObject(output, object.asList(), serializer);
+        output.writeInt(object.size());
+        for (Object e : object) {
+            kryo.writeClassAndObject(output, e);
+        }
     }
 
     @Override
     public ImmutableSet<?> read(Kryo kryo, Input input,
                                 Class<ImmutableSet<?>> type) {
-        List<?> elms = kryo.readObject(input, ArrayList.class, serializer);
-        return ImmutableSet.copyOf(elms);
+        final int size = input.readInt();
+        switch (size) {
+        case 0:
+            return ImmutableSet.of();
+        case 1:
+            return ImmutableSet.of(kryo.readClassAndObject(input));
+        default:
+            Object[] elms = new Object[size];
+            for (int i = 0; i < size; ++i) {
+                elms[i] = kryo.readClassAndObject(input);
+            }
+            return ImmutableSet.copyOf(elms);
+        }
     }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/MastershipTermSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/MastershipTermSerializer.java
index 9ef9e8c..97fd60a 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/MastershipTermSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/MastershipTermSerializer.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.store.serializers;
 
+import static org.onosproject.store.serializers.NodeIdSerializer.nodeIdSerializer;
+
 import org.onosproject.cluster.NodeId;
 import org.onosproject.mastership.MastershipTerm;
 
@@ -26,7 +28,7 @@
 /**
  * Kryo Serializer for {@link org.onosproject.mastership.MastershipTerm}.
  */
-public class MastershipTermSerializer extends Serializer<MastershipTerm> {
+public final class MastershipTermSerializer extends Serializer<MastershipTerm> {
 
     /**
      * Creates {@link MastershipTerm} serializer instance.
@@ -38,14 +40,14 @@
 
     @Override
     public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) {
-        final NodeId node = (NodeId) kryo.readClassAndObject(input);
+        final NodeId node = kryo.readObjectOrNull(input, NodeId.class, nodeIdSerializer());
         final long term = input.readLong();
         return MastershipTerm.of(node, term);
     }
 
     @Override
     public void write(Kryo kryo, Output output, MastershipTerm object) {
-        kryo.writeClassAndObject(output, object.master());
+        kryo.writeObjectOrNull(output, object.master(), nodeIdSerializer());
         output.writeLong(object.termNumber());
     }
 }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/NodeIdSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/NodeIdSerializer.java
index 0c5a44c..19e8610 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/NodeIdSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/NodeIdSerializer.java
@@ -27,6 +27,12 @@
  */
 public final class NodeIdSerializer extends Serializer<NodeId> {
 
+    private static final NodeIdSerializer INSTANCE = new NodeIdSerializer();
+
+    public static final NodeIdSerializer nodeIdSerializer() {
+        return INSTANCE;
+    }
+
     /**
      * Creates {@link NodeId} serializer instance.
      */
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/PortNumberSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/PortNumberSerializer.java
index c890599..ad5f4f1 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/PortNumberSerializer.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/PortNumberSerializer.java
@@ -25,8 +25,7 @@
 /**
  * Serializer for {@link PortNumber}.
  */
-public final class PortNumberSerializer extends
-        Serializer<PortNumber> {
+public final class PortNumberSerializer extends Serializer<PortNumber> {
 
     /**
      * Creates {@link PortNumber} serializer instance.