All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.smithy.traitcodegen.TraitCodegenUtils Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package software.amazon.smithy.traitcodegen;

import java.net.URL;
import software.amazon.smithy.codegen.core.ReservedWords;
import software.amazon.smithy.codegen.core.ReservedWordsBuilder;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.traits.UniqueItemsTrait;
import software.amazon.smithy.utils.CaseUtils;
import software.amazon.smithy.utils.SmithyInternalApi;
import software.amazon.smithy.utils.StringUtils;

/**
 * Provides utility methods for trait code generation.
 */
@SmithyInternalApi
public final class TraitCodegenUtils {
    public static final Symbol JAVA_STRING_SYMBOL = TraitCodegenUtils.fromClass(String.class);
    public static final URL RESERVED_WORDS_FILE = TraitCodegenUtils.class.getResource("reserved-words.txt");
    public static final ReservedWords SHAPE_ESCAPER = new ReservedWordsBuilder()
            .loadCaseInsensitiveWords(RESERVED_WORDS_FILE, word -> word + "Shape")
            .build();
    public static final ReservedWords MEMBER_ESCAPER = new ReservedWordsBuilder()
            .loadCaseInsensitiveWords(RESERVED_WORDS_FILE, word -> word + "Member")
            .build();

    private TraitCodegenUtils() {}

    /**
     * Gets a Smithy codegen {@link Symbol} for a Java class.
     *
     * @param clazz class to get symbol for.
     * @return Symbol representing the provided class.
     */
    public static Symbol fromClass(Class clazz) {
        Symbol.Builder builder =  Symbol.builder()
                .name(clazz.getSimpleName())
                .namespace(clazz.getCanonicalName().replace("." + clazz.getSimpleName(), ""), ".");

        if (clazz.isPrimitive()) {
            builder.putProperty(SymbolProperties.IS_PRIMITIVE, true);
        }

        return builder.build();
    }

    /**
     * Gets the default class name to use for a given Smithy {@link Shape}.
     *
     * @param shape Shape to get name for.
     * @return Default name.
     */
    public static String getDefaultName(Shape shape) {
        String baseName = shape.getId().getName();

        // If the name contains any problematic delimiters, use PascalCase converter,
        // otherwise, just capitalize first letter to avoid messing with user-defined
        // capitalization.
        String unescaped;
        if (baseName.contains("_")) {
            unescaped = CaseUtils.toPascalCase(shape.getId().getName());
        } else {
            unescaped = StringUtils.capitalize(baseName);
        }

        return SHAPE_ESCAPER.escape(unescaped);
    }

    /**
     * Gets the default class name to use for a given Smithy {@link Shape} that
     * defines a trait.
     *
     * @param shape Shape to get name for.
     * @return Default name.
     */
    public static String getDefaultTraitName(Shape shape) {
        String name = getDefaultName(shape);

        // If the trait class name doesn't already end with `Trait`,
        // use that. Otherwise, append the `Trait` suffix.
        if (name.endsWith("Trait")) {
            return name;
        }

        return name + "Trait";
    }

    /**
     * Checks if a symbol maps to a Java {@link String}.
     *
     * @param symbol Symbol to check.
     * @return Returns true if the symbol maps to a Java String.
     */
    public static boolean isJavaString(Symbol symbol) {
        Symbol baseSymbol = symbol.getProperty(SymbolProperties.BASE_SYMBOL).orElse(symbol);
        return JAVA_STRING_SYMBOL.getName().equals(baseSymbol.getName())
                && JAVA_STRING_SYMBOL.getNamespace().equals(baseSymbol.getNamespace());
    }

    /**
     * Checks if a symbol maps to a Java {@code List}.
     *
     * @param shape shape to check if it resolves to a list of java strings
     * @param symbolProvider symbol provider to use for checking member type
     * @return Returns true if the symbol maps to a Java String List.
     */
    public static boolean isJavaStringList(Shape shape, SymbolProvider symbolProvider) {
        return shape.isListShape()
                && !shape.hasTrait(UniqueItemsTrait.class)
                && TraitCodegenUtils.isJavaString(symbolProvider.toSymbol(
                        shape.asListShape().get().getMember()));
    }

    /**
     * Maps a smithy namespace to a java package namespace.
     *
     * @param rootSmithyNamespace base smithy namespace in use for trait codegen trait discovery
     * @param shapeNamespace namespace of shape to map into package namespace.
     * @param packageNamespace Java package namespace for trait codegen.
     */
    public static String mapNamespace(String rootSmithyNamespace,
                                      String shapeNamespace,
                                      String packageNamespace
    ) {
        if (!shapeNamespace.startsWith(rootSmithyNamespace)) {
            throw new IllegalArgumentException("Cannot relativize non-nested namespaces "
                    + "Root: " + rootSmithyNamespace + " Nested: " + shapeNamespace + ".");
        }
        return shapeNamespace.replace(rootSmithyNamespace, packageNamespace);
    }

    /**
     * Determines if a given member represents a nullable type.
     *
     * @see structure member optionality
     *
     * @param shape member to check for nullability
     *
     * @return if the shape is a nullable type
     */
    public static boolean isNullableMember(MemberShape shape) {
        return !shape.isRequired() && !shape.hasNonNullDefault();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy