
software.amazon.awssdk.codegen.model.intermediate.ShapeModel Maven / Gradle / Ivy
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package software.amazon.awssdk.codegen.model.intermediate;
import static software.amazon.awssdk.codegen.internal.Constant.LF;
import static software.amazon.awssdk.codegen.internal.Constant.REQUEST_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.RESPONSE_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.DocumentationUtils.removeFromEnd;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import software.amazon.awssdk.codegen.model.intermediate.customization.ShapeCustomizationInfo;
import software.amazon.awssdk.codegen.model.service.XmlNamespace;
import software.amazon.awssdk.utils.StringUtils;
public class ShapeModel extends DocumentationModel implements HasDeprecation {
private String c2jName;
// shapeName might be later modified by the customization.
private String shapeName;
// the local variable name inside marshaller/unmarshaller implementation
private boolean deprecated;
private String deprecatedMessage;
private String type;
private List required;
private boolean hasPayloadMember;
private boolean hasHeaderMember;
private boolean hasStatusCodeMember;
private boolean hasStreamingMember;
private boolean hasRequiresLengthMember;
private boolean wrapper;
private boolean simpleMethod;
private String requestSignerClassFqcn;
private EndpointDiscovery endpointDiscovery;
private List members;
private List enums;
private VariableModel variable;
private ShapeMarshaller marshaller;
private ShapeUnmarshaller unmarshaller;
private String errorCode;
private Integer httpStatusCode;
private boolean fault;
private ShapeCustomizationInfo customization = new ShapeCustomizationInfo();
private boolean isEventStream;
private boolean isEvent;
private XmlNamespace xmlNamespace;
private boolean document;
private boolean union;
private boolean retryable;
private boolean throttling;
public ShapeModel() {
}
public ShapeModel(String c2jName) {
this.c2jName = c2jName;
}
public String getShapeName() {
return shapeName;
}
public void setShapeName(String shapeName) {
this.shapeName = shapeName;
}
@Override
public boolean isDeprecated() {
return deprecated;
}
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
public String getDeprecatedMessage() {
return deprecatedMessage;
}
public void setDeprecatedMessage(String deprecatedMessage) {
this.deprecatedMessage = deprecatedMessage;
}
public String getC2jName() {
return c2jName;
}
public void setC2jName(String c2jName) {
this.c2jName = c2jName;
}
public String getType() {
return type;
}
@JsonIgnore
public void setType(ShapeType shapeType) {
setType(shapeType.getValue());
}
public void setType(String type) {
this.type = type;
}
@JsonIgnore
public ShapeType getShapeType() {
return ShapeType.fromValue(type);
}
public ShapeModel withType(String type) {
this.type = type;
return this;
}
// Returns the list of C2j member names that are required for this shape.
public List getRequired() {
return required;
}
public void setRequired(List required) {
this.required = required;
}
public boolean isHasPayloadMember() {
return hasPayloadMember;
}
public void setHasPayloadMember(boolean hasPayloadMember) {
this.hasPayloadMember = hasPayloadMember;
}
public ShapeModel withHasPayloadMember(boolean hasPayloadMember) {
setHasPayloadMember(hasPayloadMember);
return this;
}
/**
* @return The member explicitly designated as the payload member
*/
@JsonIgnore
public MemberModel getPayloadMember() {
MemberModel payloadMember = null;
for (MemberModel member : members) {
if (member.getHttp().getIsPayload()) {
if (payloadMember == null) {
payloadMember = member;
} else {
throw new IllegalStateException(
String.format("Only one payload member can be explicitly set on %s. This is likely an error in " +
"the C2J model", c2jName));
}
}
}
return payloadMember;
}
/**
* @return The list of members whose location is not specified. If no payload member is
* explicitly set then these members will appear in the payload
*/
@JsonIgnore
public List getUnboundMembers() {
List unboundMembers = new ArrayList<>();
if (members != null) {
for (MemberModel member : members) {
if (member.getHttp().getLocation() == null && !member.getHttp().getIsPayload()) {
if (hasPayloadMember) {
// There is an explicit payload, but this unbound
// member isn't it.
// Note: Somewhat unintuitive, explicit payloads don't
// have an explicit location; they're identified by
// the payload HTTP trait being true.
throw new IllegalStateException(String.format(
"C2J Shape %s has both an explicit payload member and unbound (no explicit location) member, %s."
+ " This is undefined behavior, verify the correctness of the C2J model.",
c2jName, member.getName()));
}
unboundMembers.add(member);
}
}
}
return unboundMembers;
}
/**
* @return The list of members whose are not marked with either eventheader or eventpayload trait.
*/
@JsonIgnore
public List getUnboundEventMembers() {
if (members == null) {
return new ArrayList<>();
}
return members.stream()
.filter(m -> !m.isEventHeader())
.filter(m -> !m.isEventPayload())
.collect(Collectors.toList());
}
/**
* @return True if the shape has an explicit payload member or implicit payload member(s).
*/
public boolean hasPayloadMembers() {
return hasPayloadMember ||
getExplicitEventPayloadMember() != null ||
hasImplicitPayloadMembers();
}
public boolean hasImplicitPayloadMembers() {
return !getUnboundMembers().isEmpty() ||
hasImplicitEventPayloadMembers();
}
public boolean hasImplicitEventPayloadMembers() {
return isEvent() && !getUnboundEventMembers().isEmpty();
}
/**
* Explicit event payload member will have "eventpayload" trait set to true.
* There can be at most only one member that can be declared as explicit payload.
*
* @return the member that has the 'eventpayload' trait set to true. If none found, return null.
*/
public MemberModel getExplicitEventPayloadMember() {
if (members == null) {
return null;
}
return members.stream()
.filter(MemberModel::isEventPayload)
.findFirst()
.orElse(null);
}
/**
* If all members in shape have eventheader trait, then there is no payload
*/
public boolean hasNoEventPayload() {
return members == null || members.stream().allMatch(MemberModel::isEventHeader);
}
public boolean isHasStreamingMember() {
return hasStreamingMember;
}
public void setHasStreamingMember(boolean hasStreamingMember) {
this.hasStreamingMember = hasStreamingMember;
}
public ShapeModel withHasStreamingMember(boolean hasStreamingMember) {
setHasStreamingMember(hasStreamingMember);
return this;
}
public boolean isHasRequiresLengthMember() {
return hasRequiresLengthMember;
}
public void setHasRequiresLengthMember(boolean hasRequiresLengthMember) {
this.hasRequiresLengthMember = hasRequiresLengthMember;
}
public ShapeModel withHasRequiresLengthMember(boolean hasRequiresLengthMember) {
setHasRequiresLengthMember(hasRequiresLengthMember);
return this;
}
public boolean isHasHeaderMember() {
return hasHeaderMember;
}
public void setHasHeaderMember(boolean hasHeaderMember) {
this.hasHeaderMember = hasHeaderMember;
}
public ShapeModel withHasHeaderMember(boolean hasHeaderMember) {
setHasHeaderMember(hasHeaderMember);
return this;
}
public boolean isHasStatusCodeMember() {
return hasStatusCodeMember;
}
public void setHasStatusCodeMember(boolean hasStatusCodeMember) {
this.hasStatusCodeMember = hasStatusCodeMember;
}
public boolean isWrapper() {
return wrapper;
}
public void setWrapper(boolean wrapper) {
this.wrapper = wrapper;
}
public boolean isSimpleMethod() {
return simpleMethod;
}
public void setSimpleMethod(boolean simpleMethod) {
this.simpleMethod = simpleMethod;
}
public ShapeModel withHasStatusCodeMember(boolean hasStatusCodeMember) {
setHasStatusCodeMember(hasStatusCodeMember);
return this;
}
public MemberModel getMemberByVariableName(String memberVariableName) {
for (MemberModel memberModel : members) {
if (memberModel.getVariable().getVariableName().equals(memberVariableName)) {
return memberModel;
}
}
throw new IllegalArgumentException("Unknown member variable name: " + memberVariableName);
}
public MemberModel getMemberByName(String memberName) {
for (MemberModel memberModel : members) {
if (memberModel.getName().equals(memberName)) {
return memberModel;
}
}
return null;
}
public MemberModel getMemberByC2jName(String memberName) {
for (MemberModel memberModel : members) {
if (memberModel.getC2jName().equals(memberName)) {
return memberModel;
}
}
return null;
}
public List getMembers() {
if (members == null) {
return Collections.emptyList();
}
return members;
}
/**
* @return All non-streaming members of the shape.
*/
public List getNonStreamingMembers() {
return getMembers().stream()
// Filter out binary streaming members
.filter(m -> !m.getHttp().getIsStreaming())
// Filter out event stream members (if shape is null then it's primitive and we should include it).
.filter(m -> m.getShape() == null || !m.getShape().isEventStream)
.collect(Collectors.toList());
}
public void setMembers(List members) {
this.members = members;
}
public void addMember(MemberModel member) {
if (this.members == null) {
this.members = new ArrayList<>();
}
members.add(member);
}
public List getEnums() {
return enums;
}
public void setEnums(List enums) {
this.enums = enums;
}
public void addEnum(EnumModel enumModel) {
if (this.enums == null) {
this.enums = new ArrayList<>();
}
this.enums.add(enumModel);
}
public VariableModel getVariable() {
return variable;
}
public void setVariable(VariableModel variable) {
this.variable = variable;
}
public ShapeMarshaller getMarshaller() {
return marshaller;
}
public void setMarshaller(ShapeMarshaller marshaller) {
this.marshaller = marshaller;
}
public ShapeUnmarshaller getUnmarshaller() {
return unmarshaller;
}
public void setUnmarshaller(ShapeUnmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public ShapeCustomizationInfo getCustomization() {
return customization;
}
public void setCustomization(ShapeCustomizationInfo customization) {
this.customization = customization;
}
public Map getMembersAsMap() {
Map shapeMembers = new HashMap<>();
// Creating a map of shape's members. This map is used below when
// fetching the details of a member.
List memberModels = getMembers();
if (memberModels != null) {
for (MemberModel model : memberModels) {
shapeMembers.put(model.getName(), model);
}
}
return shapeMembers;
}
/**
* Tries to find the member model associated with the given c2j member name from this shape
* model. Returns the member model if present else returns null.
*/
public MemberModel tryFindMemberModelByC2jName(String memberC2jName, boolean ignoreCase) {
List memberModels = getMembers();
String expectedName = ignoreCase ? StringUtils.lowerCase(memberC2jName)
: memberC2jName;
if (memberModels != null) {
for (MemberModel member : memberModels) {
String actualName = ignoreCase ? StringUtils.lowerCase(member.getC2jName())
: member.getC2jName();
if (expectedName.equals(actualName)) {
return member;
}
}
}
return null;
}
/**
* Returns the member model associated with the given c2j member name from this shape model.
*/
public MemberModel findMemberModelByC2jName(String memberC2jName) {
MemberModel model = tryFindMemberModelByC2jName(memberC2jName, false);
if (model == null) {
throw new IllegalArgumentException(memberC2jName + " member (c2j name) does not exist in the shape.");
}
return model;
}
/**
* Takes in the c2j member name as input and removes if the shape contains a member with the
* given name. Return false otherwise.
*/
public boolean removeMemberByC2jName(String memberC2jName, boolean ignoreCase) {
// Implicitly depending on the default equals and hashcode
// implementation of the class MemberModel
MemberModel model = tryFindMemberModelByC2jName(memberC2jName, ignoreCase);
return model == null ? false : members.remove(model);
}
/**
* Returns the enum model for the given enum value.
* Returns null if no such enum value exists.
*/
public EnumModel findEnumModelByValue(String enumValue) {
if (enums != null) {
for (EnumModel enumModel : enums) {
if (enumValue.equals(enumModel.getValue())) {
return enumModel;
}
}
}
return null;
}
@JsonIgnore
public String getDocumentationShapeName() {
switch (getShapeType()) {
case Request:
return removeFromEnd(shapeName, REQUEST_CLASS_SUFFIX);
case Response:
return removeFromEnd(shapeName, RESPONSE_CLASS_SUFFIX);
default:
return c2jName;
}
}
public String getUnionTypeGetterDocumentation() {
return "Retrieve an enum value representing which member of this object is populated. "
+ LF + LF
+ "When this class is returned in a service response, this will be {@link Type#UNKNOWN_TO_SDK_VERSION} if the "
+ "service returned a member that is only known to a newer SDK version."
+ LF + LF
+ "When this class is created directly in your code, this will be {@link Type#UNKNOWN_TO_SDK_VERSION} if zero "
+ "members are set, and {@code null} if more than one member is set.";
}
@Override
public String toString() {
return shapeName;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
/**
* Return the httpStatusCode of the exception shape. This value is present only for modeled exceptions.
*/
public Integer getHttpStatusCode() {
return httpStatusCode;
}
public void setHttpStatusCode(Integer httpStatusCode) {
this.httpStatusCode = httpStatusCode;
}
public boolean isRequestSignerAware() {
return requestSignerClassFqcn != null;
}
public String getRequestSignerClassFqcn() {
return requestSignerClassFqcn;
}
public void setRequestSignerClassFqcn(String authorizerClass) {
this.requestSignerClassFqcn = authorizerClass;
}
public EndpointDiscovery getEndpointDiscovery() {
return endpointDiscovery;
}
public void setEndpointDiscovery(EndpointDiscovery endpointDiscovery) {
this.endpointDiscovery = endpointDiscovery;
}
/**
* @return True if the shape is an 'eventstream' shape. The eventstream shape is the tagged union like
* container that holds individual 'events'.
*/
public boolean isEventStream() {
return this.isEventStream;
}
public ShapeModel withIsEventStream(boolean isEventStream) {
this.isEventStream = isEventStream;
return this;
}
/**
* @return True if the shape is an 'event'. I.E. It is a member of the eventstream and represents one logical event
* that can be delivered on the event stream.
*/
public boolean isEvent() {
return this.isEvent;
}
public ShapeModel withIsEvent(boolean isEvent) {
this.isEvent = isEvent;
return this;
}
public XmlNamespace getXmlNamespace() {
return xmlNamespace;
}
public ShapeModel withXmlNamespace(XmlNamespace xmlNamespace) {
this.xmlNamespace = xmlNamespace;
return this;
}
public void setXmlNamespace(XmlNamespace xmlNamespace) {
this.xmlNamespace = xmlNamespace;
}
public boolean isDocument() {
return document;
}
public ShapeModel withIsDocument(boolean document) {
this.document = document;
return this;
}
public boolean isUnion() {
return union;
}
public void withIsUnion(boolean union) {
this.union = union;
}
public boolean isFault() {
return fault;
}
public ShapeModel withIsFault(boolean fault) {
this.fault = fault;
return this;
}
public boolean isRetryable() {
return retryable;
}
public ShapeModel withIsRetryable(boolean retryable) {
this.retryable = retryable;
return this;
}
public boolean isThrottling() {
return throttling;
}
public ShapeModel withIsThrottling(boolean throttling) {
this.throttling = throttling;
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy