Degrade DataNodeContainer.getChildNodes() from Set to Collection
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / LazyGeneratedCodecRegistry.java
index 22817ae3e1d70180a015fb448e0dfbeaa6d99414..86f0cdf881a64b156cde44b0a45ccb6270da2563 100644 (file)
@@ -7,6 +7,18 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.util.AbstractMap.SimpleEntry;
@@ -37,6 +49,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifier;
@@ -67,23 +80,13 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-class LazyGeneratedCodecRegistry implements //
-        CodecRegistry, //
-        SchemaContextListener, //
-        GeneratorListener {
+class LazyGeneratedCodecRegistry implements CodecRegistry, SchemaContextListener, GeneratorListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
 
@@ -130,6 +133,9 @@ class LazyGeneratedCodecRegistry implements //
     private final AbstractTransformerGenerator generator;
     private final SchemaLock lock;
 
+    private static final LoadingCache<Class<?>, AugmentationFieldGetter> AUGMENTATION_GETTERS =
+            CacheBuilder.newBuilder().weakKeys().softValues().build(new AugmentationGetterLoader());
+
     // FIXME: how is this protected?
     private SchemaContext currentSchema;
 
@@ -193,7 +199,12 @@ class LazyGeneratedCodecRegistry implements //
 
     @Override
     public Class<?> getClassForPath(final List<QName> names) {
-        final DataSchemaNode node = getSchemaNode(names);
+        DataSchemaNode node = getSchemaNode(names);
+        Preconditions.checkArgument(node != null, "Path %s points to invalid schema location",names);
+        SchemaNode originalDefinition = SchemaNodeUtils.getRootOriginalIfPossible(node);
+        if(originalDefinition instanceof DataSchemaNode) {
+            node =(DataSchemaNode) originalDefinition;
+        }
         final SchemaPath path = node.getPath();
         final Type t = pathToType.get(path);
 
@@ -207,9 +218,14 @@ class LazyGeneratedCodecRegistry implements //
 
         @SuppressWarnings("rawtypes")
         final WeakReference<Class> weakRef = typeToClass.get(type);
-        Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path,
-                type.getFullyQualifiedName());
-        return weakRef.get();
+        if(weakRef != null) {
+            return weakRef.get();
+        }
+        try {
+            return classLoadingStrategy.loadClass(type);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException(String.format("Could not find loaded class for path: %s and type: %s", path,type.getFullyQualifiedName()));
+        }
     }
 
     @Override
@@ -253,10 +269,9 @@ class LazyGeneratedCodecRegistry implements //
         WeakReference<Class> weakRef = new WeakReference<>(cls);
         typeToClass.put(typeRef, weakRef);
         if (Augmentation.class.isAssignableFrom(cls)) {
-
+            // Intentionally NOOP
         } else if (DataObject.class.isAssignableFrom(cls)) {
-            @SuppressWarnings({ "unchecked", "unused" })
-            Object cdc = getCodecForDataObject((Class<? extends DataObject>) cls);
+            getCodecForDataObject((Class<? extends DataObject>) cls);
         }
     }
 
@@ -296,8 +311,7 @@ class LazyGeneratedCodecRegistry implements //
     }
 
     private DataSchemaNode searchInChoices(final DataNodeContainer node, final QName arg) {
-        Set<DataSchemaNode> children = node.getChildNodes();
-        for (DataSchemaNode child : children) {
+        for (DataSchemaNode child : node.getChildNodes()) {
             if (child instanceof ChoiceNode) {
                 ChoiceNode choiceNode = (ChoiceNode) child;
                 DataSchemaNode potential = searchInCases(choiceNode, arg);
@@ -410,8 +424,8 @@ class LazyGeneratedCodecRegistry implements //
         for (Map.Entry<Type, AugmentationSchema> entry : bimap.entrySet()) {
             Type key = entry.getKey();
             AugmentationSchema value = entry.getValue();
-            Set<DataSchemaNode> augmentedNodes = value.getChildNodes();
-            if (augmentedNodes != null && !(augmentedNodes.isEmpty())) {
+            Collection<DataSchemaNode> augmentedNodes = value.getChildNodes();
+            if (augmentedNodes != null && !augmentedNodes.isEmpty()) {
                 typeToAugment.put(key, value);
             }
         }
@@ -453,7 +467,7 @@ class LazyGeneratedCodecRegistry implements //
     private void resetDispatchCodecsAdaptation() {
         synchronized (dispatchCodecs) {
             for (LocationAwareDispatchCodec<?> codec : dispatchCodecs.values()) {
-                codec.resetAdaptation();
+                codec.resetCodec(this);
             }
         }
     }
@@ -466,7 +480,7 @@ class LazyGeneratedCodecRegistry implements //
         Preconditions.checkState(oldCodec == null);
         BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
         PublicChoiceCodecImpl<?> newCodec = new PublicChoiceCodecImpl(delegate);
-        DispatchChoiceCodecImpl dispatchCodec = new DispatchChoiceCodecImpl(choiceClass);
+        DispatchChoiceCodecImpl dispatchCodec = new DispatchChoiceCodecImpl(choiceClass,this);
         choiceCodecs.put(choiceClass, newCodec);
         synchronized (dispatchCodecs) {
             dispatchCodecs.put(choiceClass, dispatchCodec);
@@ -497,7 +511,7 @@ class LazyGeneratedCodecRegistry implements //
         if (ret != null) {
             return ret;
         }
-        ret = new AugmentableDispatchCodec(dataClass);
+        ret = new AugmentableDispatchCodec(dataClass,this);
         augmentableCodecs.put(dataClass, ret);
         synchronized (dispatchCodecs) {
             dispatchCodecs.put(dataClass, ret);
@@ -506,8 +520,52 @@ class LazyGeneratedCodecRegistry implements //
         return ret;
     }
 
-    private static abstract class IntermediateCodec<T> implements //
-            DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+    private static final class AugmentationGetterLoader extends CacheLoader<Class<?>, AugmentationFieldGetter> {
+        private static final AugmentationFieldGetter DUMMY = new AugmentationFieldGetter() {
+            @Override
+            Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
+                return Collections.emptyMap();
+            }
+        };
+
+        @Override
+        public AugmentationFieldGetter load(final Class<?> key) throws Exception {
+            Field field;
+            try {
+                field = key.getDeclaredField("augmentation");
+            } catch (NoSuchFieldException | SecurityException e) {
+                LOG.debug("Failed to acquire augmentation field", e);
+                return DUMMY;
+            }
+            field.setAccessible(true);
+
+            return new ReflectionAugmentationFieldGetter(field);
+        }
+    }
+
+    private static abstract class AugmentationFieldGetter {
+        abstract Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input);
+    }
+
+    private static final class ReflectionAugmentationFieldGetter extends AugmentationFieldGetter {
+        private final Field augmentationField;
+
+        ReflectionAugmentationFieldGetter(final Field augmentationField) {
+            this.augmentationField = Preconditions.checkNotNull(augmentationField);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
+            try {
+                return (Map<Class<? extends Augmentation<?>>, Augmentation<?>>) augmentationField.get(input);
+            } catch (IllegalArgumentException | IllegalAccessException e) {
+                throw new IllegalStateException("Failed to access augmentation field", e);
+            }
+        }
+    }
+
+    private static abstract class IntermediateCodec<T> implements DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
 
         private final BindingCodec<Map<QName, Object>, Object> delegate;
 
@@ -528,9 +586,7 @@ class LazyGeneratedCodecRegistry implements //
 
     }
 
-    private static class IdentifierCodecImpl<T extends Identifier<?>> //
-            extends IntermediateCodec<T> //
-            implements IdentifierCodec<T> {
+    private static class IdentifierCodecImpl<T extends Identifier<?>> extends IntermediateCodec<T> implements IdentifierCodec<T> {
 
         public IdentifierCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
             super(delegate);
@@ -558,9 +614,7 @@ class LazyGeneratedCodecRegistry implements //
         }
     }
 
-    private static class DataContainerCodecImpl<T extends DataContainer> //
-            extends IntermediateCodec<T> //
-            implements DataContainerCodec<T> {
+    private static class DataContainerCodecImpl<T extends DataContainer> extends IntermediateCodec<T> implements DataContainerCodec<T> {
 
         public DataContainerCodecImpl(final BindingCodec<Map<QName, Object>, Object> delegate) {
             super(delegate);
@@ -603,10 +657,16 @@ class LazyGeneratedCodecRegistry implements //
     }
 
     @SuppressWarnings("rawtypes")
-    private abstract class LocationAwareDispatchCodec<T extends LocationAwareBindingCodec> implements BindingCodec {
+    private static abstract class LocationAwareDispatchCodec<T extends LocationAwareBindingCodec> implements BindingCodec {
 
         private final Map<Class, T> implementations = Collections.synchronizedMap(new WeakHashMap<Class, T>());
         private final Set<InstanceIdentifier<?>> adaptedForPaths = new HashSet<>();
+        private LazyGeneratedCodecRegistry registry;
+
+
+        protected LocationAwareDispatchCodec(final LazyGeneratedCodecRegistry registry) {
+            this.registry = registry;
+        }
 
         protected Map<Class, T> getImplementations() {
             return implementations;
@@ -621,7 +681,8 @@ class LazyGeneratedCodecRegistry implements //
          * of new codecs and/or removal of existing ones.
          *
          */
-        public synchronized void resetAdaptation() {
+        public synchronized void resetCodec(final LazyGeneratedCodecRegistry currentRegistry) {
+            registry = currentRegistry;
             adaptedForPaths.clear();
             resetAdaptationImpl();
         }
@@ -631,6 +692,9 @@ class LazyGeneratedCodecRegistry implements //
             // behaviour.
         }
 
+        protected final LazyGeneratedCodecRegistry getRegistry() {
+            return registry;
+        }
         protected void addImplementation(final T implementation) {
             implementations.put(implementation.getDataType(), implementation);
         }
@@ -664,7 +728,7 @@ class LazyGeneratedCodecRegistry implements //
             /* In case of none is applicable, we return
              * null. Since there is no mixin which
              * is applicable in this location.
-            */
+             */
             if(applicable.isEmpty()) {
                 return null;
             }
@@ -697,14 +761,14 @@ class LazyGeneratedCodecRegistry implements //
             if (adaptedForPaths.contains(path)) {
                 return;
             }
-            LOG.info("Adapting mixin codec {} for path {}",this,path);
+            LOG.debug("Adapting mixin codec {} for path {}",this,path);
             /**
              * We search in schema context if the use of this location aware
              * codec (augmentable codec, case codec) makes sense on provided
              * location (path)
              *
              */
-            Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema,
+            Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(getRegistry().currentSchema,
                     path);
             /**
              * If context node is present, this codec makes sense on provided
@@ -729,7 +793,7 @@ class LazyGeneratedCodecRegistry implements //
                          * make sure instance identifier codec is aware of
                          * combination of this path / augmentation / case
                          */
-                        instanceIdentifierCodec.serialize(path);
+                        getRegistry().getInstanceIdentifierCodec().serialize(path);
                     } catch (Exception e) {
                         LOG.warn("Exception during preparation of instance identifier codec for  path {}.", path, e);
                     }
@@ -749,7 +813,7 @@ class LazyGeneratedCodecRegistry implements //
 
     @SuppressWarnings("rawtypes")
     private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
-            Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
+    Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
         private final BindingCodec delegate;
         private final ChoiceCaseNode schema;
         private final Map<InstanceIdentifier<?>, ChoiceCaseNode> instantiatedLocations;
@@ -876,8 +940,7 @@ class LazyGeneratedCodecRegistry implements //
         }
     }
 
-    private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>,
-            Delegator<BindingCodec<Map<QName, Object>, Object>> {
+    private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
 
         private final BindingCodec<Map<QName, Object>, Object> delegate;
 
@@ -911,7 +974,8 @@ class LazyGeneratedCodecRegistry implements //
         private final Class<?> choiceType;
         private final QName choiceName;
 
-        private DispatchChoiceCodecImpl(final Class<?> type) {
+        private DispatchChoiceCodecImpl(final Class<?> type, final LazyGeneratedCodecRegistry registry) {
+            super(registry);
             choiceType = type;
             choiceName = BindingReflections.findQName(type);
         }
@@ -952,7 +1016,7 @@ class LazyGeneratedCodecRegistry implements //
             try {
                 @SuppressWarnings("unchecked")
                 Class<? extends DataContainer> clazz = (Class<? extends DataContainer>) classLoadingStrategy
-                        .loadClass(potential);
+                .loadClass(potential);
                 ChoiceCaseCodecImpl codec = tryToLoadImplementation(clazz);
                 addImplementation(codec);
                 return Optional.of(codec);
@@ -1009,71 +1073,141 @@ class LazyGeneratedCodecRegistry implements //
         }
     }
 
+    /**
+     *
+     * Dispatch codec for augmented object, which processes augmentations
+     * <p>
+     * This codec is used from DataObject codec generated using
+     * {@link TransformerGenerator#transformerFor(Class)} and is wired
+     * during {@link LazyGeneratedCodecRegistry#onDataContainerCodecCreated(Class, Class)}.
+     * <p>
+     * Instance of this codec is associated with class of Binding DTO which
+     * represents target for augmentations.
+     *
+     */
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
+    static class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
 
         private final Class augmentableType;
 
-        public AugmentableDispatchCodec(final Class type) {
+        /**
+         * Construct augmetable dispatch codec.
+         *
+         * @param type Class representing augmentation target
+         * @param registry Registry with which this codec is associated.
+         */
+        public AugmentableDispatchCodec(final Class type, final LazyGeneratedCodecRegistry registry) {
+            super(registry);
             Preconditions.checkArgument(Augmentable.class.isAssignableFrom(type));
             augmentableType = type;
         }
 
+
+
+        /**
+         * Serializes object to list of values which needs to be injected
+         * into resulting DOM Node. Injection of data to parent DOM Node
+         * is handled by caller (in this case generated codec).
+         *
+         * TODO: Deprecate use of augmentation codec without instance
+         *       instance identifier
+         *
+         * @return list of nodes, which needs to be added to parent node.
+         *
+         */
         @Override
-        // TODO deprecate use without iid
         public Object serialize(final Object input) {
+            Preconditions.checkArgument(augmentableType.isInstance(input), "Object %s is not instance of %s ",input,augmentableType);
             if (input instanceof Augmentable<?>) {
-                Map<Class, Augmentation> augmentations = getAugmentations(input);
+                Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations = getAugmentations(input);
                 return serializeImpl(augmentations);
             }
             return null;
         }
 
-        private Map<Class, Augmentation> getAugmentations(final Object input) {
-            Field augmentationField;
-            try {
-                augmentationField = input.getClass().getDeclaredField("augmentation");
-                augmentationField.setAccessible(true);
-                Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
-                return augMap;
-            } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
-                LOG.debug("Could not read augmentations for {}", input, e);
-            }
-            return Collections.emptyMap();
+        /**
+         *
+         * Extracts augmentation from Binding DTO field using reflection
+         *
+         * @param input Instance of DataObject which is augmentable and
+         *      may contain augmentation
+         * @return Map of augmentations if read was successful, otherwise
+         *      empty map.
+         */
+        private Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
+            return AUGMENTATION_GETTERS.getUnchecked(input.getClass()).getAugmentations(input);
         }
 
-        @SuppressWarnings("deprecation")
-        private List serializeImpl(final Map<Class, Augmentation> input) {
+        /**
+         *
+         * Serialization of augmentations, returns list of composite nodes,
+         * which needs to be injected to parent node.
+         *
+         * @param input Map of classes to augmentations
+         * @return List of nodes, which should be added to parent node.
+         */
+        private List serializeImpl(final Map<Class<? extends Augmentation<?>>, Augmentation<?>> input) {
             List ret = new ArrayList<>();
-            for (Entry<Class, Augmentation> entry : input.entrySet()) {
-                AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+            for (Entry<Class<? extends Augmentation<?>>, Augmentation<?>> entry : input.entrySet()) {
+                AugmentationCodec codec = getRegistry().getCodecForAugmentation(entry.getKey());
                 CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
-                ret.addAll(node.getChildren());
+                ret.addAll(node.getValue());
             }
             return ret;
         }
 
+        /**
+         *
+         * Deserialization of augmentation which is location aware.
+         *
+         * Note: In case of composite nodes as an input, each codec
+         * is invoked since there is no augmentation identifier
+         * and we need to look for concrete classes.
+         * FIXME: Maybe faster variation will be by extending
+         * {@link AugmentationCodecWrapper} to look for particular QNames,
+         * which will filter incoming set of codecs.
+         *
+         *
+         * @param input Input representation of data
+         * @param path Wildcarded instance identifier representing location of augmentation parent
+         *       in conceptual schema tree
+         * @param codecs Set of codecs which are applicable for supplied <code>path</code>,
+         *       selected by caller to be used by deserialization
+         *
+         *
+         */
         @Override
         public Map<Class, Augmentation> deserializeImpl(final CompositeNode input, final InstanceIdentifier<?> path,
                 final Iterable<AugmentationCodecWrapper> codecs) {
             LOG.trace("{}: Going to deserialize augmentations from {} in location {}. Available codecs {}",this,input,path,codecs);
             Map<Class, Augmentation> ret = new HashMap<>();
             for (AugmentationCodecWrapper codec : codecs) {
-                    // We add Augmentation Identifier to path, in order to
-                    // correctly identify children.
-                    Class type = codec.getDataType();
-                    final InstanceIdentifier augmentPath = path.augmentation(type);
-                    ValueWithQName<?> value = codec.deserialize(input, augmentPath);
-                    if (value != null && value.getValue() != null) {
-                        ret.put(type, (Augmentation) value.getValue());
-                    }
+                // We add Augmentation Identifier to path, in order to
+                // correctly identify children.
+                Class type = codec.getDataType();
+                final InstanceIdentifier augmentPath = path.augmentation(type);
+                ValueWithQName<?> value = codec.deserialize(input, augmentPath);
+                if (value != null && value.getValue() != null) {
+                    ret.put(type, (Augmentation) value.getValue());
+                }
             }
             return ret;
         }
 
+        /**
+         *
+         * Tries to load implementation of concrete augmentation codec for supplied type
+         *
+         * Loading of codec may fail, because of supplied type may not be visible
+         * by classloaders known by registry. If class was not found returns {@link Optional#absent()}.
+         *
+         * @param potential Augmentation class identifier for which codecs should be loaded.
+         * @return Optional with codec for supplied type
+         *
+         */
         protected Optional<AugmentationCodecWrapper> tryToLoadImplementation(final Type potential) {
             try {
-                Class<? extends Augmentation<?>> clazz = (Class<? extends Augmentation<?>>) classLoadingStrategy
+                Class<? extends Augmentation<?>> clazz = (Class<? extends Augmentation<?>>) getRegistry().classLoadingStrategy
                         .loadClass(potential);
                 return Optional.of(tryToLoadImplementation(clazz));
             } catch (ClassNotFoundException e) {
@@ -1084,7 +1218,7 @@ class LazyGeneratedCodecRegistry implements //
 
         @Override
         protected AugmentationCodecWrapper tryToLoadImplementation(final Class inputType) {
-            AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getCodecForAugmentation(inputType);
+            AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getRegistry().getCodecForAugmentation(inputType);
             addImplementation(potentialImpl);
             return potentialImpl;
         }
@@ -1147,7 +1281,7 @@ class LazyGeneratedCodecRegistry implements //
                         InstanceIdentifier augPath = augTarget.augmentation(augType);
                         try {
 
-                            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = getInstanceIdentifierCodec()
+                            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = getRegistry().getInstanceIdentifierCodec()
                                     .serialize(augPath);
                             if (domPath == null) {
                                 LOG.error("Unable to serialize instance identifier for {}", augPath);
@@ -1188,8 +1322,7 @@ class LazyGeneratedCodecRegistry implements //
     }
 
     @SuppressWarnings("rawtypes")
-    private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
-            Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
+    private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>, Delegator<BindingCodec>, LocationAwareBindingCodec<Node<?>, ValueWithQName<T>> {
 
         private final BindingCodec delegate;
         private final QName augmentationQName;
@@ -1281,9 +1414,14 @@ class LazyGeneratedCodecRegistry implements //
 
         @Override
         public Class<?> deserialize(final QName input) {
+            if(input == null) {
+                return null;
+            }
             Type type = qnamesToIdentityMap.get(input);
             if (type == null) {
-                return null;
+                String packageName = BindingMapping.getRootPackageName(input);
+                String className = BindingMapping.getClassName(input);
+                type = new ReferencedTypeImpl(packageName, className);
             }
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
             WeakReference<Class> softref = typeToClass.get(typeref);
@@ -1308,7 +1446,7 @@ class LazyGeneratedCodecRegistry implements //
         public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
             Type type = qnamesToIdentityMap.get(input);
             if (type == null) {
-                return null;
+                throw new IllegalArgumentException( "Invalid for \"" + input + "\"." );
             }
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
             WeakReference<Class> softref = typeToClass.get(typeref);
@@ -1337,8 +1475,7 @@ class LazyGeneratedCodecRegistry implements //
             if (qname != null) {
                 return qname;
             }
-            ConcreteType typeref = Types.typeForClass(input);
-            qname = typeToQname.get(typeref);
+            qname = BindingReflections.findQName(input);
             if (qname != null) {
                 identityQNames.put(input, qname);
             }