--- /dev/null
+/*
+ * Copyright (c) 2022 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.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.google.gson.JsonIOException;
+import com.google.gson.stream.JsonReader;
+import java.io.IOException;
+import java.io.StringReader;
+import org.junit.jupiter.api.Test;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+class YT1550Test {
+ @Test
+ void testMissingKey() throws Exception {
+ final var modelContext = YangParserTestUtils.parseYang("""
+ module foo {
+ namespace foons;
+ prefix foo;
+
+ list foo {
+ key "one two";
+ leaf one {
+ type string {
+ base one;
+ }
+ }
+ leaf two {
+ type string {
+ base one;
+ }
+ }
+ }
+ }""");
+
+ final var holder = new NormalizationResultHolder();
+ final var factory = JSONCodecFactorySupplier.RFC7951.getShared(modelContext);
+ try (var writer = ImmutableNormalizedNodeStreamWriter.from(holder)) {
+ try (var jsonParser = JsonParserStream.create(writer, factory)) {
+ try (var reader = new JsonReader(new StringReader("""
+ {
+ "foo" : {
+ "one" : "one"
+ }
+ }"""))) {
+
+ final var ex = assertThrows(JsonIOException.class, () -> jsonParser.parse(reader));
+ assertEquals("java.io.IOException: List entry (foons)foo is missing leaf values for [two]",
+ ex.getMessage());
+ final var cause = assertInstanceOf(IOException.class, ex.getCause());
+ assertEquals("List entry (foons)foo is missing leaf values for [two]", cause.getMessage());
+ }
+ }
+ }
+ }
+}
*/
package org.opendaylight.yangtools.yang.data.util;
-import static com.google.common.base.Verify.verify;
-
+import com.google.common.base.VerifyException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.MetadataExtension;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
@Override
void addChild(final AbstractNodeDataWithSchema<?> newChild) {
- final DataSchemaNode childSchema = newChild.getSchema();
- if (childSchema instanceof LeafSchemaNode) {
- final QName childName = childSchema.getQName();
+ if (newChild.getSchema() instanceof LeafSchemaNode leaf) {
+ final var childName = leaf.getQName();
if (predicateTemplate.keySet().contains(childName)) {
- verify(newChild instanceof SimpleNodeDataWithSchema);
- keyValues.put(childName, (SimpleNodeDataWithSchema<?>)newChild);
+ if (newChild instanceof SimpleNodeDataWithSchema<?> simpleChild) {
+ keyValues.put(childName, simpleChild);
+ } else {
+ throw new VerifyException("Unexpected child " + newChild);
+ }
}
}
super.addChild(newChild);
@Override
public void write(final NormalizedNodeStreamWriter writer, final MetadataExtension metaWriter)
throws IOException {
- writer.nextDataSchemaNode(getSchema());
- final NodeIdentifierWithPredicates identifier = NodeIdentifierWithPredicates.of(getSchema().getQName(),
- predicateTemplate.instantiateTransformed(keyValues, (key, node) -> node.getValue()));
+ final var schema = getSchema();
+ writer.nextDataSchemaNode(schema);
+
+ final var nodeType = schema.getQName();
+ final Map<QName, Object> predicates;
+ try {
+ predicates = predicateTemplate.instantiateTransformed(keyValues, (key, node) -> node.getValue());
+ } catch (IllegalArgumentException e) {
+ final var present = keyValues.keySet();
+ final var module = nodeType.getModule();
+ final var missing = predicateTemplate.keySet().stream()
+ .filter(key -> !present.contains(key))
+ .map(key -> module.equals(key.getModule()) ? key.getLocalName() : key)
+ .distinct()
+ .toList();
+ throw new IOException("List entry " + nodeType + " is missing leaf values for " + missing, e);
+ }
- writer.startMapEntryNode(identifier, childSizeHint());
+ writer.startMapEntryNode(NodeIdentifierWithPredicates.of(nodeType, predicates), childSizeHint());
writeMetadata(metaWriter);
super.write(writer, metaWriter);
writer.endNode();
}
static @NonNull ListEntryNodeDataWithSchema forSchema(final ListSchemaNode schema) {
- final List<QName> keyDef = schema.getKeyDefinition();
- return keyDef.isEmpty() ? new Unkeyed(schema) : new Keyed(schema, keyDef);
+ final var keyDef = schema.getKeyDefinition();
+ return keyDef.isEmpty() ? new Unkeyed(schema) : new Keyed(schema, keyDef);
}
}