X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-codec%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fcodec%2Fimpl%2FDataObjectCodecContext.java;h=6277a058e91dc543dde4a17150191237164f49b5;hb=7a17eba49deb73733bdbb9579d2edd672bb0d71e;hp=3ac825690dcaebeae17ead4053296cb9baf14b1a;hpb=259957ffe47414cc197f4a819361e8a6dcf50b19;p=mdsal.git diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java index 3ac825690d..6277a058e9 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java @@ -9,38 +9,28 @@ package org.opendaylight.mdsal.binding.dom.codec.impl; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Verify.verify; -import static com.google.common.base.Verify.verifyNotNull; -import static java.util.Objects.requireNonNull; +import com.google.common.annotations.Beta; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; -import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Comparator; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.NotFoundException; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.mdsal.binding.dom.codec.loader.StaticClassPool; -import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy; -import org.opendaylight.mdsal.binding.model.api.JavaTypeName; +import org.opendaylight.mdsal.binding.dom.codec.api.IncorrectNestingException; +import org.opendaylight.mdsal.binding.model.api.DefaultType; import org.opendaylight.mdsal.binding.model.api.Type; +import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; -import org.opendaylight.yangtools.concepts.Immutable; -import org.opendaylight.yangtools.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -64,70 +54,69 @@ import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -abstract class DataObjectCodecContext +/** + * This class is an implementation detail. It is public only due to technical reasons and may change at any time. + */ +@Beta +public abstract class DataObjectCodecContext extends DataContainerCodecContext { - private static final class Augmentations implements Immutable { - final ImmutableMap> byYang; - final ImmutableMap, DataContainerCodecPrototype> byStream; - - Augmentations(final ImmutableMap> byYang, - final ImmutableMap, DataContainerCodecPrototype> byStream) { - this.byYang = requireNonNull(byYang); - this.byStream = requireNonNull(byStream); - } - } - private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class); - private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class, DataObjectCodecContext.class, - NormalizedNodeContainer.class); + private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class, + DataObjectCodecContext.class, NormalizedNodeContainer.class); private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class, DataObjectCodecContext.class, NormalizedNodeContainer.class); - private static final Comparator METHOD_BY_ALPHABET = Comparator.comparing(Method::getName); - private static final Augmentations EMPTY_AUGMENTATIONS = new Augmentations(ImmutableMap.of(), ImmutableMap.of()); - private static final CtClass SUPERCLASS = StaticClassPool.findClass(CodecDataObject.class); - private static final CtClass AUGMENTABLE_SUPERCLASS = StaticClassPool.findClass( - AugmentableCodecDataObject.class); - private static final NodeContextSupplier[] EMPTY_METHODS = new NodeContextSupplier[0]; + private static final VarHandle MISMATCHED_AUGMENTED; + + static { + try { + MISMATCHED_AUGMENTED = MethodHandles.lookup().findVarHandle(DataObjectCodecContext.class, + "mismatchedAugmented", ImmutableMap.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } private final ImmutableMap leafChild; private final ImmutableMap byYang; private final ImmutableMap, DataContainerCodecPrototype> byStreamClass; private final ImmutableMap, DataContainerCodecPrototype> byBindingArgClass; - private final ImmutableMap possibleAugmentations; - private final NodeContextSupplier[] byMethod; + private final ImmutableMap> augmentationByYang; + private final ImmutableMap, DataContainerCodecPrototype> augmentationByStream; + private final @NonNull Class> generatedClass; private final MethodHandle proxyConstructor; - @SuppressWarnings("rawtypes") - private static final AtomicReferenceFieldUpdater - AUGMENTATIONS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(DataObjectCodecContext.class, - Augmentations.class, "augmentations"); - private volatile Augmentations augmentations = EMPTY_AUGMENTATIONS; - + // Note this the content of this field depends only of invariants expressed as this class's fields or + // BindingRuntimeContext. It is only accessed via MISMATCHED_AUGMENTED above. + @SuppressWarnings("unused") private volatile ImmutableMap, DataContainerCodecPrototype> mismatchedAugmented = ImmutableMap.of(); DataObjectCodecContext(final DataContainerCodecPrototype prototype) { this(prototype, null); } - DataObjectCodecContext(final DataContainerCodecPrototype prototype, final @Nullable Method keyMethod) { + DataObjectCodecContext(final DataContainerCodecPrototype prototype, final Method keyMethod) { super(prototype); final Class bindingClass = getBindingClass(); - this.leafChild = factory().getLeafNodes(bindingClass, getSchema()); + final ImmutableMap tmpLeaves = factory().getLeafNodes(bindingClass, getSchema()); final Map, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(bindingClass); final Map byYangBuilder = new HashMap<>(); - final Map tmpMethodToSupplier = new HashMap<>(); final Map, DataContainerCodecPrototype> byStreamClassBuilder = new HashMap<>(); final Map, DataContainerCodecPrototype> byBindingArgClassBuilder = new HashMap<>(); // Adds leaves to mapping - for (final ValueNodeCodecContext leaf : leafChild.values()) { - tmpMethodToSupplier.put(leaf.getGetter(), leaf); + final Builder leafChildBuilder = + ImmutableMap.builderWithExpectedSize(tmpLeaves.size()); + for (final Entry entry : tmpLeaves.entrySet()) { + final ValueNodeCodecContext leaf = entry.getValue(); + leafChildBuilder.put(leaf.getSchema().getQName().getLocalName(), leaf); byYangBuilder.put(leaf.getDomPathArgument(), leaf); } + this.leafChild = leafChildBuilder.build(); + final Map> tmpDataObjects = new HashMap<>(); for (final Entry, Method> childDataObj : clsToMethod.entrySet()) { final Method method = childDataObj.getValue(); verify(!method.isDefault(), "Unexpected default method %s in %s", method, bindingClass); @@ -139,7 +128,7 @@ abstract class DataObjectCodecContext childProto = loadChildPrototype(retClass); - tmpMethodToSupplier.put(method, childProto); + tmpDataObjects.put(method, childProto.getBindingClass()); byStreamClassBuilder.put(childProto.getBindingClass(), childProto); byYangBuilder.put(childProto.getYangArg(), childProto); if (childProto.isChoice()) { @@ -150,126 +139,52 @@ abstract class DataObjectCodecContext properties = new ArrayList<>(tmpMethodToSupplier.keySet()); - properties.sort(METHOD_BY_ALPHABET); - if (!properties.isEmpty()) { - byMethod = new NodeContextSupplier[properties.size()]; - int offset = 0; - for (Method prop : properties) { - byMethod[offset++] = verifyNotNull(tmpMethodToSupplier.get(prop)); - } - } else { - byMethod = EMPTY_METHODS; - } - this.byYang = ImmutableMap.copyOf(byYangBuilder); this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder); - byBindingArgClassBuilder.putAll(byStreamClass); - this.byBindingArgClass = ImmutableMap.copyOf(byBindingArgClassBuilder); - final CtClass superClass; + // Slight footprint optimization: we do not want to copy byStreamClass, as that would force its entrySet view + // to be instantiated. Furthermore the two maps can easily end up being equal -- hence we can reuse + // byStreamClass for the purposes of both. + byBindingArgClassBuilder.putAll(byStreamClassBuilder); + this.byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? this.byStreamClass + : ImmutableMap.copyOf(byBindingArgClassBuilder); + + final ImmutableMap possibleAugmentations; if (Augmentable.class.isAssignableFrom(bindingClass)) { - this.possibleAugmentations = factory().getRuntimeContext().getAvailableAugmentationTypes(getSchema()); - superClass = AUGMENTABLE_SUPERCLASS; + possibleAugmentations = factory().getRuntimeContext().getAvailableAugmentationTypes(getSchema()); + generatedClass = CodecDataObjectGenerator.generateAugmentable(prototype.getFactory().getLoader(), + bindingClass, tmpLeaves, tmpDataObjects, keyMethod); } else { - this.possibleAugmentations = ImmutableMap.of(); - superClass = SUPERCLASS; - } - reloadAllAugmentations(); - - final Class generatedClass; - try { - generatedClass = prototype.getFactory().getLoader().generateSubclass(superClass, bindingClass, "codecImpl", - new CodecDataObjectCustomizer(properties, keyMethod)); - } catch (CannotCompileException | IOException | NotFoundException e) { - throw new LinkageError("Failed to generated class for " + bindingClass, e); - } - - try { - proxyConstructor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE) - .asType(DATAOBJECT_TYPE).bindTo(this); - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new LinkageError("Failed to find contructor for class " + generatedClass, e); + possibleAugmentations = ImmutableMap.of(); + generatedClass = CodecDataObjectGenerator.generate(prototype.getFactory().getLoader(), bindingClass, + tmpLeaves, tmpDataObjects, keyMethod); } - } - - // This method could be synchronized, but that would mean that concurrent attempts to load an invalid augmentation - // would end up being unnecessarily contended -- blocking real progress and not being able to run concurrently - // while producing no effect. We therefore use optimistic read + CAS. - private void reloadAllAugmentations() { - // Load current values - Augmentations oldAugmentations = augmentations; - - // FIXME: can we detect when we have both maps fully populated and skip all of this? - - // Scratch space for additions - final Map> addByYang = new HashMap<>(); - final Map, DataContainerCodecPrototype> addByStream = new HashMap<>(); - // Iterate over all possibilities, checking for modifications. + // Iterate over all possible augmentations, indexing them as needed + final Map> augByYang = new HashMap<>(); + final Map, DataContainerCodecPrototype> augByStream = new HashMap<>(); for (final Type augment : possibleAugmentations.values()) { final DataContainerCodecPrototype augProto = getAugmentationPrototype(augment); - if (augProto != null) { - final PathArgument yangArg = augProto.getYangArg(); - final Class bindingClass = augProto.getBindingClass(); - if (!oldAugmentations.byYang.containsKey(yangArg)) { - if (addByYang.putIfAbsent(yangArg, augProto) == null) { - LOG.trace("Discovered new YANG mapping {} -> {} in {}", yangArg, augProto, this); - } - } - if (!oldAugmentations.byStream.containsKey(bindingClass)) { - if (addByStream.putIfAbsent(bindingClass, augProto) == null) { - LOG.trace("Discovered new class mapping {} -> {} in {}", bindingClass, augProto, this); - } - } + final PathArgument augYangArg = augProto.getYangArg(); + if (augByYang.putIfAbsent(augYangArg, augProto) == null) { + LOG.trace("Discovered new YANG mapping {} -> {} in {}", augYangArg, augProto, this); } - } - - while (true) { - if (addByYang.isEmpty() && addByStream.isEmpty()) { - LOG.trace("No new augmentations discovered in {}", this); - return; + final Class augBindingClass = augProto.getBindingClass(); + if (augByStream.putIfAbsent(augBindingClass, augProto) == null) { + LOG.trace("Discovered new class mapping {} -> {} in {}", augBindingClass, augProto, this); } - - // We have some additions, propagate them out - final Augmentations newAugmentations = new Augmentations(concatMaps(oldAugmentations.byYang, addByYang), - concatMaps(oldAugmentations.byStream, addByStream)); - if (AUGMENTATIONS_UPDATER.compareAndSet(this, oldAugmentations, newAugmentations)) { - // Success, we are done - return; - } - - // We have raced installing new augmentations, read them again, remove everything present in the installed - // once and try again. This may mean that we end up not doing anything, but that's fine. - oldAugmentations = augmentations; - - // We could use Map.removeAll(oldAugmentations.byYang.keySet()), but that forces the augmentation's keyset - // to be materialized, which we otherwise do not need. Hence we do this the other way around, instantiating - // our temporary maps' keySets and iterating over them. That's fine as we'll be throwing those maps away. - removeMapKeys(addByYang, oldAugmentations.byYang); - removeMapKeys(addByStream, oldAugmentations.byStream); } - } + augmentationByYang = ImmutableMap.copyOf(augByYang); + augmentationByStream = ImmutableMap.copyOf(augByStream); - private static ImmutableMap concatMaps(final ImmutableMap old, final Map add) { - if (add.isEmpty()) { - return old; + final MethodHandle ctor; + try { + ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new LinkageError("Failed to find contructor for class " + generatedClass, e); } - final Builder builder = ImmutableMap.builderWithExpectedSize(old.size() + add.size()); - builder.putAll(old); - builder.putAll(add); - return builder.build(); - } - - private static void removeMapKeys(final Map removeFrom, final ImmutableMap map) { - final Iterator it = removeFrom.keySet().iterator(); - while (it.hasNext()) { - if (map.containsKey(it.next())) { - it.remove(); - } - } + proxyConstructor = ctor.asType(DATAOBJECT_TYPE); } @SuppressWarnings("unchecked") @@ -340,7 +255,7 @@ abstract class DataObjectCodecContext loadChildPrototype(final Class childClass) { @@ -378,7 +296,7 @@ abstract class DataObjectCodecContext) childClass); } - private DataContainerCodecPrototype yangAugmentationChild(final AugmentationIdentifier arg) { - final DataContainerCodecPrototype firstTry = augmentations.byYang.get(arg); - if (firstTry != null) { - return firstTry; - } - if (possibleAugmentations.containsKey(arg)) { - // Try to load augmentations, which will potentially update knownAugmentations, hence we re-load that field - // again. - reloadAllAugmentations(); - return augmentations.byYang.get(arg); - } - return null; - } - private @Nullable DataContainerCodecPrototype augmentationByClass(final @NonNull Class childClass) { - DataContainerCodecPrototype lookup = augmentationByClassOrEquivalentClass(childClass); - if (lookup != null || !isPotentialAugmentation(childClass)) { - return lookup; - } - - // Attempt to reload all augmentations using TCCL and lookup again - reloadAllAugmentations(); - lookup = augmentationByClassOrEquivalentClass(childClass); - if (lookup != null) { - return lookup; - } - - // Still no result, this can be caused by TCCL not being set up properly -- try the class's ClassLoader - // if it is present; - final ClassLoader loader = childClass.getClassLoader(); - if (loader == null) { - return null; - } - - LOG.debug("Class {} not loaded via TCCL, attempting to recover", childClass); - ClassLoaderUtils.runWithClassLoader(loader, this::reloadAllAugmentations); - return augmentationByClassOrEquivalentClass(childClass); - } - - private boolean isPotentialAugmentation(final Class childClass) { - final JavaTypeName name = JavaTypeName.create(childClass); - for (Type type : possibleAugmentations.values()) { - if (name.equals(type.getIdentifier())) { - return true; - } - } - return false; + final DataContainerCodecPrototype childProto = augmentationByStream.get(childClass); + return childProto != null ? childProto : mismatchedAugmentationByClass(childClass); } - private @Nullable DataContainerCodecPrototype augmentationByClassOrEquivalentClass( - final @NonNull Class childClass) { - // Perform a single load, so we can reuse it if we end up going to the reflection-based slow path - final ImmutableMap, DataContainerCodecPrototype> local = augmentations.byStream; - final DataContainerCodecPrototype childProto = local.get(childClass); - if (childProto != null) { - return childProto; - } - + private @Nullable DataContainerCodecPrototype mismatchedAugmentationByClass(final @NonNull Class childClass) { /* * It is potentially mismatched valid augmentation - we look up equivalent augmentation using reflection * and walk all stream child and compare augmentations classes if they are equivalent. When we find a match * we'll cache it so we do not need to perform reflection operations again. */ - final DataContainerCodecPrototype mismatched = mismatchedAugmented.get(childClass); - if (mismatched != null) { - return mismatched; - } + final ImmutableMap, DataContainerCodecPrototype> local = + (ImmutableMap, DataContainerCodecPrototype>) MISMATCHED_AUGMENTED.getAcquire(this); + final DataContainerCodecPrototype mismatched = local.get(childClass); + return mismatched != null ? mismatched : loadMismatchedAugmentation(local, childClass); + } + + private @Nullable DataContainerCodecPrototype loadMismatchedAugmentation( + final ImmutableMap, DataContainerCodecPrototype> oldMismatched, + final @NonNull Class childClass) { @SuppressWarnings("rawtypes") final Class augTarget = BindingReflections.findAugmentationTarget((Class) childClass); - if (getBindingClass().equals(augTarget)) { - for (final DataContainerCodecPrototype realChild : local.values()) { + // Do not bother with proposals which are not augmentations of our class, or do not match what the runtime + // context would load. + if (getBindingClass().equals(augTarget) && belongsToRuntimeContext(childClass)) { + for (final DataContainerCodecPrototype realChild : augmentationByStream.values()) { if (Augmentation.class.isAssignableFrom(realChild.getBindingClass()) && BindingReflections.isSubstitutionFor(childClass, realChild.getBindingClass())) { - return cacheMismatched(childClass, realChild); + return cacheMismatched(oldMismatched, childClass, realChild); } } } @@ -480,58 +353,64 @@ abstract class DataObjectCodecContext cacheMismatched(final Class childClass, - final DataContainerCodecPrototype prototype) { - // Original access was unsynchronized, we need to perform additional checking - final ImmutableMap, DataContainerCodecPrototype> local = mismatchedAugmented; - final DataContainerCodecPrototype existing = local.get(childClass); - if (existing != null) { - return existing; - } + private @NonNull DataContainerCodecPrototype cacheMismatched( + final @NonNull ImmutableMap, DataContainerCodecPrototype> oldMismatched, + final @NonNull Class childClass, final @NonNull DataContainerCodecPrototype prototype) { - final Builder, DataContainerCodecPrototype> builder = ImmutableMap.builderWithExpectedSize( - local.size() + 1); - builder.putAll(local); - builder.put(childClass, prototype); + ImmutableMap, DataContainerCodecPrototype> expected = oldMismatched; + while (true) { + final Map, DataContainerCodecPrototype> newMismatched = + ImmutableMap., DataContainerCodecPrototype>builderWithExpectedSize(expected.size() + 1) + .putAll(expected) + .put(childClass, prototype) + .build(); + + final Object witness = MISMATCHED_AUGMENTED.compareAndExchangeRelease(this, expected, newMismatched); + if (witness == expected) { + LOG.trace("Cached mismatched augmentation {} -> {} in {}", childClass, prototype, this); + return prototype; + } - mismatchedAugmented = builder.build(); - LOG.trace("Cached mismatched augmentation {} -> {} in {}", childClass, prototype, this); - return prototype; + expected = (ImmutableMap, DataContainerCodecPrototype>) witness; + final DataContainerCodecPrototype existing = expected.get(childClass); + if (existing != null) { + LOG.trace("Using raced mismatched augmentation {} -> {} in {}", childClass, existing, this); + return existing; + } + } } - private DataContainerCodecPrototype getAugmentationPrototype(final Type value) { - final ClassLoadingStrategy loader = factory().getRuntimeContext().getStrategy(); - @SuppressWarnings("rawtypes") - final Class augClass; + private boolean belongsToRuntimeContext(final Class cls) { + final BindingRuntimeContext ctx = factory().getRuntimeContext(); + final Class loaded; try { - augClass = loader.loadClass(value); - } catch (final ClassNotFoundException e) { - LOG.debug("Failed to load augmentation prototype for {}. Will be retried when needed.", value, e); - return null; + loaded = ctx.loadClass(DefaultType.of(cls)); + } catch (ClassNotFoundException e) { + LOG.debug("Proposed {} cannot be loaded in {}", cls, ctx); + return false; } - - @SuppressWarnings("unchecked") - final Entry augSchema = factory().getRuntimeContext() - .getResolvedAugmentationSchema(getSchema(), augClass); - return DataContainerCodecPrototype.from(augClass, augSchema.getKey(), augSchema.getValue(), factory()); + return cls.equals(loaded); } - @SuppressWarnings("rawtypes") - @Nullable Object getBindingChildValue(final NormalizedNodeContainer domData, final int offset) { - final NodeCodecContext childContext = byMethod[offset].get(); + private @NonNull DataContainerCodecPrototype getAugmentationPrototype(final Type value) { + final BindingRuntimeContext ctx = factory().getRuntimeContext(); - @SuppressWarnings("unchecked") - final Optional> domChild = domData.getChild(childContext.getDomPathArgument()); + final Class> augClass; + try { + augClass = ctx.loadClass(value); + } catch (final ClassNotFoundException e) { + throw new IllegalStateException("RuntimeContext references type " + value + " but failed to its class", e); + } - // We do not want to use Optional.map() here because we do not want to invoke defaultObject() when we have - // normal value because defaultObject() may end up throwing an exception intentionally. - return domChild.isPresent() ? childContext.deserializeObject(domChild.get()) : childContext.defaultObject(); + final Entry augSchema = + ctx.getResolvedAugmentationSchema(getSchema(), augClass); + return DataContainerCodecPrototype.from(augClass, augSchema.getKey(), augSchema.getValue(), factory()); } @SuppressWarnings("checkstyle:illegalCatch") - protected final D createBindingProxy(final NormalizedNodeContainer node) { + protected final @NonNull D createBindingProxy(final NormalizedNodeContainer node) { try { - return (D) proxyConstructor.invokeExact(node); + return (D) proxyConstructor.invokeExact(this, node); } catch (final Throwable e) { Throwables.throwIfUnchecked(e); throw new IllegalStateException(e); @@ -548,14 +427,14 @@ abstract class DataObjectCodecContext childValue : data.getValue()) { if (childValue instanceof AugmentationNode) { final AugmentationNode augDomNode = (AugmentationNode) childValue; - final DataContainerCodecPrototype codecProto = yangAugmentationChild(augDomNode.getIdentifier()); + final DataContainerCodecPrototype codecProto = augmentationByYang.get(augDomNode.getIdentifier()); if (codecProto != null) { final DataContainerCodecContext codec = codecProto.get(); map.put(codec.getBindingClass(), codec.deserializeObject(augDomNode)); } } } - for (final DataContainerCodecPrototype value : augmentations.byStream.values()) { + for (final DataContainerCodecPrototype value : augmentationByStream.values()) { final Optional> augData = data.getChild(value.getYangArg()); if (augData.isPresent()) { map.put(value.getBindingClass(), value.get().deserializeObject(augData.get())); @@ -564,6 +443,10 @@ abstract class DataObjectCodecContext> generatedClass() { + return generatedClass; + } + @Override public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) { checkArgument(getDomPathArgument().equals(arg));