Fix NoSuchElementException reported in ONOS-4763 and ONOS-4757

Change-Id: I973b6c33f02defac3463b6e53ea177056f1f9714
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
index 7ec9de0..a6a7d08 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
@@ -98,14 +98,25 @@
     public DiscreteResources difference(DiscreteResources other) {
         if (other instanceof EncodableDiscreteResources) {
             EncodableDiscreteResources cast = (EncodableDiscreteResources) other;
-            Map<Class<?>, EncodedDiscreteResources> newMap =
-                    Stream.concat(this.map.entrySet().stream(), cast.map.entrySet().stream())
-                            .filter(entry -> this.map.containsKey(entry.getKey()))
-                            .collect(Collectors.toMap(
-                                    Map.Entry::getKey,
-                                    Map.Entry::getValue,
-                                    EncodedDiscreteResources::difference,
-                                    LinkedHashMap::new));
+
+            Map<Class<?>, EncodedDiscreteResources> newMap = new LinkedHashMap<>();
+            for (Class<?> key : this.map.keySet()) {
+                EncodedDiscreteResources thisValues = this.map.get(key);
+                if (!cast.map.containsKey(key)) {
+                    newMap.put(key, thisValues);
+                    continue;
+                }
+                EncodedDiscreteResources otherValues = cast.map.get(key);
+                EncodedDiscreteResources diff = thisValues.difference(otherValues);
+                // omit empty resources from a new resource set
+                // empty EncodedDiscreteResources can't deserialize due to
+                // inability to reproduce a Class<?> instance from the serialized data
+                if (diff.isEmpty()) {
+                    continue;
+                }
+                newMap.put(key, diff);
+            }
+
             return of(parent, newMap);
         } else if (other instanceof EmptyDiscreteResources) {
             return this;
diff --git a/core/store/dist/src/test/java/org/onosproject/store/resource/impl/EncodableDiscreteResourcesTest.java b/core/store/dist/src/test/java/org/onosproject/store/resource/impl/EncodableDiscreteResourcesTest.java
index 40f20b6..31285d94 100644
--- a/core/store/dist/src/test/java/org/onosproject/store/resource/impl/EncodableDiscreteResourcesTest.java
+++ b/core/store/dist/src/test/java/org/onosproject/store/resource/impl/EncodableDiscreteResourcesTest.java
@@ -18,16 +18,19 @@
 
 import com.google.common.collect.ImmutableSet;
 import org.junit.Test;
+import org.onlab.packet.VlanId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.resource.DiscreteResource;
 import org.onosproject.net.resource.Resources;
 import org.onosproject.store.service.Serializer;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
@@ -83,6 +86,30 @@
     }
 
     @Test
+    public void testSerializeInstanceContainingEmptyEncodedDiscreteResources() {
+        DiscreteResource device = Resources.discrete(DeviceId.deviceId("a")).resource();
+        List<PortNumber> ports = IntStream.range(0, 1)
+                .mapToObj(PortNumber::portNumber)
+                .collect(Collectors.toList());
+        List<VlanId> vlans = IntStream.range(0, 2)
+                .mapToObj(x -> VlanId.vlanId((short) x))
+                .collect(Collectors.toList());
+
+        Set<DiscreteResource> originalResources = Stream.concat(ports.stream(), vlans.stream())
+                .map(device::child)
+                .collect(Collectors.toSet());
+        DiscreteResources sut = EncodableDiscreteResources.of(originalResources);
+
+        Set<DiscreteResource> portOnlyResources = ports.stream().map(device::child).collect(Collectors.toSet());
+        DiscreteResources other = EncodableDiscreteResources.of(portOnlyResources);
+
+        DiscreteResources diff = sut.difference(other);
+
+        byte[] bytes = serializer.encode(diff);
+        assertThat(serializer.decode(bytes), is(diff));
+    }
+
+    @Test
     public void testIfDifferenceIsNotEmpty() {
         DiscreteResource res1 = Resources.discrete(DeviceId.deviceId("a"), PortNumber.portNumber(1)).resource();
         DiscreteResource res2 = Resources.discrete(DeviceId.deviceId("a"), PortNumber.portNumber(2)).resource();