From: Stephen Kitt Date: Tue, 13 Jun 2017 16:25:59 +0000 (+0200) Subject: Bug 8622: convert sal-rest-docgen to Jackson X-Git-Tag: release/nitrogen~62^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=9bbc46b835a5829afd2070e0a2c463adc23b1614;p=netconf.git Bug 8622: convert sal-rest-docgen to Jackson This removes the requirement for org.json in sal-rest-docgen, which causes bundle wiring issues in Karaf 4 (sal-rest-docgen ends up exporting org.json, which Jackson’s compatibility layer consumes, creating a dependency loop which causes refreshes anytime anything touches the sal-rest-docgen). Change-Id: I877f3e567fdeba3258a19a40f1f9e31bb19df24d Signed-off-by: Stephen Kitt --- diff --git a/restconf/sal-rest-docgen/pom.xml b/restconf/sal-rest-docgen/pom.xml index 8a21e7e244..262448a461 100644 --- a/restconf/sal-rest-docgen/pom.xml +++ b/restconf/sal-rest-docgen/pom.xml @@ -46,10 +46,6 @@ com.fasterxml.jackson.core jackson-databind - - com.fasterxml.jackson.datatype - jackson-datatype-json-org - com.google.guava @@ -62,11 +58,6 @@ jaxrs-api - - org.json - json - - org.opendaylight.controller sal-core-api @@ -145,8 +136,7 @@ org.apache.shiro.web.env - com.fasterxml.jackson.datatype.*, - org.json + com.fasterxml.jackson.datatype.* org.opendaylight.netconf.sal.rest.doc.DocProvider /apidoc diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ApiDocServiceImpl.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ApiDocServiceImpl.java index 2f22fa9a42..f5002e0371 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ApiDocServiceImpl.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ApiDocServiceImpl.java @@ -7,13 +7,14 @@ */ package org.opendaylight.netconf.sal.rest.doc.impl; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.Map.Entry; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import org.json.JSONWriter; import org.opendaylight.netconf.sal.rest.doc.api.ApiDocService; import org.opendaylight.netconf.sal.rest.doc.mountpoints.MountPointSwagger; import org.opendaylight.netconf.sal.rest.doc.swagger.ApiDeclaration; @@ -86,16 +87,16 @@ public class ApiDocServiceImpl implements ApiDocService { public synchronized Response getListOfMounts(final UriInfo uriInfo) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (OutputStreamWriter streamWriter = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) { - final JSONWriter writer = new JSONWriter(streamWriter); - writer.array(); + JsonGenerator writer = new JsonFactory().createGenerator(streamWriter); + writer.writeStartArray(); for (final Entry entry : MountPointSwagger.getInstance().getInstanceIdentifiers() .entrySet()) { - writer.object(); - writer.key("instance").value(entry.getKey()); - writer.key("id").value(entry.getValue()); - writer.endObject(); + writer.writeStartObject(); + writer.writeObjectField("instance", entry.getKey()); + writer.writeObjectField("id", entry.getValue()); + writer.writeEndObject(); } - writer.endArray(); + writer.writeEndArray(); } catch (final Exception e) { return Response.status(500).entity(e.getMessage()).build(); } diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java index 7ffc4c5816..91612c1eac 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java @@ -11,7 +11,7 @@ import static org.opendaylight.netconf.sal.rest.doc.util.RestDocgenUtil.resolveP import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Preconditions; import java.io.IOException; import java.net.URI; @@ -28,8 +28,6 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.ws.rs.core.UriInfo; -import org.json.JSONException; -import org.json.JSONObject; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Delete; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Get; @@ -72,7 +70,6 @@ public class BaseYangSwaggerGenerator { private static boolean newDraft; protected BaseYangSwaggerGenerator() { - this.mapper.registerModule(new JsonOrgModule()); this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true); } @@ -231,7 +228,7 @@ public class BaseYangSwaggerGenerator { if (!apis.isEmpty()) { doc.setApis(apis); - JSONObject models = null; + ObjectNode models = null; try { models = this.jsonConverter.convertToJsonSchema(module, schemaContext); @@ -239,7 +236,7 @@ public class BaseYangSwaggerGenerator { if (LOG.isDebugEnabled()) { LOG.debug(this.mapper.writeValueAsString(doc)); } - } catch (IOException | JSONException e) { + } catch (IOException e) { LOG.error("Exception occured in ModelGenerator", e); } diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ModelGenerator.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ModelGenerator.java index f4ba8d4189..5149200a09 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ModelGenerator.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/ModelGenerator.java @@ -9,17 +9,18 @@ package org.opendaylight.netconf.sal.rest.doc.impl; import static org.opendaylight.netconf.sal.rest.doc.util.RestDocgenUtil.resolveNodesName; -import com.google.common.base.Optional; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import com.mifmif.common.regex.Generex; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import javax.annotation.concurrent.NotThreadSafe; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder; import org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.Post; import org.opendaylight.yangtools.yang.common.QName; @@ -103,14 +104,13 @@ public class ModelGenerator { * * @param module - Yang module to be converted * @param schemaContext - SchemaContext of all Yang files used by Api Doc - * @return JSONObject containing data used for creating examples and models in Api Doc + * @return ObjectNode containing data used for creating examples and models in Api Doc * @throws IOException if I/O operation fails - * @throws JSONException when things are amiss */ - public JSONObject convertToJsonSchema(final Module module, - final SchemaContext schemaContext) throws IOException, JSONException { - final JSONObject models = new JSONObject(); - models.put(UNIQUE_EMPTY_IDENTIFIER, new JSONObject()); + public ObjectNode convertToJsonSchema(final Module module, + final SchemaContext schemaContext) throws IOException { + final ObjectNode models = JsonNodeFactory.instance.objectNode(); + models.put(UNIQUE_EMPTY_IDENTIFIER, NullNode.getInstance()); topLevelModule = module; processModules(module, models, schemaContext); processContainersAndLists(module, models, schemaContext); @@ -119,14 +119,14 @@ public class ModelGenerator { return models; } - private void processModules(final Module module, final JSONObject models, - final SchemaContext schemaContext) throws JSONException { + private void processModules(final Module module, final ObjectNode models, + final SchemaContext schemaContext) { createConcreteModelForPost(models, module.getName() + BaseYangSwaggerGenerator.MODULE_NAME_SUFFIX, createPropertiesForPost(module, schemaContext, module.getName())); } - private void processContainersAndLists(final Module module, final JSONObject models, - final SchemaContext schemaContext) throws IOException, JSONException { + private void processContainersAndLists(final Module module, final ObjectNode models, + final SchemaContext schemaContext) throws IOException { final String moduleName = module.getName(); for (final DataSchemaNode childNode : module.getChildNodes()) { @@ -144,22 +144,20 @@ public class ModelGenerator { * for each RPC that contains input & output elements. * * @param module module - * @throws JSONException when things are amiss * @throws IOException if I/O operation fails */ - private void processRPCs(final Module module, final JSONObject models, - final SchemaContext schemaContext) throws JSONException, - IOException { + private void processRPCs(final Module module, final ObjectNode models, + final SchemaContext schemaContext) throws IOException { final Set rpcs = module.getRpcs(); final String moduleName = module.getName(); for (final RpcDefinition rpc : rpcs) { final ContainerSchemaNode input = rpc.getInput(); if (!input.getChildNodes().isEmpty()) { - final JSONObject properties = + final ObjectNode properties = processChildren(input.getChildNodes(), moduleName, models, true, schemaContext); final String filename = "(" + rpc.getQName().getLocalName() + ")input"; - final JSONObject childSchema = getSchemaTemplate(); + final ObjectNode childSchema = getSchemaTemplate(); childSchema.put(TYPE_KEY, OBJECT_TYPE); childSchema.put(PROPERTIES_KEY, properties); childSchema.put(ID_KEY, filename); @@ -170,10 +168,10 @@ public class ModelGenerator { final ContainerSchemaNode output = rpc.getOutput(); if (!output.getChildNodes().isEmpty()) { - final JSONObject properties = + final ObjectNode properties = processChildren(output.getChildNodes(), moduleName, models, true, schemaContext); final String filename = "(" + rpc.getQName().getLocalName() + ")output"; - final JSONObject childSchema = getSchemaTemplate(); + final ObjectNode childSchema = getSchemaTemplate(); childSchema.put(TYPE_KEY, OBJECT_TYPE); childSchema.put(PROPERTIES_KEY, properties); childSchema.put(ID_KEY, filename); @@ -184,18 +182,18 @@ public class ModelGenerator { } } - private JSONObject processTopData(final String filename, final JSONObject models, final SchemaNode schemaNode) { - final JSONObject items = new JSONObject(); + private ObjectNode processTopData(final String filename, final ObjectNode models, final SchemaNode schemaNode) { + final ObjectNode items = JsonNodeFactory.instance.objectNode(); items.put(REF_KEY, filename); - final JSONObject dataNodeProperties = new JSONObject(); + final ObjectNode dataNodeProperties = JsonNodeFactory.instance.objectNode(); dataNodeProperties.put(TYPE_KEY, schemaNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE); dataNodeProperties.put(ITEMS_KEY, items); - dataNodeProperties.putOpt(DESCRIPTION_KEY, schemaNode.getDescription()); - final JSONObject properties = new JSONObject(); + putIfNonNull(dataNodeProperties, DESCRIPTION_KEY, schemaNode.getDescription()); + final ObjectNode properties = JsonNodeFactory.instance.objectNode(); properties.put(topLevelModule.getName() + ":" + schemaNode.getQName().getLocalName(), dataNodeProperties); - final JSONObject finalChildSchema = getSchemaTemplate(); + final ObjectNode finalChildSchema = getSchemaTemplate(); finalChildSchema.put(TYPE_KEY, OBJECT_TYPE); finalChildSchema.put(PROPERTIES_KEY, properties); finalChildSchema.put(ID_KEY, filename + OperationBuilder.TOP); @@ -208,42 +206,42 @@ public class ModelGenerator { * Processes the 'identity' statement in a yang model and maps it to a 'model' in the Swagger JSON spec. * * @param module The module from which the identity stmt will be processed - * @param models The JSONObject in which the parsed identity will be put as a 'model' obj + * @param models The ObjectNode in which the parsed identity will be put as a 'model' obj */ - private static void processIdentities(final Module module, final JSONObject models) throws JSONException { + private static void processIdentities(final Module module, final ObjectNode models) { final String moduleName = module.getName(); final Set idNodes = module.getIdentities(); LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size()); for (final IdentitySchemaNode idNode : idNodes) { - final JSONObject identityObj = new JSONObject(); + final ObjectNode identityObj = JsonNodeFactory.instance.objectNode(); final String identityName = idNode.getQName().getLocalName(); LOG.debug("Processing Identity: {}", identityName); identityObj.put(ID_KEY, identityName); - identityObj.put(DESCRIPTION_KEY, idNode.getDescription()); + putIfNonNull(identityObj, DESCRIPTION_KEY, idNode.getDescription()); - final JSONObject props = new JSONObject(); + final ObjectNode props = JsonNodeFactory.instance.objectNode(); final IdentitySchemaNode baseId = idNode.getBaseIdentity(); if (baseId == null) { - /** + /* * This is a base identity. So lets see if it has sub types. If it does, then add them to the model * definition. */ final Set derivedIds = idNode.getDerivedIdentities(); if (derivedIds != null) { - final JSONArray subTypes = new JSONArray(); + final ArrayNode subTypes = new ArrayNode(JsonNodeFactory.instance); for (final IdentitySchemaNode derivedId : derivedIds) { - subTypes.put(derivedId.getQName().getLocalName()); + subTypes.add(derivedId.getQName().getLocalName()); } identityObj.put(SUB_TYPES_KEY, subTypes); } } else { - /** + /* * This is a derived entity. Add it's base type & move on. */ props.put(TYPE_KEY, baseId.getQName().getLocalName()); @@ -255,18 +253,18 @@ public class ModelGenerator { } } - private JSONObject processDataNodeContainer( - final DataNodeContainer dataNode, final String parentName, final JSONObject models, final boolean isConfig, - final SchemaContext schemaContext) throws JSONException, IOException { + private ObjectNode processDataNodeContainer( + final DataNodeContainer dataNode, final String parentName, final ObjectNode models, final boolean isConfig, + final SchemaContext schemaContext) throws IOException { if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) { final Iterable containerChildren = dataNode.getChildNodes(); final String localName = ((SchemaNode) dataNode).getQName().getLocalName(); - final JSONObject properties = + final ObjectNode properties = processChildren(containerChildren, parentName + "/" + localName, models, isConfig, schemaContext); final String nodeName = parentName + (isConfig ? OperationBuilder.CONFIG : OperationBuilder.OPERATIONAL) + localName; - final JSONObject childSchema = getSchemaTemplate(); + final ObjectNode childSchema = getSchemaTemplate(); childSchema.put(TYPE_KEY, OBJECT_TYPE); childSchema.put(PROPERTIES_KEY, properties); @@ -283,30 +281,29 @@ public class ModelGenerator { return null; } - private static void createConcreteModelForPost(final JSONObject models, final String localName, - final JSONObject properties) throws JSONException { + private static void createConcreteModelForPost(final ObjectNode models, final String localName, + final JsonNode properties) { final String nodePostName = OperationBuilder.CONFIG + localName + Post.METHOD_NAME; - final JSONObject postSchema = getSchemaTemplate(); + final ObjectNode postSchema = getSchemaTemplate(); postSchema.put(TYPE_KEY, OBJECT_TYPE); postSchema.put(ID_KEY, nodePostName); postSchema.put(PROPERTIES_KEY, properties); models.put(nodePostName, postSchema); } - private JSONObject createPropertiesForPost(final DataNodeContainer dataNodeContainer, - final SchemaContext schemaContext, final String parentName) - throws JSONException { - final JSONObject properties = new JSONObject(); + private JsonNode createPropertiesForPost(final DataNodeContainer dataNodeContainer, + final SchemaContext schemaContext, final String parentName) { + final ObjectNode properties = JsonNodeFactory.instance.objectNode(); for (final DataSchemaNode childNode : dataNodeContainer.getChildNodes()) { if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) { - final JSONObject items = new JSONObject(); + final ObjectNode items = JsonNodeFactory.instance.objectNode(); items.put(REF_KEY, parentName + "(config)" + childNode.getQName().getLocalName()); - final JSONObject property = new JSONObject(); + final ObjectNode property = JsonNodeFactory.instance.objectNode(); property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE); property.put(ITEMS_KEY, items); properties.put(childNode.getQName().getLocalName(), property); } else if (childNode instanceof LeafSchemaNode) { - final JSONObject property = processLeafNode((LeafSchemaNode) childNode, schemaContext); + final ObjectNode property = processLeafNode((LeafSchemaNode) childNode, schemaContext); properties.put(childNode.getQName().getLocalName(), property); } } @@ -316,15 +313,14 @@ public class ModelGenerator { /** * Processes the nodes. */ - private JSONObject processChildren( - final Iterable nodes, final String parentName, final JSONObject models, - final boolean isConfig, final SchemaContext schemaContext) - throws JSONException, IOException { - final JSONObject properties = new JSONObject(); + private ObjectNode processChildren( + final Iterable nodes, final String parentName, final ObjectNode models, + final boolean isConfig, final SchemaContext schemaContext) throws IOException { + final ObjectNode properties = JsonNodeFactory.instance.objectNode(); for (final DataSchemaNode node : nodes) { if (node.isConfiguration() == isConfig) { final String name = resolveNodesName(node, topLevelModule, schemaContext); - final JSONObject property; + final ObjectNode property; if (node instanceof LeafSchemaNode) { property = processLeafNode((LeafSchemaNode) node, schemaContext); @@ -352,22 +348,22 @@ public class ModelGenerator { } else { throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass()); } - property.putOpt(DESCRIPTION_KEY, node.getDescription()); + putIfNonNull(property, DESCRIPTION_KEY, node.getDescription()); properties.put(topLevelModule.getName() + ":" + name, property); } } return properties; } - private JSONObject processLeafListNode(final LeafListSchemaNode listNode, - final SchemaContext schemaContext) throws JSONException { - final JSONObject props = new JSONObject(); + private ObjectNode processLeafListNode(final LeafListSchemaNode listNode, + final SchemaContext schemaContext) { + final ObjectNode props = JsonNodeFactory.instance.objectNode(); props.put(TYPE_KEY, ARRAY_TYPE); - final JSONObject itemsVal = new JSONObject(); + final ObjectNode itemsVal = JsonNodeFactory.instance.objectNode(); final ConstraintDefinition constraints = listNode.getConstraints(); - final Optional maxOptional = Optional.fromNullable(constraints.getMaxElements()); - if (maxOptional.or(2) >= 2) { + int max = constraints.getMaxElements() == null ? 2 : constraints.getMaxElements(); + if (max >= 2) { processTypeDef(listNode.getType(), listNode, itemsVal, schemaContext); processTypeDef(listNode.getType(), listNode, itemsVal, schemaContext); } else { @@ -382,12 +378,12 @@ public class ModelGenerator { } private void processChoiceNode( - final Iterable nodes, final String moduleName, final JSONObject models, - final SchemaContext schemaContext, final boolean isConfig, final JSONObject properties) - throws JSONException, IOException { + final Iterable nodes, final String moduleName, final ObjectNode models, + final SchemaContext schemaContext, final boolean isConfig, final ObjectNode properties) + throws IOException { for (final DataSchemaNode node : nodes) { final String name = resolveNodesName(node, topLevelModule, schemaContext); - final JSONObject property; + final ObjectNode property; if (node instanceof LeafSchemaNode) { property = processLeafNode((LeafSchemaNode) node, schemaContext); @@ -417,13 +413,13 @@ public class ModelGenerator { throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass()); } - property.putOpt(DESCRIPTION_KEY, node.getDescription()); + putIfNonNull(property, DESCRIPTION_KEY, node.getDescription()); properties.put(name, property); } } private static void processConstraints(final ConstraintDefinition constraints, - final JSONObject props) throws JSONException { + final ObjectNode props) { final boolean isMandatory = constraints.isMandatory(); props.put(REQUIRED_KEY, isMandatory); @@ -437,23 +433,23 @@ public class ModelGenerator { } } - private JSONObject processLeafNode(final LeafSchemaNode leafNode, - final SchemaContext schemaContext) throws JSONException { - final JSONObject property = new JSONObject(); + private ObjectNode processLeafNode(final LeafSchemaNode leafNode, + final SchemaContext schemaContext) { + final ObjectNode property = JsonNodeFactory.instance.objectNode(); final String leafDescription = leafNode.getDescription(); - property.put(DESCRIPTION_KEY, leafDescription); + putIfNonNull(property, DESCRIPTION_KEY, leafDescription); processConstraints(leafNode.getConstraints(), property); processTypeDef(leafNode.getType(), leafNode, property, schemaContext); return property; } - private static JSONObject processAnyXMLNode(final AnyXmlSchemaNode leafNode) throws JSONException { - final JSONObject property = new JSONObject(); + private static ObjectNode processAnyXMLNode(final AnyXmlSchemaNode leafNode) { + final ObjectNode property = JsonNodeFactory.instance.objectNode(); final String leafDescription = leafNode.getDescription(); - property.put(DESCRIPTION_KEY, leafDescription); + putIfNonNull(property, DESCRIPTION_KEY, leafDescription); processConstraints(leafNode.getConstraints(), property); final String localName = leafNode.getQName().getLocalName(); @@ -463,7 +459,7 @@ public class ModelGenerator { } private String processTypeDef(final TypeDefinition leafTypeDef, final DataSchemaNode node, - final JSONObject property, final SchemaContext schemaContext) throws JSONException { + final ObjectNode property, final SchemaContext schemaContext) { final String jsonType; if (leafTypeDef.getDefaultValue() == null) { if (leafTypeDef instanceof BinaryTypeDefinition) { @@ -514,11 +510,11 @@ public class ModelGenerator { } else { jsonType = String.valueOf(leafTypeDef.getDefaultValue()); } - property.putOpt(TYPE_KEY, jsonType); + putIfNonNull(property, TYPE_KEY, jsonType); return jsonType; } - private String processLeafRef(final DataSchemaNode node, final JSONObject property, + private String processLeafRef(final DataSchemaNode node, final ObjectNode property, final SchemaContext schemaContext, final TypeDefinition leafTypeDef) { RevisionAwareXPath xpath = ((LeafrefTypeDefinition) leafTypeDef).getPathStatement(); final SchemaNode schemaNode; @@ -544,42 +540,41 @@ public class ModelGenerator { .findModuleByNamespaceAndRevision(qualifiedName.getNamespace(), qualifiedName.getRevision()); } - private static String processBinaryType(final JSONObject property) throws JSONException { - final JSONObject media = new JSONObject(); + private static String processBinaryType(final ObjectNode property) { + final ObjectNode media = JsonNodeFactory.instance.objectNode(); media.put(BINARY_ENCODING_KEY, BASE_64); property.put(MEDIA_KEY, media); return "bin1 bin2"; } private static String processEnumType(final EnumTypeDefinition enumLeafType, - final JSONObject property) throws JSONException { + final ObjectNode property) { final List enumPairs = enumLeafType.getValues(); - final List enumNames = new ArrayList<>(); + ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance); for (final EnumPair enumPair : enumPairs) { - enumNames.add(enumPair.getName()); + enumNames.add(new TextNode(enumPair.getName())); } - property.putOpt(ENUM, new JSONArray(enumNames)); + property.put(ENUM, enumNames); return enumLeafType.getValues().iterator().next().getName(); } private static String processBitsType(final BitsTypeDefinition bitsType, - final JSONObject property) throws JSONException { + final ObjectNode property) { property.put(MIN_ITEMS, 0); property.put(UNIQUE_ITEMS_KEY, true); - final List enumNames = new ArrayList<>(); + ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance); final List bits = bitsType.getBits(); for (final Bit bit : bits) { - enumNames.add(bit.getName()); + enumNames.add(new TextNode(bit.getName())); } - property.put(ENUM, new JSONArray(enumNames)); + property.put(ENUM, enumNames); return enumNames.iterator().next() + " " + enumNames.get(enumNames.size() - 1); } private static String processStringType(final TypeDefinition stringType, - final JSONObject property, final String nodeName) - throws JSONException { + final ObjectNode property, final String nodeName) { StringTypeDefinition type = (StringTypeDefinition) stringType; List lengthConstraints = ((StringTypeDefinition) stringType).getLengthConstraints(); while (lengthConstraints.isEmpty() && type.getBaseType() != null) { @@ -592,8 +587,8 @@ public class ModelGenerator { for (final LengthConstraint lengthConstraint : lengthConstraints) { final Number min = lengthConstraint.getMin(); final Number max = lengthConstraint.getMax(); - property.putOpt(MIN_LENGTH_KEY, min); - property.putOpt(MAX_LENGTH_KEY, max); + putIfNonNull(property, MIN_LENGTH_KEY, min); + putIfNonNull(property, MAX_LENGTH_KEY, max); } if (type.getPatternConstraints().iterator().hasNext()) { final PatternConstraint pattern = type.getPatternConstraints().iterator().next(); @@ -606,25 +601,46 @@ public class ModelGenerator { } } - private String processUnionType(final UnionTypeDefinition unionType, final JSONObject property, - final SchemaContext schemaContext, final DataSchemaNode node) - throws JSONException { - final List unionNames = new ArrayList<>(); + private String processUnionType(final UnionTypeDefinition unionType, final ObjectNode property, + final SchemaContext schemaContext, final DataSchemaNode node) { + final ArrayNode unionNames = new ArrayNode(JsonNodeFactory.instance); for (final TypeDefinition typeDef : unionType.getTypes()) { unionNames.add(processTypeDef(typeDef, node, property, schemaContext)); } - property.put(ENUM, new JSONArray(unionNames)); - return unionNames.iterator().next(); + property.put(ENUM, unionNames); + return unionNames.iterator().next().asText(); } /** * Helper method to generate a pre-filled JSON schema object. */ - private static JSONObject getSchemaTemplate() throws JSONException { - final JSONObject schemaJSON = new JSONObject(); + private static ObjectNode getSchemaTemplate() { + final ObjectNode schemaJSON = JsonNodeFactory.instance.objectNode(); schemaJSON.put(SCHEMA_KEY, SCHEMA_URL); return schemaJSON; } + private static void putIfNonNull(ObjectNode property, String key, Number number) { + if (key != null && number != null) { + if (number instanceof Double) { + property.put(key, (Double) number); + } else if (number instanceof Float) { + property.put(key, (Float) number); + } else if (number instanceof Integer) { + property.put(key, (Integer) number); + } else if (number instanceof Short) { + property.put(key, (Short) number); + } else if (number instanceof Long) { + property.put(key, (Long) number); + } + } + } + + private static void putIfNonNull(ObjectNode property, String key, String value) { + if (key != null && value != null) { + property.put(key, value); + } + } + } \ No newline at end of file diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/jaxrs/JaxbContextResolver.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/jaxrs/JaxbContextResolver.java index de8c5bc501..a8baa7774c 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/jaxrs/JaxbContextResolver.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/jaxrs/JaxbContextResolver.java @@ -9,7 +9,6 @@ package org.opendaylight.netconf.sal.rest.doc.jaxrs; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @@ -26,7 +25,6 @@ public class JaxbContextResolver implements ContextResolver { public JaxbContextResolver() { ctx = new ObjectMapper(); - ctx.registerModule(new JsonOrgModule()); ctx.getSerializationConfig().withSerializationInclusion(JsonInclude.Include.ALWAYS); } diff --git a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/swagger/ApiDeclaration.java b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/swagger/ApiDeclaration.java index 3d735ac2f6..00c6de8fe3 100644 --- a/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/swagger/ApiDeclaration.java +++ b/restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/swagger/ApiDeclaration.java @@ -7,8 +7,8 @@ */ package org.opendaylight.netconf.sal.rest.doc.swagger; +import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.List; -import org.json.JSONObject; /** * Implementation of swagger spec (see produces; private List apis; - private JSONObject models; + private ObjectNode models; - public JSONObject getModels() { + public ObjectNode getModels() { return models; } - public void setModels(JSONObject models) { + public void setModels(ObjectNode models) { this.models = models; } @@ -86,6 +86,6 @@ public class ApiDeclaration { } public boolean hasModel() { - return (models != null && models.length() > 0); + return (models != null && models.size() > 0); } } diff --git a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java index 91cbcec2c7..50fe6b6225 100644 --- a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java +++ b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java @@ -13,6 +13,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Preconditions; import java.sql.Date; import java.util.Arrays; @@ -21,8 +23,6 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.ws.rs.core.UriInfo; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -164,72 +164,67 @@ public class ApiDocGeneratorTest { * Validates whether doc {@code doc} contains concrete specified models. */ private void validateSwaggerModules(final ApiDeclaration doc) { - final JSONObject models = doc.getModels(); + final ObjectNode models = doc.getModels(); assertNotNull(models); - try { - final JSONObject configLstTop = models.getJSONObject("toaster2(config)lst-TOP"); - assertNotNull(configLstTop); - containsReferences(configLstTop, "toaster2:lst", "toaster2(config)"); + final JsonNode configLstTop = models.get("toaster2(config)lst-TOP"); + assertNotNull(configLstTop); - final JSONObject configLst = models.getJSONObject("toaster2(config)lst"); - assertNotNull(configLst); + containsReferences(configLstTop, "toaster2:lst", "toaster2(config)"); - containsReferences(configLst, "toaster2:lst1", "toaster2/lst(config)"); - containsReferences(configLst, "toaster2:cont1", "toaster2/lst(config)"); + final JsonNode configLst = models.get("toaster2(config)lst"); + assertNotNull(configLst); - final JSONObject configLst1Top = models.getJSONObject("toaster2/lst(config)lst1-TOP"); - assertNotNull(configLst1Top); + containsReferences(configLst, "toaster2:lst1", "toaster2/lst(config)"); + containsReferences(configLst, "toaster2:cont1", "toaster2/lst(config)"); - containsReferences(configLst1Top, "toaster2:lst1", "toaster2/lst(config)"); + final JsonNode configLst1Top = models.get("toaster2/lst(config)lst1-TOP"); + assertNotNull(configLst1Top); - final JSONObject configLst1 = models.getJSONObject("toaster2/lst(config)lst1"); - assertNotNull(configLst1); + containsReferences(configLst1Top, "toaster2:lst1", "toaster2/lst(config)"); - final JSONObject configCont1Top = models.getJSONObject("toaster2/lst(config)cont1-TOP"); - assertNotNull(configCont1Top); + final JsonNode configLst1 = models.get("toaster2/lst(config)lst1"); + assertNotNull(configLst1); - containsReferences(configCont1Top, "toaster2:cont1", "toaster2/lst(config)"); - final JSONObject configCont1 = models.getJSONObject("toaster2/lst(config)cont1"); - assertNotNull(configCont1); + final JsonNode configCont1Top = models.get("toaster2/lst(config)cont1-TOP"); + assertNotNull(configCont1Top); - containsReferences(configCont1, "toaster2:cont11", "toaster2/lst/cont1(config)"); - containsReferences(configCont1, "toaster2:lst11", "toaster2/lst/cont1(config)"); + containsReferences(configCont1Top, "toaster2:cont1", "toaster2/lst(config)"); + final JsonNode configCont1 = models.get("toaster2/lst(config)cont1"); + assertNotNull(configCont1); - final JSONObject configCont11Top = models.getJSONObject("toaster2/lst/cont1(config)cont11-TOP"); - assertNotNull(configCont11Top); + containsReferences(configCont1, "toaster2:cont11", "toaster2/lst/cont1(config)"); + containsReferences(configCont1, "toaster2:lst11", "toaster2/lst/cont1(config)"); - containsReferences(configCont11Top, "toaster2:cont11", "toaster2/lst/cont1(config)"); - final JSONObject configCont11 = models.getJSONObject("toaster2/lst/cont1(config)cont11"); - assertNotNull(configCont11); + final JsonNode configCont11Top = models.get("toaster2/lst/cont1(config)cont11-TOP"); + assertNotNull(configCont11Top); - final JSONObject configlst11Top = models.getJSONObject("toaster2/lst/cont1(config)lst11-TOP"); - assertNotNull(configlst11Top); + containsReferences(configCont11Top, "toaster2:cont11", "toaster2/lst/cont1(config)"); + final JsonNode configCont11 = models.get("toaster2/lst/cont1(config)cont11"); + assertNotNull(configCont11); - containsReferences(configlst11Top, "toaster2:lst11", "toaster2/lst/cont1(config)"); - final JSONObject configLst11 = models.getJSONObject("toaster2/lst/cont1(config)lst11"); - assertNotNull(configLst11); - } catch (final JSONException e) { - fail("JSONException wasn't expected"); - } + final JsonNode configlst11Top = models.get("toaster2/lst/cont1(config)lst11-TOP"); + assertNotNull(configlst11Top); + containsReferences(configlst11Top, "toaster2:lst11", "toaster2/lst/cont1(config)"); + final JsonNode configLst11 = models.get("toaster2/lst/cont1(config)lst11"); + assertNotNull(configLst11); } /** * Checks whether object {@code mainObject} contains in properties/items key $ref with concrete value. */ - private void containsReferences(final JSONObject mainObject, final String childObject, final String prefix) - throws JSONException { - final JSONObject properties = mainObject.getJSONObject("properties"); + private void containsReferences(final JsonNode mainObject, final String childObject, final String prefix) { + final JsonNode properties = mainObject.get("properties"); assertNotNull(properties); - final JSONObject nodeInProperties = properties.getJSONObject(childObject); + final JsonNode nodeInProperties = properties.get(childObject); assertNotNull(nodeInProperties); - final JSONObject itemsInNodeInProperties = nodeInProperties.getJSONObject("items"); + final JsonNode itemsInNodeInProperties = nodeInProperties.get("items"); assertNotNull(itemsInNodeInProperties); - final String itemRef = itemsInNodeInProperties.getString("$ref"); + final String itemRef = itemsInNodeInProperties.get("$ref").asText(); assertEquals(prefix + childObject.split(":")[1], itemRef); } @@ -246,7 +241,7 @@ public class ApiDocGeneratorTest { // testing bugs.opendaylight.org bug 1290. UnionType model type. final String jsonString = doc.getModels().toString(); - assertTrue(jsonString.contains("testUnion\":{\"type\":\"-2147483648\",\"required\":false," + assertTrue(jsonString.contains("testUnion\":{\"required\":false,\"type\":\"-2147483648\"," + "\"enum\":[\"-2147483648\",\"Some testUnion\"]}")); } } @@ -263,13 +258,13 @@ public class ApiDocGeneratorTest { this.schemaContext); assertNotNull(doc); - final JSONObject models = doc.getModels(); - final JSONObject inputTop = models.getJSONObject("(make-toast)input-TOP"); + final ObjectNode models = doc.getModels(); + final JsonNode inputTop = models.get("(make-toast)input-TOP"); final String testString = "{\"toaster:input\":{\"type\":\"object\",\"items\":{\"$ref\":\"(make-toast)input\"}}}"; - assertEquals(testString, inputTop.getJSONObject("properties").toString()); - final JSONObject input = models.getJSONObject("(make-toast)input"); - final JSONObject properties = input.getJSONObject("properties"); + assertEquals(testString, inputTop.get("properties").toString()); + final JsonNode input = models.get("(make-toast)input"); + final JsonNode properties = input.get("properties"); assertTrue(properties.has("toaster:toasterDoneness")); assertTrue(properties.has("toaster:toasterToastType")); } @@ -322,7 +317,7 @@ public class ApiDocGeneratorTest { // TODO: we should really do some more validation of the // documentation... - /** + /* * Missing validation: Explicit validation of URLs, and their methods Input / output models. */ } @@ -355,28 +350,24 @@ public class ApiDocGeneratorTest { } private void validateTosterDocContainsModulePrefixes(final ApiDeclaration doc) { - final JSONObject topLevelJson = doc.getModels(); - try { - final JSONObject configToaster = topLevelJson.getJSONObject("toaster2(config)toaster"); - assertNotNull("(config)toaster JSON object missing", configToaster); - // without module prefix - containsProperties(configToaster, "toaster2:toasterSlot"); - - final JSONObject toasterSlot = topLevelJson.getJSONObject("toaster2/toaster(config)toasterSlot"); - assertNotNull("(config)toasterSlot JSON object missing", toasterSlot); - // with module prefix - containsProperties(toasterSlot, "toaster2:toaster-augmented:slotInfo"); - - } catch (final JSONException e) { - fail("Json exception while reading JSON object. Original message " + e.getMessage()); - } + final ObjectNode topLevelJson = doc.getModels(); + + final JsonNode configToaster = topLevelJson.get("toaster2(config)toaster"); + assertNotNull("(config)toaster JSON object missing", configToaster); + // without module prefix + containsProperties(configToaster, "toaster2:toasterSlot"); + + final JsonNode toasterSlot = topLevelJson.get("toaster2/toaster(config)toasterSlot"); + assertNotNull("(config)toasterSlot JSON object missing", toasterSlot); + // with module prefix + containsProperties(toasterSlot, "toaster2:toaster-augmented:slotInfo"); } - private void containsProperties(final JSONObject jsonObject, final String... properties) throws JSONException { + private void containsProperties(final JsonNode jsonObject, final String... properties) { for (final String property : properties) { - final JSONObject propertiesObject = jsonObject.getJSONObject("properties"); + final JsonNode propertiesObject = jsonObject.get("properties"); assertNotNull("Properties object missing in ", propertiesObject); - final JSONObject concretePropertyObject = propertiesObject.getJSONObject(property); + final JsonNode concretePropertyObject = propertiesObject.get(property); assertNotNull(property + " is missing", concretePropertyObject); } } diff --git a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGenTestHelper.java b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGenTestHelper.java index 3adc856983..a8196dac47 100644 --- a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGenTestHelper.java +++ b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGenTestHelper.java @@ -12,7 +12,6 @@ import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; import java.io.File; import java.io.FileNotFoundException; import java.net.URI; @@ -65,7 +64,6 @@ public class DocGenTestHelper { public void setUp() throws Exception { this.modules = loadModules("/yang"); this.mapper = new ObjectMapper(); - this.mapper.registerModule(new JsonOrgModule()); this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true); } diff --git a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java index b4ab8f4f56..58478425b9 100644 --- a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java +++ b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java @@ -8,9 +8,9 @@ package org.opendaylight.controller.sal.rest.doc.impl; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Preconditions; import java.sql.Date; -import org.json.JSONObject; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -45,7 +45,7 @@ public class ModelGeneratorTest { if (m.getQNameModule().getNamespace().toString().equals(NAMESPACE) && m.getQNameModule().getRevision().equals(REVISION)) { - final JSONObject jsonObject = generator.convertToJsonSchema(m, this.schemaContext); + final ObjectNode jsonObject = generator.convertToJsonSchema(m, this.schemaContext); Assert.assertNotNull(jsonObject); } }