From 52e6d7f4e865626b9db7661962729b7027d96458 Mon Sep 17 00:00:00 2001 From: Michael Dowling Date: Tue, 19 Dec 2023 15:56:58 -0600 Subject: [PATCH] Move allowOptionalNull to Feature Move allowOptionalNull to Feature --- .../validation/NodeValidationVisitor.java | 54 ++++++++++--------- .../traits/ProtocolTestCaseValidator.java | 2 +- .../traits/SmokeTestCaseValidator.java | 2 +- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java index a3e74ebd245..8c7a00bb00f 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java @@ -16,7 +16,10 @@ package software.amazon.smithy.model.validation; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -53,10 +56,8 @@ import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.model.validation.node.NodeValidatorPlugin; import software.amazon.smithy.model.validation.node.TimestampValidationStrategy; -import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ListUtils; import software.amazon.smithy.utils.SmithyBuilder; -import software.amazon.smithy.utils.SmithyInternalApi; /** * Validates {@link Node} values provided for {@link Shape} definitions. @@ -74,7 +75,6 @@ public final class NodeValidationVisitor implements ShapeVisitorBy default, null values are not allowed for optional types. + */ + ALLOW_OPTIONAL_NULLS; public static Feature fromNode(Node node) { return Feature.valueOf(node.expectStringNode().getValue()); @@ -119,6 +126,10 @@ public static Feature fromNode(Node node) { public static Node toNode(Feature feature) { return StringNode.from(feature.toString()); } + + private static EnumSet enumSet(Collection features) { + return features.isEmpty() ? EnumSet.noneOf(Feature.class) : EnumSet.copyOf(features); + } } public static Builder builder() { @@ -169,7 +180,6 @@ private NodeValidationVisitor traverse(String segment, Node node) { builder.model(model); builder.startingContext(startingContext.isEmpty() ? segment : (startingContext + "." + segment)); builder.timestampValidationStrategy(timestampValidationStrategy); - builder.allowOptionalNull(allowOptionalNull); NodeValidationVisitor visitor = new NodeValidationVisitor(builder); // Use the same validation context. visitor.validationContext = this.validationContext; @@ -395,7 +405,7 @@ public List serviceShape(ServiceShape shape) { private List invalidShape(Shape shape, NodeType expectedType) { // Nullable shapes allow null values. - if (allowOptionalNull && value.isNullNode()) { + if (value.isNullNode() && validationContext.hasFeature(Feature.ALLOW_OPTIONAL_NULLS)) { // Non-members are nullable. Members are nullable based on context. if (!shape.isMemberShape() || shape.asMemberShape().filter(nullableIndex::isMemberNullable).isPresent()) { return Collections.emptyList(); @@ -468,8 +478,7 @@ public static final class Builder implements SmithyBuilder> features = BuilderRef.forUnorderedSet(); + private final Set features = new HashSet<>(); Builder() {} @@ -550,18 +559,14 @@ public Builder allowBoxedNull(boolean allowBoxedNull) { return allowOptionalNull(allowBoxedNull); } - /** - * Configure how null values are handled when they are provided for - * optional types. - * - *

By default, null values are not allowed for optional types. - * - * @param allowOptionalNull Set to true to allow null values for optional shapes. - * @return Returns the builder. - */ + @Deprecated public Builder allowOptionalNull(boolean allowOptionalNull) { - this.allowOptionalNull = allowOptionalNull; - return this; + if (allowOptionalNull) { + return addFeature(Feature.ALLOW_OPTIONAL_NULLS); + } else { + features.remove(Feature.ALLOW_OPTIONAL_NULLS); + return this; + } } /** @@ -570,9 +575,8 @@ public Builder allowOptionalNull(boolean allowOptionalNull) { * @param feature Feature to set. * @return Returns the builder. */ - @SmithyInternalApi public Builder addFeature(Feature feature) { - this.features.get().add(feature); + this.features.add(feature); return this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ProtocolTestCaseValidator.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ProtocolTestCaseValidator.java index c2c066240e6..5c630d30ff4 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ProtocolTestCaseValidator.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ProtocolTestCaseValidator.java @@ -160,7 +160,7 @@ private NodeValidationVisitor createVisitor( .startingContext(traitId + "." + position + contextSuffix) .eventId(getName()) .timestampValidationStrategy(TimestampValidationStrategy.EPOCH_SECONDS) - .allowOptionalNull(true) + .addFeature(NodeValidationVisitor.Feature.ALLOW_OPTIONAL_NULLS) .build(); } diff --git a/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCaseValidator.java b/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCaseValidator.java index e8e6f87f554..0722c26333b 100644 --- a/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCaseValidator.java +++ b/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCaseValidator.java @@ -106,7 +106,7 @@ private NodeValidationVisitor createVisitor( .startingContext(SmokeTestsTrait.ID + "." + caseId + contextSuffix) .eventId(getName()) .timestampValidationStrategy(TimestampValidationStrategy.EPOCH_SECONDS) - .allowOptionalNull(true) + .addFeature(NodeValidationVisitor.Feature.ALLOW_OPTIONAL_NULLS) .build(); } }