Bug 4969: NPE in JSONCodecFactory by attempt to find codec for a leafref
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / JSONCodecFactory.java
index 3766169f3c8ad8a57919f0006773ab9bf105460e..1d6ffc827724a1670da028bdc5a34cc9810ccc43 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -20,9 +21,11 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
-import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
+import org.opendaylight.yangtools.yang.model.util.DerivedType;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,7 +54,7 @@ public final class JSONCodecFactory {
         }
 
         @Override
-        public void serializeToWriter(JsonWriter writer, Object value) throws IOException {
+        public void serializeToWriter(final JsonWriter writer, final Object value) throws IOException {
             // NOOP since codec is unkwown.
             LOG.warn("Call of the serializeToWriter method on JSONCodecFactory.NULL_CODEC object. No operation performed.");
         }
@@ -78,7 +81,7 @@ public final class JSONCodecFactory {
 
     private JSONCodecFactory(final SchemaContext context) {
         this.schemaContext = Preconditions.checkNotNull(context);
-        iidCodec = new JSONStringInstanceIdentifierCodec(context);
+        iidCodec = new JSONStringInstanceIdentifierCodec(context, this);
     }
 
     /**
@@ -91,41 +94,36 @@ public final class JSONCodecFactory {
         return new JSONCodecFactory(context);
     }
 
-    private static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
-        TypeDefinition<?> superType = type;
-        while (superType.getBaseType() != null) {
-            superType = superType.getBaseType();
-        }
-        return superType;
-    }
-
     @SuppressWarnings("unchecked")
-    private JSONCodec<Object> createCodec(DataSchemaNode key, TypeDefinition<?> type) {
-        TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
-        if (baseType instanceof LeafrefTypeDefinition) {
-            return createReferencedTypeCodec(key, (LeafrefTypeDefinition) baseType);
-        } else if (baseType instanceof IdentityrefType) {
-            final JSONCodec<?> jsonStringIdentityrefCodec = new JSONStringIdentityrefCodec(schemaContext,
-                    key.getQName().getModule());
+    private JSONCodec<Object> createCodec(final DataSchemaNode key, final TypeDefinition<?> type) {
+        final TypeDefinition<?> normalizedType = DerivedType.from(type);
+        if (normalizedType instanceof LeafrefTypeDefinition) {
+            return createReferencedTypeCodec(key, (LeafrefTypeDefinition) normalizedType);
+        } else if (normalizedType instanceof IdentityrefTypeDefinition) {
+            final JSONCodec<?> jsonStringIdentityrefCodec =
+                    new JSONStringIdentityrefCodec(schemaContext, key.getQName().getModule());
             return (JSONCodec<Object>) jsonStringIdentityrefCodec;
         }
-        return createFromSimpleType(type);
+        return createFromSimpleType(normalizedType);
     }
 
-    private JSONCodec<Object> createReferencedTypeCodec(DataSchemaNode schema,
-            LeafrefTypeDefinition type) {
+    private JSONCodec<Object> createReferencedTypeCodec(final DataSchemaNode schema,
+            final LeafrefTypeDefinition type) {
         // FIXME: Verify if this does indeed support leafref of leafref
-        TypeDefinition<?> referencedType =
+        final TypeDefinition<?> referencedType =
                 SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema);
-        return createFromSimpleType(referencedType);
+        Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath());
+        return createCodec(schema, referencedType);
     }
 
     @SuppressWarnings("unchecked")
-    private JSONCodec<Object> createFromSimpleType(TypeDefinition<?> type) {
-        final TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
-        if (baseType instanceof InstanceIdentifierType) {
+    private JSONCodec<Object> createFromSimpleType(final TypeDefinition<?> type) {
+        if (type instanceof InstanceIdentifierTypeDefinition) {
             return (JSONCodec<Object>) iidCodec;
         }
+        if (type instanceof EmptyTypeDefinition) {
+            return JSONEmptyCodec.INSTANCE;
+        }
 
         final TypeDefinitionAwareCodec<Object, ?> codec = TypeDefinitionAwareCodec.from(type);
         if (codec == null) {
@@ -140,7 +138,7 @@ public final class JSONCodecFactory {
         return schemaContext;
     }
 
-    JSONCodec<Object> codecFor(DataSchemaNode schema) {
+    JSONCodec<Object> codecFor(final DataSchemaNode schema) {
         return codecs.getUnchecked(schema);
     }