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 8a196f0d5ea..6a59c9e5006 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 @@ -15,12 +15,8 @@ package software.amazon.smithy.model.validation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; + import software.amazon.smithy.model.Model; import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.knowledge.NullableIndex; @@ -51,6 +47,7 @@ import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.shapes.TimestampShape; import software.amazon.smithy.model.shapes.UnionShape; +import software.amazon.smithy.model.traits.TimestampFormatTrait; import software.amazon.smithy.model.validation.node.NodeValidatorPlugin; import software.amazon.smithy.model.validation.node.TimestampValidationStrategy; import software.amazon.smithy.utils.BuilderRef; @@ -354,11 +351,20 @@ public List unionShape(UnionShape shape) { @Override public List memberShape(MemberShape shape) { - List events = applyPlugins(shape); - events.addAll(model.getShape(shape.getTarget()) - .map(member -> member.accept(this)) - .orElse(ListUtils.of())); - return events; + List allEvents = applyPlugins(shape); + Optional target = model.getShape(shape.getTarget()); + if (target.map(t -> t.isTimestampShape() && shape.hasTrait(TimestampFormatTrait.class)).orElse(false)) { + TimestampShape t = target.get().asTimestampShape().get(); + TimestampFormatTrait fmt = shape.expectTrait(TimestampFormatTrait.class); + TimestampShape updatedShape = t.toBuilder().addTrait(fmt).build(); + allEvents.addAll(updatedShape.accept(this)); + } else { + allEvents.addAll(model.getShape(shape.getTarget()) + .map(member -> member.accept(this)) + .orElse(ListUtils.of())); + } + + return allEvents; } @Override diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java index 6833bc75747..e8faa0806c5 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java @@ -40,10 +40,6 @@ final class TimestampFormatPlugin implements NodeValidatorPlugin { public void apply(Shape shape, Node value, Context context, Emitter emitter) { if (shape instanceof TimestampShape) { validate(shape, shape.getTrait(TimestampFormatTrait.class).orElse(null), value, emitter); - } else if (shape instanceof MemberShape && shape.getTrait(TimestampFormatTrait.class).isPresent()) { - // Only perform timestamp format validation on a member when it references - // a timestamp shape and the member has an explicit timestampFormat trait. - validate(shape, shape.getTrait(TimestampFormatTrait.class).get(), value, emitter); } } diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java index 0d5b2a07f32..e321b389681 100644 --- a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java +++ b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java @@ -242,6 +242,7 @@ public static Collection data() { {"ns.foo#HttpDate", "\"Tuesday, 29 April 2014 18:30:38 GMT\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: Tuesday, 29 April 2014 18:30:38 GMT"}}, {"ns.foo#HttpDate", "\"Tue, 29 Apr 2014 18:30:38 PST\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: Tue, 29 Apr 2014 18:30:38 PST"}}, {"ns.foo#HttpDate", "11", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: number"}}, + {"ns.foo#Structure4", "{\"httpDate\": \"Tue, 29 Apr 2014 18:30:38 GMT\"}", null}, // date-time {"ns.foo#DateTime", "\"1985-04-12T23:20:50.52Z\"", null}, @@ -257,8 +258,7 @@ public static Collection data() { // timestamp member with format. {"ns.foo#TimestampList", "[\"1985-04-12T23:20:50.52Z\"]", null}, {"ns.foo#TimestampList", "[\"1985-04-12T23:20:50.52-07:00\"]", new String[] { - "0: Invalid string value, `1985-04-12T23:20:50.52-07:00`, provided for timestamp, `smithy.api#Timestamp`. Expected an RFC 3339 formatted timestamp (e.g., \"1985-04-12T23:20:50.52Z\")", - "0: Invalid string value, `1985-04-12T23:20:50.52-07:00`, provided for timestamp, `ns.foo#TimestampList$member`. Expected an RFC 3339 formatted timestamp (e.g., \"1985-04-12T23:20:50.52Z\")" + "0: Invalid string value, `1985-04-12T23:20:50.52-07:00`, provided for timestamp, `smithy.api#Timestamp`. Expected an RFC 3339 formatted timestamp (e.g., \"1985-04-12T23:20:50.52Z\")" }}, {"ns.foo#TimestampList", "[123]", new String[] {"0: Expected a string value for a date-time timestamp (e.g., \"1985-04-12T23:20:50.52Z\")"}}, diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json index d7ea24ca1eb..cbed8545a4d 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json @@ -268,6 +268,17 @@ } } }, + "ns.foo#Structure4": { + "type": "structure", + "members": { + "httpDate": { + "target": "smithy.api#Timestamp", + "traits": { + "smithy.api#timestampFormat": "http-date" + } + } + } + }, "ns.foo#Service": { "type": "service", "version": "2017-17-01",