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

software.amazon.smithy.traitcodegen.generators.ProviderGenerator 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 software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.DocumentShape;
import software.amazon.smithy.model.shapes.EnumShape;
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.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.model.traits.Trait;
import software.amazon.smithy.traitcodegen.TraitCodegenUtils;
import software.amazon.smithy.traitcodegen.writer.TraitCodegenWriter;


/**
 * Adds provider class to use as the {@link software.amazon.smithy.model.traits.TraitService} implementation for a
 * trait.
 *
 * 

This provider class is only required for Trait classes, and is not needed in nested shapes. The {@code fromNode} * method is used where possible to create the smithy node from the provided node. Provider methods MUST * be added to the {@code META-INF/services/software.amazon.smithy.model.traits.TraitService} service provider file * for the Trait class to be discovered during model assembly. */ final class ProviderGenerator implements Runnable { private final TraitCodegenWriter writer; private final Model model; private final Shape shape; private final SymbolProvider provider; private final Symbol traitSymbol; ProviderGenerator(TraitCodegenWriter writer, Model model, Shape shape, SymbolProvider provider, Symbol traitSymbol ) { this.writer = writer; this.model = model; this.shape = shape; this.provider = provider; this.traitSymbol = traitSymbol; } @Override public void run() { shape.accept(new ProviderMethodVisitor()); } private final class ProviderMethodVisitor extends TraitVisitor { @Override public Void documentShape(DocumentShape shape) { writer.openBlock("public static final class Provider extends $T.Provider {", "}", AbstractTrait.class, () -> { generateProviderConstructor(); writer.newLine(); writer.override(); writer.openBlock("public $T createTrait($T target, $T value) {", "}", Trait.class, ShapeId.class, Node.class, () -> writer.write("return new $T(value);", traitSymbol)); }); return null; } @Override public Void stringShape(StringShape shape) { // If the symbol resolves to a simple java string use the simplified string // provider. Otherwise, use a generic value shape provider. if (TraitCodegenUtils.isJavaString(traitSymbol)) { generateStringShapeProvider(); } else { generateValueShapeProvider(); } return null; } @Override public Void mapShape(MapShape shape) { generateAbstractTraitProvider(); return null; } @Override public Void listShape(ListShape shape) { // If the trait is a string-only list we can use a simpler provider from the StringListTrait base class if (TraitCodegenUtils.isJavaStringList(shape, provider)) { writer.openBlock("public static final class Provider extends $T.Provider<$T> {", "}", StringListTrait.class, traitSymbol, () -> writer.openBlock("public Provider() {", "}", () -> writer.write("super(ID, $T::new);", traitSymbol))); } else { generateAbstractTraitProvider(); } return null; } @Override public Void enumShape(EnumShape shape) { generateStringShapeProvider(); return null; } @Override public Void structureShape(StructureShape shape) { generateAbstractTraitProvider(); return null; } @Override public Void timestampShape(TimestampShape shape) { generateAbstractTraitProvider(); return null; } @Override protected Void numberShape(NumberShape shape) { generateValueShapeProvider(); return null; } private void generateAbstractTraitProvider() { writer.openBlock("public static final class Provider extends $T.Provider {", "}", AbstractTrait.class, () -> { generateProviderConstructor(); writer.override(); writer.openBlock("public $T createTrait($T target, $T value) {", "}", Trait.class, ShapeId.class, Node.class, () -> { writer.write("$1T result = $1T.fromNode(value);", traitSymbol); writer.writeWithNoFormatting("result.setNodeCache(value);"); writer.writeWithNoFormatting("return result;"); }); }); } private void generateProviderConstructor() { writer.openBlock("public Provider() {", "}", () -> writer.write("super(ID);")).newLine(); } private void generateValueShapeProvider() { writer.openBlock("public static final class Provider extends $T.Provider {", "}", AbstractTrait.class, () -> { generateProviderConstructor(); writer.override(); writer.openBlock("public $T createTrait($T target, $T value) {", "}", Trait.class, ShapeId.class, Node.class, () -> writer.write("return new $1T($2C, value.getSourceLocation());", traitSymbol, (Runnable) () -> shape.accept(new FromNodeMapperVisitor(writer, model, "value"))) ); }); } private void generateStringShapeProvider() { writer.openBlock("public static final class Provider extends $T.Provider<$T> {", "}", StringTrait.class, traitSymbol, () -> writer.openBlock("public Provider() {", "}", () -> writer.write("super(ID, $T::new);", traitSymbol))); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy