@Override
    public Node toNode() {
        if (asNode != null) {
            return asNode;
        }

        ObjectNode.Builder result = Node.objectNodeBuilder()
                .withOptionalMember("type", getType().map(Node::from))
                .withOptionalMember("$ref", getRef().map(Node::from))
                .withOptionalMember("const", getConstValue())
                .withOptionalMember("default", getDefaultValue())

                .withOptionalMember("multipleOf", getMultipleOf().map(Node::from))
                .withOptionalMember("maximum", getMaximum().map(Node::from))
                .withOptionalMember("exclusiveMaximum", getExclusiveMaximum().map(Node::from))
                .withOptionalMember("minimum", getMinimum().map(Node::from))
                .withOptionalMember("exclusiveMinimum", getExclusiveMinimum().map(Node::from))

                .withOptionalMember("items", getItems().map(ToNode::toNode))
                .withOptionalMember("maxItems", getMaxItems().map(Node::from))
                .withOptionalMember("minItems", getMinItems().map(Node::from))
                .withOptionalMember("uniqueItems", uniqueItems ? Optional.of(Node.from(true)) : Optional.empty())

                .withOptionalMember("maxLength", getMaxLength().map(Node::from))
                .withOptionalMember("minLength", getMinLength().map(Node::from))
                .withOptionalMember("pattern", getPattern().map(Node::from))

                .withOptionalMember("additionalProperties", getAdditionalProperties().map(Schema::toNode))
                .withOptionalMember("propertyNames", getPropertyNames().map(Schema::toNode))
                .withOptionalMember("maxProperties", getMaxProperties().map(Node::from))
                .withOptionalMember("minProperties", getMinProperties().map(Node::from))

                .withOptionalMember("not", getNot().map(Schema::toNode))

                .withOptionalMember("comment", getComment().map(Node::from))
                .withOptionalMember("examples", getExamples())
                .withOptionalMember("deprecated", this.deprecated ? Optional.of(Node.from(true)) : Optional.empty())
                .withOptionalMember("title", getTitle().map(Node::from))
                .withOptionalMember("description", getDescription().map(Node::from))
                .withOptionalMember("format", getFormat().map(Node::from))

                .withOptionalMember("contentEncoding", getContentEncoding().map(Node::from))
                .withOptionalMember("contentMediaType", getContentMediaType().map(Node::from));

        if (!properties.isEmpty()) {
            result.withMember("properties",
                    properties.entrySet()
                            .stream()
                            .collect(ObjectNode.collectStringKeys(Map.Entry::getKey, e -> e.getValue().toNode())));
        }

        if (!patternProperties.isEmpty()) {
            result.withMember("patternProperties",
                    patternProperties.entrySet()
                            .stream()
                            .collect(ObjectNode.collectStringKeys(Map.Entry::getKey, e -> e.getValue().toNode())));
        }

        if (!required.isEmpty()) {
            result.withMember("required", required.stream().sorted().map(Node::from).collect(ArrayNode.collect()));
        }

        if (!enumValues.isEmpty() || !intEnumValues.isEmpty()) {
            ArrayNode.Builder builder = ArrayNode.builder();
            if (getIntEnumValues().isPresent()) {
                for (Integer i : getIntEnumValues().get()) {
                    builder.withValue(i);
                }
            }

            if (getEnumValues().isPresent()) {
                for (String s : getEnumValues().get()) {
                    builder.withValue(s);
                }
            }
            result.withOptionalMember("enum", builder.build().asArrayNode());
        }

        if (!allOf.isEmpty()) {
            result.withMember("allOf", allOf.stream().collect(ArrayNode.collect()));
        }

        if (!anyOf.isEmpty()) {
            result.withMember("anyOf", anyOf.stream().collect(ArrayNode.collect()));
        }

        if (!oneOf.isEmpty()) {
            result.withMember("oneOf", oneOf.stream().collect(ArrayNode.collect()));
        }

        if (readOnly) {
            result.withMember("readOnly", Node.from(true));
        }

        if (writeOnly) {
            result.withMember("writeOnly", Node.from(true));
        }

        if (deprecated) {
            result.withMember("deprecated", Node.from(true));
        }

        for (Map.Entry<String, ToNode> entry : extensions.entrySet()) {
            result.withMember(entry.getKey(), entry.getValue().toNode());
        }

        asNode = result.build();
        return asNode;
    }
Defines a single JSON schema.

<p>This supports a subset of the "draft-handrews-json-schema-validation-01"
version of JSON Schema. The following properties are not supported:

<ul>
    <li>dependencies</li>
    <li>if</li>
    <li>then</li>
    <li>else</li>
    <li>examples</li>
</ul>

<p>Custom properties can be added to the scheme using the
{@link Builder#putExtension} method. Custom properties are merged with
the schema document when serializing it to a {@link Node} object. Any
extension properties that conflict with built-in properties overwrite the
built-in property.

@see <a href="https://json-schema.org/latest/json-schema-validation.html">JSON Schema Validation</a>
smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java