Validate augmentation binding class 61/72961/6
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 13 Jun 2018 14:34:39 +0000 (16:34 +0200)
committerRobert Varga <nite@hq.sk>
Tue, 19 Jun 2018 07:23:24 +0000 (07:23 +0000)
LazyDataObject's DataObject.augmentation(Class) implementation
needs to re-validate if the augmentation we are about to decode
matches user-requested augmentation.

This is needed to ensure that we do not return shape-equivalent
augmentation, such as when the same augmentation is applied to
multiple instantiations of the same grouping. In such a case
type-safety indicates that the grouping can have either of the
augmentations, yet in reality its validity depends on
instantiation.

JIRA: MDSAL-328
Change-Id: I57dd70ddead65fc7f61c72b58da4ef6d26e739f8
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyDataObject.java

index 85fd4c976ee907e139a172320011702e58fd56a6..79e26fcbe2f8c5bc780c3d6a25112ae10738000f 100644 (file)
@@ -181,18 +181,27 @@ class LazyDataObject<D extends DataObject> implements InvocationHandler, Augment
     }
 
     private Object getAugmentationImpl(final Class<?> cls) {
+        Preconditions.checkNotNull(cls, "Supplied augmentation must not be null.");
+
         final ImmutableMap<Class<? extends Augmentation<?>>, Augmentation<?>> aug = cachedAugmentations;
         if (aug != null) {
             return aug.get(cls);
         }
-        Preconditions.checkNotNull(cls,"Supplied augmentation must not be null.");
 
         @SuppressWarnings({"unchecked","rawtypes"})
-        final Optional<DataContainerCodecContext<?, ?>> augCtx = context.possibleStreamChild((Class) cls);
-        if (augCtx.isPresent()) {
-            final java.util.Optional<NormalizedNode<?, ?>> augData = data.getChild(augCtx.get().getDomPathArgument());
-            if (augData.isPresent()) {
-                return augCtx.get().deserialize(augData.get());
+        final Optional<DataContainerCodecContext<?, ?>> optAugCtx = context.possibleStreamChild((Class) cls);
+        if (optAugCtx.isPresent()) {
+            final DataContainerCodecContext<?, ?> augCtx = optAugCtx.get();
+            // Due to binding specification not representing grouping instantiations we can end up having the same
+            // augmentation applied to a grouping multiple times. While these augmentations have the same shape, they
+            // are still represented by distinct binding classes and therefore we need to make sure the result matches
+            // the augmentation the user is requesting -- otherwise a strict receiver would end up with a cryptic
+            // ClassCastException.
+            if (cls.isAssignableFrom(augCtx.getBindingClass())) {
+                final java.util.Optional<NormalizedNode<?, ?>> augData = data.getChild(augCtx.getDomPathArgument());
+                if (augData.isPresent()) {
+                    return augCtx.deserialize(augData.get());
+                }
             }
         }
         return null;
@@ -201,7 +210,7 @@ class LazyDataObject<D extends DataObject> implements InvocationHandler, Augment
     public String bindingToString() {
         final ToStringHelper helper = MoreObjects.toStringHelper(context.getBindingClass()).omitNullValues();
 
-        for (final Method m :context.getHashCodeAndEqualsMethods()) {
+        for (final Method m : context.getHashCodeAndEqualsMethods()) {
             helper.add(m.getName(), getBindingData(m));
         }
         if (Augmentable.class.isAssignableFrom(context.getBindingClass())) {