package org.opendaylight.yangtools.yang.data.codec.gson;
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParseException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
in.beginObject();
while (in.hasNext()) {
final String jsonElementName = in.nextName();
- final NamespaceAndName namespaceAndName = resolveNamespace(jsonElementName);
+ final NamespaceAndName namespaceAndName = resolveNamespace(jsonElementName, parent.getSchema());
final String localName = namespaceAndName.getName();
addNamespace(namespaceAndName.getUri());
if (namesakes.contains(jsonElementName)) {
namespaces.pop();
}
- private void addNamespace(final Optional<URI> namespace) {
- if (!namespace.isPresent()) {
- if (namespaces.isEmpty()) {
- throw new IllegalStateException("Namespace has to be specified at top level.");
- } else {
- namespaces.push(namespaces.peek());
- }
- } else {
- namespaces.push(namespace.get());
- }
+ private void addNamespace(final URI namespace) {
+ namespaces.push(namespace);
}
- private NamespaceAndName resolveNamespace(final String childName) {
+ private NamespaceAndName resolveNamespace(final String childName, final DataSchemaNode dataSchemaNode) {
int lastIndexOfColon = childName.lastIndexOf(':');
String moduleNamePart = null;
String nodeNamePart = null;
nodeNamePart = childName;
}
- Optional<URI> namespaceOpt = namespace == null ? Optional.<URI> absent() : Optional.of(namespace);
- return new NamespaceAndName(nodeNamePart, namespaceOpt);
+ if (namespace == null) {
+ Set<URI> potentialUris = Collections.emptySet();
+ potentialUris = resolveAllPotentialNamespaces(nodeNamePart, dataSchemaNode);
+ if (potentialUris.contains(getCurrentNamespace())) {
+ namespace = getCurrentNamespace();
+ } else if (potentialUris.size() == 1) {
+ namespace = potentialUris.iterator().next();
+ } else if (potentialUris.size() > 1) {
+ throw new IllegalStateException("Choose suitable module name for element "+nodeNamePart+":"+toModuleNames(potentialUris));
+ } else if (potentialUris.isEmpty()) {
+ throw new IllegalStateException("Schema node with name "+nodeNamePart+" wasn't found.");
+ }
+ }
+
+ return new NamespaceAndName(nodeNamePart, namespace);
+ }
+
+ private String toModuleNames(Set<URI> potentialUris) {
+ final StringBuilder builder = new StringBuilder();
+ for (URI potentialUri : potentialUris) {
+ builder.append("\n");
+ //FIXME how to get information about revision from JSON input? currently first available is used.
+ builder.append(schema.findModuleByNamespace(potentialUri).iterator().next().getName());
+ }
+ return builder.toString();
+ }
+
+ private Set<URI> resolveAllPotentialNamespaces(final String elementName, final DataSchemaNode dataSchemaNode) {
+ final Set<URI> potentialUris = new HashSet<>();
+ final Set<ChoiceNode> choices = new HashSet<>();
+ if (dataSchemaNode instanceof DataNodeContainer) {
+ for (DataSchemaNode childSchemaNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) {
+ if (childSchemaNode instanceof ChoiceNode) {
+ choices.add((ChoiceNode)childSchemaNode);
+ } else if (childSchemaNode.getQName().getLocalName().equals(elementName)) {
+ potentialUris.add(childSchemaNode.getQName().getNamespace());
+ }
+ }
+
+ for (ChoiceNode choiceNode : choices) {
+ for (ChoiceCaseNode concreteCase : choiceNode.getCases()) {
+ potentialUris.addAll(resolveAllPotentialNamespaces(elementName, concreteCase));
+ }
+ }
+ }
+ return potentialUris;
}
private URI getCurrentNamespace() {
}
private static class NamespaceAndName {
- private final Optional<URI> uri;
+ private final URI uri;
private final String name;
- public NamespaceAndName(final String name, final Optional<URI> uri) {
+ public NamespaceAndName(final String name, final URI uri) {
this.name = name;
this.uri = uri;
}
return name;
}
- public Optional<URI> getUri() {
+ public URI getUri() {
return uri;
}
}
package org.opendaylight.yangtools.yang.data.codec.gson;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadModules;
import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadTextFile;
verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.unkeyedNodeInContainer());
}
+ /**
+ * Top level JSON element contains no information about module name.
+ *
+ * It should be possible to find out potential module name from available schema context.
+ *
+ */
+ @Test
+ public void missingModuleInfoInTopLevelElement() throws IOException, URISyntaxException {
+ String inputJson = loadTextFile("/complexjson/missing-module-in-top-level.json");
+ verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.topLevelContainer());
+ }
+
+ /**
+ *
+ * Exception expected.
+ *
+ * It tests case when several elements with the same name and various namespaces exists and are in JSON specified
+ * without module name prefix.
+ */
+ @Test
+ public void leafNamesakes() throws IOException, URISyntaxException {
+ String inputJson = loadTextFile("/complexjson/namesakes.json");
+ try {
+ //second parameter isn't necessary because error will be raised before it is used.
+ verifyTransformationToNormalizedNode(inputJson, null);
+ } catch (IllegalStateException e) {
+ final String errorMessage = e.getMessage();
+ assertTrue(errorMessage.contains("Choose suitable module name for element lf11-namesake:"));
+ assertTrue(errorMessage.contains("complexjson-augmentation"));
+ assertTrue(errorMessage.contains("complexjson-augmentation-namesake"));
+ }
+ }
+
+ /**
+ *
+ * Exception expected.
+ *
+ * Json input contains element which doesn't exist in YANG schema
+ */
+ @Test
+ public void parsingNotExistingElement() throws IOException, URISyntaxException {
+ String inputJson = loadTextFile("/complexjson/not-existing-element.json");
+ try {
+ //second parameter isn't necessary because error will be raised before it is used.
+ verifyTransformationToNormalizedNode(inputJson, null);
+ } catch (IllegalStateException e) {
+ assertTrue(e.getMessage().contains("Schema node with name dummy-element wasn't found."));
+ }
+ }
+
+
private void verifyTransformationToNormalizedNode(final String inputJson,
final NormalizedNode<?, ?> awaitedStructure) {
NormalizedNodeResult result = new NormalizedNodeResult();