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();