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

software.amazon.smithy.traitcodegen.generators.TraitGenerator Maven / Gradle / Ivy

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

package software.amazon.smithy.traitcodegen.generators;

import java.util.function.Consumer;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.DocumentShape;
import software.amazon.smithy.model.shapes.EnumShape;
import software.amazon.smithy.model.shapes.IntEnumShape;
import software.amazon.smithy.model.shapes.ListShape;
import software.amazon.smithy.model.shapes.MapShape;
import software.amazon.smithy.model.shapes.NumberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.shapes.ShapeType;
import software.amazon.smithy.model.shapes.ShapeVisitor;
import software.amazon.smithy.model.shapes.StringShape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.TimestampShape;
import software.amazon.smithy.model.traits.AbstractTrait;
import software.amazon.smithy.model.traits.StringListTrait;
import software.amazon.smithy.model.traits.StringTrait;
import software.amazon.smithy.traitcodegen.GenerateTraitDirective;
import software.amazon.smithy.traitcodegen.TraitCodegenContext;
import software.amazon.smithy.traitcodegen.TraitCodegenUtils;
import software.amazon.smithy.traitcodegen.sections.ClassSection;
import software.amazon.smithy.traitcodegen.writer.TraitCodegenWriter;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
 * Consumer that generates a trait class definition from a {@link GenerateTraitDirective}.
 *
 * 

This base class will automatically generate a provider method and add that provider to the * {@code META-INF/services/software.amazon.smithy.model.traits.TraitService} service provider * file so the generated trait implementation will be discoverable by a {@code ServiceLoader}. */ class TraitGenerator implements Consumer { private static final String PROVIDER_FILE = "META-INF/services/software.amazon.smithy.model.traits.TraitService"; @Override public void accept(GenerateTraitDirective directive) { directive.context().writerDelegator().useShapeWriter(directive.shape(), writer -> { writer.pushState(new ClassSection(directive.shape())); // Add class definition context writer.putContext("baseClass", directive.shape().accept(new BaseClassVisitor(directive.symbolProvider()))); // Only collection types implement ToSmithyBuilder boolean isAggregateType = directive.shape().getType().getCategory().equals(ShapeType.Category.AGGREGATE); writer.putContext("isAggregateType", isAggregateType); writer.openBlock("public final class $2T extends $baseClass:T" + "${?isAggregateType} implements $1T<$2T>${/isAggregateType} {", "}", ToSmithyBuilder.class, directive.symbol(), () -> { // All traits include a static ID property writer.write("public static final $1T ID = $1T.from($2S);", ShapeId.class, directive.shape().getId()); writer.newLine(); new PropertiesGenerator(writer, directive.shape(), directive.symbolProvider()).run(); new ConstructorGenerator(writer, directive.symbol(), directive.shape(), directive.symbolProvider()).run(); // Abstract Traits need to define serde methods if (AbstractTrait.class.equals( directive.shape().accept(new BaseClassVisitor(directive.symbolProvider()))) ) { new ToNodeGenerator(writer, directive.shape(), directive.symbolProvider(), directive.model()).run(); } new FromNodeGenerator(writer, directive.symbol(), directive.shape(), directive.symbolProvider(), directive.model()).run(); new GetterGenerator(writer, directive.symbolProvider(), directive.model(), directive.shape()).run(); directive.shape().accept(new NestedClassVisitor(writer, directive.symbolProvider(), directive.model())); new BuilderGenerator(writer, directive.symbol(), directive.symbolProvider(), directive.shape(), directive.model()).run(); new ProviderGenerator(writer, directive.model(), directive.shape(), directive.symbolProvider(), directive.symbol()).run(); }); writer.popState(); }); // Add the trait provider to the META-INF/services/TraitService file addSpiTraitProvider(directive.context(), directive.symbol()); } /** * Write provider method to Java SPI to service file for {@link software.amazon.smithy.model.traits.TraitService}. * * @param context Codegen context * @param symbol Symbol for trait class */ private static void addSpiTraitProvider(TraitCodegenContext context, Symbol symbol) { context.writerDelegator().useFileWriter(PROVIDER_FILE, writer -> writer.writeInline("$L$$Provider", symbol.getFullName())); } /** * Returns the base class to use for a trait. */ private static final class BaseClassVisitor extends TraitVisitor> { private final SymbolProvider symbolProvider; private BaseClassVisitor(SymbolProvider symbolProvider) { this.symbolProvider = symbolProvider; } @Override public Class listShape(ListShape shape) { // Do not create a property if the shape can inherit from the StringListTrait base class. if (TraitCodegenUtils.isJavaStringList(shape, symbolProvider)) { return StringListTrait.class; } return AbstractTrait.class; } @Override public Class mapShape(MapShape shape) { return AbstractTrait.class; } @Override public Class documentShape(DocumentShape shape) { return AbstractTrait.class; } @Override public Class stringShape(StringShape shape) { if (TraitCodegenUtils.isJavaString(symbolProvider.toSymbol(shape))) { return StringTrait.class; } return AbstractTrait.class; } @Override public Class enumShape(EnumShape shape) { return StringTrait.class; } @Override public Class structureShape(StructureShape shape) { return AbstractTrait.class; } @Override public Class timestampShape(TimestampShape shape) { return AbstractTrait.class; } @Override protected Class numberShape(NumberShape shape) { return AbstractTrait.class; } } private static final class NestedClassVisitor extends ShapeVisitor.Default { private final TraitCodegenWriter writer; private final SymbolProvider symbolProvider; private final Model model; private NestedClassVisitor(TraitCodegenWriter writer, SymbolProvider symbolProvider, Model model) { this.writer = writer; this.symbolProvider = symbolProvider; this.model = model; } @Override protected Void getDefault(Shape shape) { // Most classes have no nested classes return null; } @Override public Void intEnumShape(IntEnumShape shape) { new EnumShapeGenerator.IntEnumShapeGenerator().writeEnum(shape, symbolProvider, writer, model, false); writer.newLine(); return null; } @Override public Void enumShape(EnumShape shape) { new EnumShapeGenerator.StringEnumShapeGenerator().writeEnum(shape, symbolProvider, writer, model, false); writer.newLine(); return null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy