Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
software.amazon.awssdk.codegen.naming.DefaultNamingStrategy 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.naming;
import static java.util.stream.Collectors.joining;
import static software.amazon.awssdk.codegen.internal.Constant.CONFLICTING_NAME_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.EXCEPTION_CLASS_SUFFIX;
import static software.amazon.awssdk.codegen.internal.Constant.FAULT_CLASS_SUFFIX;
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.Utils.unCapitalize;
import static software.amazon.awssdk.utils.internal.CodegenNamingUtils.pascalCase;
import static software.amazon.awssdk.utils.internal.CodegenNamingUtils.splitOnWordBoundaries;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import software.amazon.awssdk.codegen.internal.Constant;
import software.amazon.awssdk.codegen.internal.Utils;
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
import software.amazon.awssdk.codegen.model.config.customization.UnderscoresInNameBehavior;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
import software.amazon.awssdk.codegen.model.service.ServiceModel;
import software.amazon.awssdk.codegen.model.service.Shape;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.awssdk.utils.Validate;
/**
* Default implementation of naming strategy respecting.
*/
public class DefaultNamingStrategy implements NamingStrategy {
private static final Logger log = Logger.loggerFor(DefaultNamingStrategy.class);
private static final Pattern VALID_IDENTIFIER_NAME =
Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*");
private static final String COLLISION_DISAMBIGUATION_PREFIX = "Default";
private static final Set RESERVED_KEYWORDS;
private static final Set RESERVED_EXCEPTION_METHOD_NAMES;
private static final Set RESERVED_STRUCTURE_METHOD_NAMES;
static {
Set reservedJavaKeywords = new HashSet<>();
Collections.addAll(reservedJavaKeywords,
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final",
"finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",
"interface", "long", "native", "new", "null", "package", "private", "protected", "public",
"return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw",
"throws", "transient", "true", "try", "void", "volatile", "while");
RESERVED_KEYWORDS = Collections.unmodifiableSet(reservedJavaKeywords);
Set reservedJavaMethodNames = new HashSet<>();
Collections.addAll(reservedJavaMethodNames,
"equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait");
Set reserveJavaPojoMethodNames = new HashSet<>(reservedJavaMethodNames);
Collections.addAll(reserveJavaPojoMethodNames,
"builder", "sdkFields", "toBuilder");
Set reservedExceptionMethodNames = new HashSet<>(reserveJavaPojoMethodNames);
Collections.addAll(reservedExceptionMethodNames,
"awsErrorDetails", "cause", "fillInStackTrace", "getCause", "getLocalizedMessage",
"getMessage", "getStackTrace", "getSuppressed", "isClockSkewException", "isThrottlingException",
"printStackTrace", "requestId", "retryable", "serializableBuilderClass", "statusCode");
RESERVED_EXCEPTION_METHOD_NAMES = Collections.unmodifiableSet(reservedExceptionMethodNames);
Set reservedStructureMethodNames = new HashSet<>(reserveJavaPojoMethodNames);
Collections.addAll(reservedStructureMethodNames,
"overrideConfiguration", "sdkHttpResponse");
RESERVED_STRUCTURE_METHOD_NAMES = Collections.unmodifiableSet(reservedStructureMethodNames);
}
private final ServiceModel serviceModel;
private final CustomizationConfig customizationConfig;
public DefaultNamingStrategy(ServiceModel serviceModel,
CustomizationConfig customizationConfig) {
this.serviceModel = serviceModel;
this.customizationConfig = customizationConfig == null ? CustomizationConfig.create() : customizationConfig;
}
private static boolean isJavaKeyword(String word) {
return RESERVED_KEYWORDS.contains(word) ||
RESERVED_KEYWORDS.contains(StringUtils.lowerCase(word));
}
@Override
public String getServiceName() {
String baseName = serviceId();
baseName = pascalCase(baseName);
baseName = removeRedundantPrefixesAndSuffixes(baseName);
return baseName;
}
@Override
public String getServiceNameForEnvironmentVariables() {
String baseName = serviceId();
baseName = baseName.replace(' ', '_');
baseName = StringUtils.upperCase(baseName);
return baseName;
}
@Override
public String getServiceNameForSystemProperties() {
return getServiceName();
}
@Override
public String getServiceNameForProfileFile() {
return StringUtils.lowerCase(getServiceNameForEnvironmentVariables());
}
private String serviceId() {
return Stream.of(serviceModel.getMetadata().getServiceId())
.filter(Objects::nonNull)
.filter(s -> !s.trim().isEmpty())
.findFirst()
.orElseThrow(() -> new IllegalStateException("ServiceId is missing in the c2j model."));
}
private static String removeRedundantPrefixesAndSuffixes(String baseName) {
baseName = Utils.removeLeading(baseName, "amazon");
baseName = Utils.removeLeading(baseName, "aws");
baseName = Utils.removeTrailing(baseName, "service");
return baseName;
}
@Override
public String getClientPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName),
Constant.PACKAGE_NAME_CLIENT_PATTERN);
}
@Override
public String getModelPackageName(String serviceName) {
// Share model package classes if we are sharing models.
if (customizationConfig.getShareModelConfig() != null
&& customizationConfig.getShareModelConfig().getShareModelWith() != null) {
serviceName = customizationConfig.getShareModelConfig().getShareModelWith();
}
return getCustomizedPackageName(serviceName,
Constant.PACKAGE_NAME_MODEL_PATTERN);
}
@Override
public String getTransformPackageName(String serviceName) {
// Share transform package classes if we are sharing models.
if (customizationConfig.getShareModelConfig() != null
&& customizationConfig.getShareModelConfig().getShareModelWith() != null) {
serviceName = customizationConfig.getShareModelConfig().getShareModelWith();
}
return getCustomizedPackageName(serviceName,
Constant.PACKAGE_NAME_TRANSFORM_PATTERN);
}
@Override
public String getRequestTransformPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName),
Constant.PACKAGE_NAME_TRANSFORM_PATTERN);
}
@Override
public String getPaginatorsPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_PAGINATORS_PATTERN);
}
@Override
public String getWaitersPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_WAITERS_PATTERN);
}
@Override
public String getEndpointRulesPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_RULES_PATTERN);
}
@Override
public String getAuthSchemePackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_AUTH_SCHEME_PATTERN);
}
@Override
public String getJmesPathPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_JMESPATH_PATTERN);
}
@Override
public String getBatchManagerPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName), Constant.PACKAGE_NAME_BATCHMANAGER_PATTERN);
}
@Override
public String getSmokeTestPackageName(String serviceName) {
return getCustomizedPackageName(concatServiceNameIfShareModel(serviceName),
Constant.PACKAGE_NAME_SMOKE_TEST_PATTERN);
}
/**
* If the service is sharing models with other services, we need to concatenate its customized package name
* if provided or service name with the shared service name.
*/
private String concatServiceNameIfShareModel(String serviceName) {
if (customizationConfig.getShareModelConfig() != null) {
return customizationConfig.getShareModelConfig().getShareModelWith() + "." +
Optional.ofNullable(customizationConfig.getShareModelConfig().getPackageName()).orElse(serviceName);
}
return serviceName;
}
private String screamCase(String word) {
return Stream.of(splitOnWordBoundaries(word)).map(s -> s.toUpperCase(Locale.US)).collect(joining("_"));
}
private String getCustomizedPackageName(String serviceName, String defaultPattern) {
return String.format(defaultPattern, StringUtils.lowerCase(serviceName));
}
@Override
public String getExceptionName(String errorShapeName) {
String baseName;
if (errorShapeName.endsWith(FAULT_CLASS_SUFFIX)) {
baseName = pascalCase(errorShapeName.substring(0, errorShapeName.length() - FAULT_CLASS_SUFFIX.length())) +
EXCEPTION_CLASS_SUFFIX;
} else if (errorShapeName.endsWith(EXCEPTION_CLASS_SUFFIX)) {
baseName = pascalCase(errorShapeName);
} else {
baseName = pascalCase(errorShapeName) + EXCEPTION_CLASS_SUFFIX;
}
if (baseName.equals(getServiceName() + EXCEPTION_CLASS_SUFFIX)) {
return COLLISION_DISAMBIGUATION_PREFIX + baseName;
}
return baseName;
}
@Override
public String getRequestClassName(String operationName) {
String baseName = pascalCase(operationName) + REQUEST_CLASS_SUFFIX;
if (!operationName.equals(getServiceName())) {
return baseName;
}
return COLLISION_DISAMBIGUATION_PREFIX + baseName;
}
@Override
public String getResponseClassName(String operationName) {
String baseName = pascalCase(operationName) + RESPONSE_CLASS_SUFFIX;
if (!operationName.equals(getServiceName())) {
return baseName;
}
return COLLISION_DISAMBIGUATION_PREFIX + baseName;
}
@Override
public String getVariableName(String name) {
// Exclude keywords because they will not compile, and exclude reserved method names because they're frequently
// used for local variable names.
if (isJavaKeyword(name) ||
RESERVED_STRUCTURE_METHOD_NAMES.contains(name) ||
RESERVED_EXCEPTION_METHOD_NAMES.contains(name)) {
return unCapitalize(name + CONFLICTING_NAME_SUFFIX);
}
return unCapitalize(name);
}
@Override
public String getEnumValueName(String enumValue) {
String result = enumValue;
// Special cases
result = result.replace("textORcsv", "TEXT_OR_CSV");
// Split into words
result = String.join("_", splitOnWordBoundaries(result));
// Enums should be upper-case
result = StringUtils.upperCase(result);
if (!result.matches("^[A-Z][A-Z0-9_]*$")) {
String attempt = result;
log.warn(() -> "Invalid enum member generated for input '" + enumValue + "'. Best attempt: '" + attempt + "' If this "
+ "enum is not customized out, the build will fail.");
}
return result;
}
@Override
public String getShapeClassName(String shapeName) {
return Utils.capitalize(shapeName);
}
@Override
public String getFluentGetterMethodName(String memberName, Shape parentShape, Shape shape) {
String getterMethodName = Utils.unCapitalize(memberName);
getterMethodName = rewriteInvalidMemberName(getterMethodName, parentShape);
if (Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
getterMethodName += "AsString";
if (Utils.isListShape(shape) || Utils.isMapShape(shape)) {
getterMethodName += "s";
}
}
return getterMethodName;
}
@Override
public String getFluentEnumGetterMethodName(String memberName, Shape parentShape, Shape shape) {
if (!Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
return null;
}
String getterMethodName = Utils.unCapitalize(memberName);
getterMethodName = rewriteInvalidMemberName(getterMethodName, parentShape);
return getterMethodName;
}
@Override
public String getExistenceCheckMethodName(String memberName, Shape parentShape) {
String existenceCheckMethodName = Utils.unCapitalize(memberName);
existenceCheckMethodName = rewriteInvalidMemberName(existenceCheckMethodName, parentShape);
return String.format("has%s", Utils.capitalize(existenceCheckMethodName));
}
@Override
public String getBeanStyleGetterMethodName(String memberName, Shape parentShape, Shape c2jShape) {
String fluentGetterMethodName;
if (Utils.isOrContainsEnumShape(c2jShape, serviceModel.getShapes())) {
// Use the enum (modeled) name for bean-style getters
fluentGetterMethodName = getFluentEnumGetterMethodName(memberName, parentShape, c2jShape);
} else {
fluentGetterMethodName = getFluentGetterMethodName(memberName, parentShape, c2jShape);
}
return String.format("get%s", Utils.capitalize(fluentGetterMethodName));
}
@Override
public String getBeanStyleSetterMethodName(String memberName, Shape parentShape, Shape c2jShape) {
String beanStyleGetter = getBeanStyleGetterMethodName(memberName, parentShape, c2jShape);
return String.format("set%s", beanStyleGetter.substring("get".length()));
}
@Override
public String getFluentSetterMethodName(String memberName, Shape parentShape, Shape shape) {
String setterMethodName = Utils.unCapitalize(memberName);
setterMethodName = rewriteInvalidMemberName(setterMethodName, parentShape);
if (Utils.isOrContainsEnumShape(shape, serviceModel.getShapes()) &&
(Utils.isListShape(shape) || Utils.isMapShape(shape))) {
setterMethodName += "WithStrings";
}
return setterMethodName;
}
@Override
public String getFluentEnumSetterMethodName(String memberName, Shape parentShape, Shape shape) {
if (!Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
return null;
}
String setterMethodName = Utils.unCapitalize(memberName);
setterMethodName = rewriteInvalidMemberName(setterMethodName, parentShape);
return setterMethodName;
}
@Override
public String getSdkFieldFieldName(MemberModel memberModel) {
return screamCase(memberModel.getName()) + "_FIELD";
}
@Override
public String getUnionEnumTypeName(MemberModel memberModel) {
return screamCase(memberModel.getName());
}
private String rewriteInvalidMemberName(String memberName, Shape parentShape) {
if (isJavaKeyword(memberName) || isDisallowedNameForShape(memberName, parentShape)) {
return Utils.unCapitalize(memberName + CONFLICTING_NAME_SUFFIX);
}
return memberName;
}
private boolean isDisallowedNameForShape(String name, Shape parentShape) {
// Reserve the name "type" for union shapes.
if (parentShape.isUnion() && "type".equals(name)) {
return true;
}
if (parentShape.isException()) {
return RESERVED_EXCEPTION_METHOD_NAMES.contains(name);
} else {
return RESERVED_STRUCTURE_METHOD_NAMES.contains(name);
}
}
@Override
public void validateCustomerVisibleNaming(IntermediateModel trimmedModel) {
Metadata metadata = trimmedModel.getMetadata();
validateCustomerVisibleName(metadata.getSyncInterface(), "metadata-derived interface name");
validateCustomerVisibleName(metadata.getSyncBuilderInterface(), "metadata-derived builder interface name");
validateCustomerVisibleName(metadata.getAsyncInterface(), "metadata-derived async interface name");
validateCustomerVisibleName(metadata.getAsyncBuilderInterface(), "metadata-derived async builder interface name");
validateCustomerVisibleName(metadata.getBaseBuilderInterface(), "metadata-derived builder interface name");
validateCustomerVisibleName(metadata.getBaseExceptionName(), "metadata-derived exception name");
validateCustomerVisibleName(metadata.getBaseRequestName(), "metadata-derived request name");
validateCustomerVisibleName(metadata.getBaseResponseName(), "metadata-derived response name");
trimmedModel.getOperations().values().forEach(operation -> {
validateCustomerVisibleName(operation.getOperationName(), "operations");
});
trimmedModel.getWaiters().forEach((name, waiter) -> {
validateCustomerVisibleName(name, "waiters");
});
trimmedModel.getShapes().values().forEach(shape -> {
String shapeName = shape.getShapeName();
validateCustomerVisibleName(shapeName, "shapes");
shape.getMembers().forEach(member -> {
validateCustomerVisibleName(member.getFluentGetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getFluentSetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getFluentEnumGetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getFluentEnumSetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getExistenceCheckMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getBeanStyleGetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getBeanStyleSetterMethodName(), shapeName + " shape");
validateCustomerVisibleName(member.getEnumType(), shapeName + " shape");
});
});
}
private void validateCustomerVisibleName(String name, String location) {
if (name == null) {
return;
}
if (name.contains("_")) {
UnderscoresInNameBehavior behavior = customizationConfig.getUnderscoresInNameBehavior();
String supportedBehaviors = Arrays.toString(UnderscoresInNameBehavior.values());
Validate.notNull(behavior,
"Encountered a name or identifier that the customer will see (%s in the %s) with an underscore. "
+ "This isn't idiomatic in Java. Please either remove the underscores or apply the "
+ "'underscoresInNameBehavior' customization for this service (Supported "
+ "'underscoresInNameBehavior' values: %s).", name, location, supportedBehaviors);
Validate.isTrue(behavior == UnderscoresInNameBehavior.ALLOW,
"Unsupported underscoresInShapeNameBehavior: %s. Supported values: %s", behavior, supportedBehaviors);
}
Validate.isTrue(VALID_IDENTIFIER_NAME.matcher(name).matches(),
"Encountered a name or identifier that is invalid within Java (%s in %s). Please remove invalid "
+ "characters.", name, location);
}
}