Represent large number types as strings 65/84965/2
authorMario Abraham <mario.abraham@pantheon.tech>
Fri, 27 Sep 2019 09:00:08 +0000 (11:00 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 7 Oct 2019 10:47:41 +0000 (12:47 +0200)
A value of the int64, uint64 and decimal64 type is
represented as a JSON string related to rfc 7951.

Issue-ID: YANGTOOLS-1027
Change-Id: Ic6aea0a0f97e042ed40d2e0be323557750401621
Signed-off-by: Mario Abraham <mario.abraham@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit af02c59d72a4f6af9361ea2842c35e634f6454e4)

yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactory.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactorySupplier.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02JSONCodecFactory.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951JSONCodecFactory.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractYT1027Test.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02YT1027Test.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951YT1027Test.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/resources/yt1027/yt1027.yang [new file with mode: 0644]

index ca39f1b6778141c25899ebc3ac923adbb81c835f..68b57a2726cbb0d733ba98574165143640b3f005 100644 (file)
@@ -7,12 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
-import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
-
 import com.google.common.annotations.Beta;
 import java.util.List;
-import java.util.function.BiFunction;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.impl.codec.AbstractIntegerStringCodec;
 import org.opendaylight.yangtools.yang.data.impl.codec.BinaryStringCodec;
@@ -50,112 +47,104 @@ import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
  * a particular {@link SchemaContext}, but can be reused by multiple {@link JSONNormalizedNodeStreamWriter}s.
  */
 @Beta
-public final class JSONCodecFactory extends AbstractCodecFactory<JSONCodec<?>> {
-    private final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec> iidCodecSupplier;
-    private final JSONCodec<?> iidCodec;
-
-    JSONCodecFactory(final SchemaContext context, final CodecCache<JSONCodec<?>> cache,
-            final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec> iidCodecSupplier) {
+public abstract class JSONCodecFactory extends AbstractCodecFactory<JSONCodec<?>> {
+    JSONCodecFactory(final @NonNull SchemaContext context, final @NonNull CodecCache<JSONCodec<?>> cache) {
         super(context, cache);
-        this.iidCodecSupplier = requireNonNull(iidCodecSupplier);
-        iidCodec = verifyNotNull(iidCodecSupplier.apply(context, this));
     }
 
     @Override
-    protected JSONCodec<?> binaryCodec(final BinaryTypeDefinition type) {
+    protected final JSONCodec<?> binaryCodec(final BinaryTypeDefinition type) {
         return new QuotedJSONCodec<>(BinaryStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> booleanCodec(final BooleanTypeDefinition type) {
+    protected final JSONCodec<?> booleanCodec(final BooleanTypeDefinition type) {
         return new BooleanJSONCodec(BooleanStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> bitsCodec(final BitsTypeDefinition type) {
+    protected final JSONCodec<?> bitsCodec(final BitsTypeDefinition type) {
         return new QuotedJSONCodec<>(BitsStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> decimalCodec(final DecimalTypeDefinition type) {
-        return new NumberJSONCodec<>(DecimalStringCodec.from(type));
+    protected final JSONCodec<?> decimalCodec(final DecimalTypeDefinition type) {
+        return wrapDecimalCodec(DecimalStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> emptyCodec(final EmptyTypeDefinition type) {
+    protected final JSONCodec<?> emptyCodec(final EmptyTypeDefinition type) {
         return EmptyJSONCodec.INSTANCE;
     }
 
     @Override
-    protected JSONCodec<?> enumCodec(final EnumTypeDefinition type) {
+    protected final JSONCodec<?> enumCodec(final EnumTypeDefinition type) {
         return new QuotedJSONCodec<>(EnumStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> identityRefCodec(final IdentityrefTypeDefinition type, final QNameModule module) {
+    protected final JSONCodec<?> identityRefCodec(final IdentityrefTypeDefinition type, final QNameModule module) {
         return new IdentityrefJSONCodec(getSchemaContext(), module);
     }
 
     @Override
-    protected JSONCodec<?> instanceIdentifierCodec(final InstanceIdentifierTypeDefinition type) {
-        return iidCodec;
-    }
-
-    @Override
-    protected JSONCodec<?> int8Codec(final Int8TypeDefinition type) {
+    protected final JSONCodec<?> int8Codec(final Int8TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> int16Codec(final Int16TypeDefinition type) {
+    protected final JSONCodec<?> int16Codec(final Int16TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> int32Codec(final Int32TypeDefinition type) {
+    protected final JSONCodec<?> int32Codec(final Int32TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> int64Codec(final Int64TypeDefinition type) {
-        return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
+    protected final JSONCodec<?> int64Codec(final Int64TypeDefinition type) {
+        return wrapIntegerCodec(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> stringCodec(final StringTypeDefinition type) {
+    protected final JSONCodec<?> stringCodec(final StringTypeDefinition type) {
         return new QuotedJSONCodec<>(StringStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> uint8Codec(final Uint8TypeDefinition type) {
+    protected final JSONCodec<?> uint8Codec(final Uint8TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> uint16Codec(final Uint16TypeDefinition type) {
+    protected final JSONCodec<?> uint16Codec(final Uint16TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> uint32Codec(final Uint32TypeDefinition type) {
+    protected final JSONCodec<?> uint32Codec(final Uint32TypeDefinition type) {
         return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> uint64Codec(final Uint64TypeDefinition type) {
-        return new NumberJSONCodec<>(AbstractIntegerStringCodec.from(type));
+    protected final JSONCodec<?> uint64Codec(final Uint64TypeDefinition type) {
+        return wrapIntegerCodec(AbstractIntegerStringCodec.from(type));
     }
 
     @Override
-    protected JSONCodec<?> unionCodec(final UnionTypeDefinition type, final List<JSONCodec<?>> codecs) {
+    protected final JSONCodec<?> unionCodec(final UnionTypeDefinition type, final List<JSONCodec<?>> codecs) {
         return UnionJSONCodec.create(type, codecs);
     }
 
     @Override
-    protected JSONCodec<?> unknownCodec(final UnknownTypeDefinition type) {
+    protected final JSONCodec<?> unknownCodec(final UnknownTypeDefinition type) {
         return NullJSONCodec.INSTANCE;
     }
 
+    @Override
+    protected abstract JSONCodec<?> instanceIdentifierCodec(InstanceIdentifierTypeDefinition type);
+
     // Returns a one-off factory for the purposes of normalizing an anydata tree.
     //
     // FIXME: 4.0.0: this is really ugly, as we should be able to tell if the new context is the same as ours and
@@ -165,7 +154,13 @@ public final class JSONCodecFactory extends AbstractCodecFactory<JSONCodec<?>> {
     //
     //               The above is not currently possible, as we cannot reference JSONCodecFactorySupplier from the
     //               factory due to that potentially creating a circular reference.
-    JSONCodecFactory rebaseTo(final SchemaContext newSchemaContext) {
-        return new JSONCodecFactory(newSchemaContext, new LazyCodecCache<>(), iidCodecSupplier);
+    final JSONCodecFactory rebaseTo(final SchemaContext newSchemaContext) {
+        return rebaseTo(newSchemaContext, new LazyCodecCache<>());
     }
+
+    abstract JSONCodecFactory rebaseTo(SchemaContext newSchemaContext, CodecCache<JSONCodec<?>> newCache);
+
+    abstract JSONCodec<?> wrapDecimalCodec(DecimalStringCodec decimalCodec);
+
+    abstract JSONCodec<?> wrapIntegerCodec(AbstractIntegerStringCodec<?, ?> integerCodec);
 }
index 23f01a76b3afd8bdded180669bf9c3d529f46da9..4be9b8979462e5dc53ae80717078d3879051a1c3 100644 (file)
@@ -18,6 +18,7 @@ import com.google.common.cache.LoadingCache;
 import java.util.Optional;
 import java.util.function.BiFunction;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.LazyCodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.NoopCodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.PrecomputedCodecCache;
@@ -39,36 +40,43 @@ public enum JSONCodecFactorySupplier {
     /**
      * Source of {@link JSONCodecFactory} instances compliant with RFC7951.
      */
-    // FIXME: YANGTOOLS-766: use a different codec
-    RFC7951(RFC7951JSONInstanceIdentifierCodec::new),
+    RFC7951() {
+        @Override
+        JSONCodecFactory createFactory(final SchemaContext context, final CodecCache<JSONCodec<?>> cache) {
+            return new RFC7951JSONCodecFactory(context, cache);
+        }
+    },
     /**
-     * Source of {@link JSONCodecFactory} instances compliant with RFC7951.
+     * Source of {@link JSONCodecFactory} instances compliant with draft-lhotka-netmod-yang-json-02.
      */
-    DRAFT_LHOTKA_NETMOD_YANG_JSON_02(Lhotka02JSONInstanceIdentifierCodec::new);
+    DRAFT_LHOTKA_NETMOD_YANG_JSON_02() {
+        @Override
+        JSONCodecFactory createFactory(final SchemaContext context, final CodecCache<JSONCodec<?>> cache) {
+            return new Lhotka02JSONCodecFactory(context, cache);
+        }
+    };
 
     private static final Logger LOG = LoggerFactory.getLogger(JSONCodecFactorySupplier.class);
 
     private static final class EagerCacheLoader extends CacheLoader<SchemaContext, JSONCodecFactory> {
-        private final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec>
-            iidCodecSupplier;
+        private final BiFunction<SchemaContext, CodecCache<JSONCodec<?>>, JSONCodecFactory> factorySupplier;
 
-        EagerCacheLoader(final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec>
-                iidCodecSupplier) {
-            this.iidCodecSupplier = requireNonNull(iidCodecSupplier);
+        EagerCacheLoader(final BiFunction<SchemaContext, CodecCache<JSONCodec<?>>, JSONCodecFactory> factorySupplier) {
+            this.factorySupplier = requireNonNull(factorySupplier);
         }
 
         @Override
         public JSONCodecFactory load(final SchemaContext key) {
             final Stopwatch sw = Stopwatch.createStarted();
             final LazyCodecCache<JSONCodec<?>> lazyCache = new LazyCodecCache<>();
-            final JSONCodecFactory lazy = new JSONCodecFactory(key, lazyCache, iidCodecSupplier);
+            final JSONCodecFactory lazy = factorySupplier.apply(key, lazyCache);
             final int visitedLeaves = requestCodecsForChildren(lazy, key);
             sw.stop();
 
             final PrecomputedCodecCache<JSONCodec<?>> cache = lazyCache.toPrecomputed();
             LOG.debug("{} leaf nodes resulted in {} simple and {} complex codecs in {}", visitedLeaves,
                 cache.simpleSize(), cache.complexSize(), sw);
-            return new JSONCodecFactory(key, cache, iidCodecSupplier);
+            return factorySupplier.apply(key, cache);
         }
 
         private static int requestCodecsForChildren(final JSONCodecFactory lazy, final DataNodeContainer parent) {
@@ -86,22 +94,18 @@ public enum JSONCodecFactorySupplier {
         }
     }
 
-    private final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec> iidCodecSupplier;
-
     // Weak keys to retire the entry when SchemaContext goes away
     private final LoadingCache<SchemaContext, JSONCodecFactory> precomputed;
 
     // Weak keys to retire the entry when SchemaContext goes away and to force identity-based lookup
     private final LoadingCache<SchemaContext, JSONCodecFactory> shared;
 
-    JSONCodecFactorySupplier(
-            final BiFunction<SchemaContext, JSONCodecFactory, JSONInstanceIdentifierCodec> iidCodecSupplier) {
-        this.iidCodecSupplier = requireNonNull(iidCodecSupplier);
-        precomputed = CacheBuilder.newBuilder().weakKeys().build(new EagerCacheLoader(iidCodecSupplier));
+    JSONCodecFactorySupplier() {
+        precomputed = CacheBuilder.newBuilder().weakKeys().build(new EagerCacheLoader(this::createFactory));
         shared = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader<SchemaContext, JSONCodecFactory>() {
             @Override
             public JSONCodecFactory load(final SchemaContext key) {
-                return new JSONCodecFactory(key, new SharedCodecCache<>(), iidCodecSupplier);
+                return createFactory(key, new SharedCodecCache<>());
             }
         });
     }
@@ -177,7 +181,7 @@ public enum JSONCodecFactorySupplier {
      * @throws NullPointerException if context is null
      */
     public @NonNull JSONCodecFactory createLazy(final @NonNull SchemaContext context) {
-        return new JSONCodecFactory(context, new LazyCodecCache<>(), iidCodecSupplier);
+        return createFactory(context, new LazyCodecCache<>());
     }
 
     /**
@@ -194,6 +198,8 @@ public enum JSONCodecFactorySupplier {
      * @throws NullPointerException if context is null.
      */
     public @NonNull JSONCodecFactory createSimple(final @NonNull SchemaContext context) {
-        return new JSONCodecFactory(context, NoopCodecCache.getInstance(), iidCodecSupplier);
+        return createFactory(context, NoopCodecCache.getInstance());
     }
+
+    abstract @NonNull JSONCodecFactory createFactory(SchemaContext context, CodecCache<JSONCodec<?>> cache);
 }
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02JSONCodecFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02JSONCodecFactory.java
new file mode 100644 (file)
index 0000000..56ce4a7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import org.opendaylight.yangtools.yang.data.impl.codec.AbstractIntegerStringCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.DecimalStringCodec;
+import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+
+final class Lhotka02JSONCodecFactory extends JSONCodecFactory {
+    private final JSONInstanceIdentifierCodec iidCodec;
+
+    Lhotka02JSONCodecFactory(final SchemaContext context, final CodecCache<JSONCodec<?>> cache) {
+        super(context, cache);
+        iidCodec = new Lhotka02JSONInstanceIdentifierCodec(context, this);
+    }
+
+    @Override
+    protected JSONCodec<?> instanceIdentifierCodec(final InstanceIdentifierTypeDefinition type) {
+        return iidCodec;
+    }
+
+    @Override
+    Lhotka02JSONCodecFactory rebaseTo(final SchemaContext newSchemaContext, final CodecCache<JSONCodec<?>> newCache) {
+        return new Lhotka02JSONCodecFactory(newSchemaContext, newCache);
+    }
+
+    @Override
+    JSONCodec<?> wrapDecimalCodec(final DecimalStringCodec decimalCodec) {
+        return new NumberJSONCodec<>(decimalCodec);
+    }
+
+    @Override
+    JSONCodec<?> wrapIntegerCodec(final AbstractIntegerStringCodec<?, ?> integerCodec) {
+        return new NumberJSONCodec<>(integerCodec);
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951JSONCodecFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951JSONCodecFactory.java
new file mode 100644 (file)
index 0000000..51e7a57
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import org.opendaylight.yangtools.yang.data.impl.codec.AbstractIntegerStringCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.DecimalStringCodec;
+import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+
+final class RFC7951JSONCodecFactory extends JSONCodecFactory {
+    private final RFC7951JSONInstanceIdentifierCodec iidCodec;
+
+    RFC7951JSONCodecFactory(final SchemaContext context, final CodecCache<JSONCodec<?>> cache) {
+        super(context, cache);
+        iidCodec = new RFC7951JSONInstanceIdentifierCodec(context, this);
+    }
+
+    @Override
+    protected JSONCodec<?> instanceIdentifierCodec(final InstanceIdentifierTypeDefinition type) {
+        return iidCodec;
+    }
+
+    @Override
+    JSONCodecFactory rebaseTo(final SchemaContext newSchemaContext, final CodecCache<JSONCodec<?>> newCache) {
+        return new RFC7951JSONCodecFactory(newSchemaContext, newCache);
+    }
+
+    @Override
+    JSONCodec<?> wrapDecimalCodec(final DecimalStringCodec decimalCodec) {
+        return new QuotedJSONCodec<>(decimalCodec);
+    }
+
+    @Override
+    JSONCodec<?> wrapIntegerCodec(final AbstractIntegerStringCodec<?, ?> integerCodec) {
+        return new QuotedJSONCodec<>(integerCodec);
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractYT1027Test.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractYT1027Test.java
new file mode 100644 (file)
index 0000000..2349b14
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static com.google.common.base.Verify.verify;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.google.gson.stream.JsonReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public abstract class AbstractYT1027Test {
+    private static final QName DECIMAL = QName.create("yt1027.test", "decimal");
+    private static final QName INT64 = QName.create(DECIMAL, "int64");
+    private static final QName UINT64 = QName.create(DECIMAL, "uint64");
+
+    static final LeafNode<?> DECIMAL_DATA = ImmutableNodes.leafNode(DECIMAL, new BigDecimal("1.1"));
+    static final LeafNode<?> INT64_DATA = ImmutableNodes.leafNode(INT64, 2L);
+    static final LeafNode<?> UINT64_DATA = ImmutableNodes.leafNode(UINT64, BigInteger.ONE);
+
+    static final String UNQUOTED_DECIMAL = "{\n"
+            + "  \"yt1027:decimal\": 1.1\n"
+            + "}";
+    static final String UNQUOTED_INT64 = "{\n"
+            + "  \"yt1027:int64\": 2\n"
+            + "}";
+    static final String UNQUOTED_UINT64 = "{\n"
+            + "  \"yt1027:uint64\": 1\n"
+            + "}";
+
+    static SchemaContext SCHEMA_CONTEXT;
+    private static DecimalTypeDefinition DECIMAL_TYPE;
+    private static Int64TypeDefinition INT64_TYPE;
+    private static Uint64TypeDefinition UINT64_TYPE;
+
+    @BeforeClass
+    public static void beforeClass() {
+        SCHEMA_CONTEXT = YangParserTestUtils.parseYangResourceDirectory("/yt1027");
+        DECIMAL_TYPE = (DecimalTypeDefinition) getTypeDefinition(DECIMAL);
+        INT64_TYPE = (Int64TypeDefinition) getTypeDefinition(INT64);
+        UINT64_TYPE = (Uint64TypeDefinition) getTypeDefinition(UINT64);
+    }
+
+    private static TypeDefinition<?> getTypeDefinition(final QName name) {
+        DataSchemaNode child = SCHEMA_CONTEXT.findDataTreeChild(name).get();
+        verify(child instanceof LeafSchemaNode);
+        return ((LeafSchemaNode) child).getType();
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        DECIMAL_TYPE = null;
+        INT64_TYPE = null;
+        UINT64_TYPE = null;
+        SCHEMA_CONTEXT = null;
+    }
+
+    @Test
+    public void testDecimal() {
+        assertThat(codecFactory().decimalCodec(DECIMAL_TYPE), instanceOf(wrapperClass()));
+    }
+
+    @Test
+    public void testInt64() {
+        assertThat(codecFactory().int64Codec(INT64_TYPE), instanceOf(wrapperClass()));
+    }
+
+    @Test
+    public void testUint64() {
+        assertThat(codecFactory().uint64Codec(UINT64_TYPE), instanceOf(wrapperClass()));
+    }
+
+    @Test
+    public void testDecimalSerialization() throws IOException {
+        assertEquals(expectedDecimal(), toJSON(DECIMAL_DATA));
+    }
+
+    @Test
+    public void testInt64Serialization() throws IOException {
+        assertEquals(expectedInt64(), toJSON(INT64_DATA));
+    }
+
+    @Test
+    public void testUint64Serialization() throws IOException {
+        assertEquals(expectedUint64(), toJSON(UINT64_DATA));
+    }
+
+    @Test
+    public void testDecimalParsing() throws IOException {
+        assertEquals(DECIMAL_DATA, fromJSON(expectedDecimal()));
+    }
+
+    @Test
+    public void testInt64Parsing() throws IOException {
+        assertEquals(INT64_DATA, fromJSON(expectedInt64()));
+    }
+
+    @Test
+    public void testUint64Parsing() throws IOException {
+        assertEquals(UINT64_DATA, fromJSON(expectedUint64()));
+    }
+
+    abstract JSONCodecFactory codecFactory();
+
+    abstract Class<?> wrapperClass();
+
+    abstract String expectedDecimal();
+
+    abstract String expectedInt64();
+
+    abstract String expectedUint64();
+
+    final NormalizedNode<?, ?> fromJSON(final String input) throws IOException {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, codecFactory());
+        jsonParser.parse(new JsonReader(new StringReader(input)));
+        return result.getResult();
+    }
+
+    private String toJSON(final NormalizedNode<?, ?> input) throws IOException {
+        final Writer writer = new StringWriter();
+        final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.createExclusiveWriter(
+            codecFactory(), SchemaPath.ROOT, null, JsonWriterFactory.createJsonWriter(writer, 2));
+        try (NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream)) {
+            nodeWriter.write(input);
+        }
+
+        return writer.toString();
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02YT1027Test.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/Lhotka02YT1027Test.java
new file mode 100644 (file)
index 0000000..cdeb76f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class Lhotka02YT1027Test extends AbstractYT1027Test {
+    private static JSONCodecFactory CODEC_FACTORY;
+
+    @BeforeClass
+    public static void createFactory() {
+        CODEC_FACTORY = JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(SCHEMA_CONTEXT);
+    }
+
+    @AfterClass
+    public static void destroyFactory() {
+        CODEC_FACTORY = null;
+    }
+
+    @Override
+    JSONCodecFactory codecFactory() {
+        return CODEC_FACTORY;
+    }
+
+    @Override
+    Class<?> wrapperClass() {
+        return NumberJSONCodec.class;
+    }
+
+    @Override
+    String expectedDecimal() {
+        return UNQUOTED_DECIMAL;
+    }
+
+    @Override
+    String expectedInt64() {
+        return UNQUOTED_INT64;
+    }
+
+    @Override
+    String expectedUint64() {
+        return UNQUOTED_UINT64;
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951YT1027Test.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/RFC7951YT1027Test.java
new file mode 100644 (file)
index 0000000..c8e1ff6
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RFC7951YT1027Test extends AbstractYT1027Test {
+    private static JSONCodecFactory CODEC_FACTORY;
+
+    @BeforeClass
+    public static void createFactory() {
+        CODEC_FACTORY = JSONCodecFactorySupplier.RFC7951.getShared(SCHEMA_CONTEXT);
+    }
+
+    @AfterClass
+    public static void destroyFactory() {
+        CODEC_FACTORY = null;
+    }
+
+    @Test
+    public void testDecimalUnquotedParsing() throws IOException {
+        assertEquals(DECIMAL_DATA, fromJSON(UNQUOTED_DECIMAL));
+    }
+
+    @Test
+    public void testInt64UnquotedParsing() throws IOException {
+        assertEquals(INT64_DATA, fromJSON(UNQUOTED_INT64));
+    }
+
+    @Test
+    public void testUint64UnquotedParsing() throws IOException {
+        assertEquals(UINT64_DATA, fromJSON(UNQUOTED_UINT64));
+    }
+
+    @Override
+    JSONCodecFactory codecFactory() {
+        return CODEC_FACTORY;
+    }
+
+    @Override
+    Class<?> wrapperClass() {
+        return QuotedJSONCodec.class;
+    }
+
+    @Override
+    String expectedDecimal() {
+        return "{\n"
+                + "  \"yt1027:decimal\": \"1.1\"\n"
+                + "}";
+    }
+
+    @Override
+    String expectedInt64() {
+        return "{\n"
+                + "  \"yt1027:int64\": \"2\"\n"
+                + "}";
+    }
+
+    @Override
+    String expectedUint64() {
+        return "{\n"
+                + "  \"yt1027:uint64\": \"1\"\n"
+                + "}";
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/test/resources/yt1027/yt1027.yang b/yang/yang-data-codec-gson/src/test/resources/yt1027/yt1027.yang
new file mode 100644 (file)
index 0000000..12e756b
--- /dev/null
@@ -0,0 +1,19 @@
+module yt1027 {
+  namespace "yt1027.test";
+  prefix tst;
+
+  leaf uint64 {
+    type uint64;
+  }
+  leaf int64 {
+    type int64;
+  }
+  leaf decimal {
+    type decimal64 {
+      fraction-digits 1;
+    }
+  }
+}
+