diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ServiceTrait.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ServiceTrait.java
index bc8cdcd3bb5..7d4c43afeed 100644
--- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ServiceTrait.java
+++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ServiceTrait.java
@@ -19,8 +19,8 @@
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Logger;
-import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.SourceException;
+import software.amazon.smithy.model.node.ExpectationNotMetException;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.node.StringNode;
@@ -40,7 +40,6 @@ public final class ServiceTrait extends AbstractTrait implements ToSmithyBuilder
public static final ShapeId ID = ShapeId.from("aws.api#service");
private static final Logger LOGGER = Logger.getLogger(ServiceTrait.class.getName());
- private final ShapeId target;
private final String cloudFormationName;
private final String arnNamespace;
private final String sdkId;
@@ -50,7 +49,6 @@ public final class ServiceTrait extends AbstractTrait implements ToSmithyBuilder
private ServiceTrait(Builder builder) {
super(ID, builder.getSourceLocation());
- this.target = SmithyBuilder.requiredState("target", builder.target);
this.sdkId = SmithyBuilder.requiredState("sdkId", builder.sdkId);
this.arnNamespace = SmithyBuilder.requiredState("arnNamespace", builder.arnNamespace);
this.cloudFormationName = SmithyBuilder.requiredState("cloudFormationName", builder.cloudFormationName);
@@ -149,25 +147,31 @@ public String getCloudTrailEventSource() {
}
/**
- * Returns the documentation identifier value for the service.
+ * Resolves the doc id value for the service.
*
*
When value on trait is not set, this method defaults to the lower
* cased value of the sdkId followed by the service version, separated by
* dashes.
*
+ * @param serviceShape the shape which this trait targets
* @return Returns the documentation identifier value for the service name.
+ * @throws ExpectationNotMetException if the shape is not the target of this trait.
*/
- public String getDocId(Model model) {
- return getDocId().orElseGet(() -> buildDefaultDocId(model));
+ public String resolveDocId(ServiceShape serviceShape) {
+ return getDocId().orElseGet(() -> buildDefaultDocId(serviceShape));
}
protected Optional getDocId() {
return Optional.ofNullable(docId);
}
- private String buildDefaultDocId(Model model) {
- String version = model.expectShape(target, ServiceShape.class).getVersion();
- return sdkId.replace(" ", "-").toLowerCase(Locale.US) + "-" + version;
+ private String buildDefaultDocId(ServiceShape serviceShape) {
+ if (!serviceShape.expectTrait(ServiceTrait.class).equals(this)) {
+ throw new ExpectationNotMetException(String.format(
+ "Provided service shape `%s` is not the target of this trait.", serviceShape.getId()), this);
+ }
+
+ return sdkId.replace(" ", "-").toLowerCase(Locale.US) + "-" + serviceShape.getVersion();
}
/**
@@ -192,7 +196,6 @@ public Optional getAbbreviation() {
@Override
public Builder toBuilder() {
return new Builder()
- .target(target)
.sdkId(sdkId)
.sourceLocation(getSourceLocation())
.cloudFormationName(cloudFormationName)
@@ -206,7 +209,6 @@ public Builder toBuilder() {
protected Node createNode() {
return Node.objectNodeBuilder()
.sourceLocation(getSourceLocation())
- .withMember("target", Node.from(target.toString()))
.withMember("sdkId", Node.from(sdkId))
.withMember("arnNamespace", Node.from(getArnNamespace()))
.withMember("cloudFormationName", Node.from(getCloudFormationName()))
@@ -227,7 +229,6 @@ public boolean equals(Object other) {
} else {
ServiceTrait os = (ServiceTrait) other;
return sdkId.equals(os.sdkId)
- && target.equals(os.target)
&& arnNamespace.equals(os.arnNamespace)
&& cloudFormationName.equals(os.cloudFormationName)
&& cloudTrailEventSource.equals(os.cloudTrailEventSource)
@@ -240,13 +241,12 @@ public boolean equals(Object other) {
@Override
public int hashCode() {
- return Objects.hash(toShapeId(), target, sdkId, arnNamespace, cloudFormationName,
+ return Objects.hash(toShapeId(), sdkId, arnNamespace, cloudFormationName,
cloudTrailEventSource, docId, endpointPrefix);
}
/** Builder for {@link ServiceTrait}. */
public static final class Builder extends AbstractTraitBuilder {
- private ShapeId target;
private String sdkId;
private String cloudFormationName;
private String arnNamespace;
@@ -266,8 +266,6 @@ public ServiceTrait build() {
}
public ServiceTrait build(ShapeId target) {
- this.target = target;
-
// Fill in default values if they weren't set.
if (arnNamespace == null) {
arnNamespace(target.getName().toLowerCase(Locale.US));
@@ -288,17 +286,6 @@ public ServiceTrait build(ShapeId target) {
return new ServiceTrait(this);
}
- /**
- * Sets the target shape to which the trait is applied.
- *
- * @param target the ShapeId targeted by the trait.
- * @return Returns the builder.
- */
- private Builder target(ShapeId target) {
- this.target = target;
- return this;
- }
-
/**
* Sets the AWS CloudFormation resource type service name.
*
diff --git a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/EventSourceValidatorTest.java b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/EventSourceValidatorTest.java
index 2515de84e1a..91906dce3cf 100644
--- a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/EventSourceValidatorTest.java
+++ b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/EventSourceValidatorTest.java
@@ -10,22 +10,20 @@
import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.ServiceShape;
-import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.model.validation.ValidationEvent;
public class EventSourceValidatorTest {
@Test
public void detectsWhenEventSourceIsUnexpected() {
- ShapeId id = ShapeId.from("smithy.example#Foo");
ServiceTrait trait = ServiceTrait.builder()
.sdkId("Foo")
.arnNamespace("foo")
.cloudTrailEventSource("REPLACE_ME_LATER")
.cloudFormationName("AWS::Foo")
- .build(id);
+ .build();
ServiceShape service = ServiceShape.builder()
- .id(id)
+ .id("smithy.example#Foo")
.version("123")
.addTrait(trait)
.build();
@@ -41,15 +39,14 @@ public void detectsWhenEventSourceIsUnexpected() {
@Test
public void detectsWhenEventSourceIsPlaceholder() {
- ShapeId id = ShapeId.from("smithy.example#Foo");
ServiceTrait trait = ServiceTrait.builder()
.sdkId("Foo")
.arnNamespace("foo")
.cloudTrailEventSource("notfoo.amazonaws.com")
.cloudFormationName("AWS::Foo")
- .build(id);
+ .build();
ServiceShape service = ServiceShape.builder()
- .id(id)
+ .id("smithy.example#Foo")
.version("123")
.addTrait(trait)
.build();
@@ -66,15 +63,14 @@ public void detectsWhenEventSourceIsPlaceholder() {
@Test
public void ignoresKnownExceptions() {
- ShapeId id = ShapeId.from("smithy.example#Foo");
ServiceTrait trait = ServiceTrait.builder()
.sdkId("Foo")
.arnNamespace("cloudwatch")
.cloudTrailEventSource("monitoring.amazonaws.com")
.cloudFormationName("AWS::Foo")
- .build(id);
+ .build();
ServiceShape service = ServiceShape.builder()
- .id(id)
+ .id("smithy.example#Foo")
.version("123")
.addTrait(trait)
.build();
diff --git a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/ServiceTraitTest.java b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/ServiceTraitTest.java
index 21bff845d31..1d2e870c528 100644
--- a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/ServiceTraitTest.java
+++ b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/ServiceTraitTest.java
@@ -16,7 +16,6 @@
package software.amazon.smithy.aws.traits;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -26,6 +25,7 @@
import java.util.Optional;
import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.node.ExpectationNotMetException;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.ShapeId;
@@ -50,8 +50,6 @@ public void loadsTraitWithString() {
assertThat(serviceTrait.getEndpointPrefix(), equalTo("foo"));
assertThat(serviceTrait.toBuilder().build(), equalTo(serviceTrait));
assertFalse(serviceTrait.getDocId().isPresent());
- assertThat(Node.prettyPrintJson(serviceTrait.createNode()),
- containsString("\"target\": \"ns.foo#Foo\","));
}
@Test
@@ -89,6 +87,27 @@ public void requiresSdkServiceId() {
assertThrows(IllegalStateException.class, () -> ServiceTrait.builder().build());
}
+ @Test
+ public void requiresProperServiceShapeToResolveDocId() {
+ ServiceTrait trait = ServiceTrait.builder()
+ .sdkId("Foo SDK")
+ .arnNamespace("foo")
+ .cloudTrailEventSource("cloudTrailEventSource")
+ .cloudFormationName("AWS::Foo")
+ .build();
+ ServiceShape service = ServiceShape.builder()
+ .id("smithy.example#Foo")
+ .version("123")
+ .addTrait(trait)
+ .build();
+ ServiceShape anotherService = ServiceShape.builder()
+ .id("smithy.example#Bar")
+ .build();
+
+ assertThat(trait.resolveDocId(service), equalTo("foo-sdk-123"));
+ assertThrows(ExpectationNotMetException.class, () -> trait.resolveDocId(anotherService));
+ }
+
@Test
public void loadsFromModel() {
Model result = Model.assembler()
@@ -105,6 +124,6 @@ public void loadsFromModel() {
assertThat(trait.getArnNamespace(), equalTo("service"));
assertThat(trait.getEndpointPrefix(), equalTo("some-service"));
assertFalse(trait.getDocId().isPresent());
- assertThat(trait.getDocId(result), equalTo("some-value-2018-03-17"));
+ assertThat(trait.resolveDocId(service), equalTo("some-value-2018-03-17"));
}
}