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/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();
+        }
     }
 }