From a2c527507a942c91cfe78b367dba3e232c049184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Sun, 8 Mar 2026 21:10:41 -0700 Subject: [PATCH 1/2] Add logic to avoid conficts between the enum class and variants class names --- .../java/codegen/JavaSymbolProvider.java | 28 ++++ .../smithy/java/codegen/SymbolProperties.java | 5 + .../codegen/generators/EnumGenerator.java | 17 +-- .../ExternalTypesIntegration.java | 4 + .../test-cases/enums/expected/TextType.java | 140 ++++++++++++++++++ .../types/test-cases/enums/model/main.smithy | 8 +- 6 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/TextType.java diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/JavaSymbolProvider.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/JavaSymbolProvider.java index 162b98445..c78b4d7f0 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/JavaSymbolProvider.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/JavaSymbolProvider.java @@ -51,6 +51,7 @@ import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.model.traits.StreamingTrait; import software.amazon.smithy.model.traits.UnitTypeTrait; +import software.amazon.smithy.utils.CaseUtils; /** * Maps Smithy types to Java Symbols @@ -187,6 +188,33 @@ public Symbol stringShape(StringShape stringShape) { @Override public Symbol memberShape(MemberShape memberShape) { + var container = model.getShape(memberShape.getContainer()) + .orElseThrow( + () -> new CodegenException( + "Could not find shape " + memberShape.getContainer() + " containing " + + memberShape)); + if (container.isEnumShape() || container.isIntEnumShape()) { + // Adds a property SymbolProperties.ENUM_VARIANT_CLASS_NAME containing the class name + // for each of the enum variants. The class name is created by converting the enum field + // name (typically UPPER_SNAKE_CASE like OPTION_ONE) to a class name (PascalCase like + // OptionOneType). The "Type" suffix avoids conflicts with java. If the resulting + // name conflicts with the enum class name the suffix value is added after "Type". + var memberName = CodegenUtils.toMemberName(memberShape, model); + var className = CaseUtils.toPascalCase(memberName) + "Type"; + var targetName = CodegenUtils.getDefaultName(container, service); + if (targetName.equals(className)) { + className = className + "Value"; + } + Symbol targetSymbol; + if (container.isEnumShape()) { + targetSymbol = CodegenUtils.fromClass(String.class); + } else { + targetSymbol = CodegenUtils.fromClass(Integer.class); + } + return targetSymbol.toBuilder() + .putProperty(SymbolProperties.ENUM_VARIANT_CLASS_NAME, className) + .build(); + } var target = model.getShape(memberShape.getTarget()) .orElseThrow( () -> new CodegenException( diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/SymbolProperties.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/SymbolProperties.java index b958b848a..28a4f11b5 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/SymbolProperties.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/SymbolProperties.java @@ -67,6 +67,11 @@ public final class SymbolProperties { */ public static final Property ENUM_VALUE_TYPE = Property.named("enum-value-type"); + /** + * Symbol representing the class name for an enum variant. + */ + public static final Property ENUM_VARIANT_CLASS_NAME = Property.named("enum-value-class-name"); + /** * Indicates that the symbol is defined outside the current closure. */ diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java index a2f3e230a..bdedbd25b 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java @@ -27,7 +27,6 @@ import software.amazon.smithy.model.shapes.IntEnumShape; import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.model.shapes.Shape; -import software.amazon.smithy.utils.CaseUtils; import software.amazon.smithy.utils.SmithyInternalApi; @SmithyInternalApi @@ -110,7 +109,8 @@ public void run() { for (var member : shape.members()) { writer.pushState(new EnumVariantSection(member)); var fieldName = symbolProvider.toMemberName(member); - var className = toClassName(fieldName); + var className = + symbolProvider.toSymbol(member).expectProperty(SymbolProperties.ENUM_VARIANT_CLASS_NAME); types.add(fieldName); writer.putContext("fieldName", fieldName); writer.putContext("className", className); @@ -181,8 +181,8 @@ public void run() { // Generate known enum variant classes for (var member : shape.members()) { writer.pushState(); - var fieldName = symbolProvider.toMemberName(member); - var className = toClassName(fieldName); + var className = + symbolProvider.toSymbol(member).expectProperty(SymbolProperties.ENUM_VARIANT_CLASS_NAME); var memberValue = enumValues.get(member.getMemberName()); var template = """ @@ -333,13 +333,4 @@ private static Map getEnumValues(Shape shape) { throw new IllegalArgumentException("Expected Int enum or enum"); } } - - /** - * Converts an enum field name (typically UPPER_SNAKE_CASE like OPTION_ONE) - * to a class name (PascalCase like OptionOneType). The "Type" suffix avoids - * conflicts with java.lang types like String, Boolean, etc. - */ - private static String toClassName(String fieldName) { - return CaseUtils.toPascalCase(fieldName) + "Type"; - } } diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java index af25a32ad..20b0c7d92 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java @@ -104,6 +104,10 @@ public Symbol toSymbol(Shape shape) { .references(List.of(new SymbolReference(keySymbol), new SymbolReference(valueSymbol))) .build(); } + if (shape.getId().equals(ShapeId.from("smithy.api#Unit"))) { + return symbolProvider.toSymbol(shape); + } + return symbolProvider.toSymbol(shape); } diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/TextType.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/TextType.java new file mode 100644 index 000000000..f89d34eb0 --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/TextType.java @@ -0,0 +1,140 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableShape; +import software.amazon.smithy.java.core.schema.ShapeBuilder; +import software.amazon.smithy.java.core.serde.ShapeDeserializer; +import software.amazon.smithy.java.core.serde.ShapeSerializer; +import software.amazon.smithy.java.core.serde.ToStringSerializer; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.utils.SmithyGenerated; + +@SmithyGenerated +public sealed interface TextType extends SerializableShape { + TextType TEXT = new TextTypeValue(); + List $TYPES = List.of(TEXT); + + Schema $SCHEMA = Schema.createEnum(ShapeId.from("smithy.java.codegen.types.naming#TextType"), + Set.of(TEXT.getValue()) + ); + + ShapeId $ID = $SCHEMA.id(); + + String getValue(); + + @Override + default void serialize(ShapeSerializer serializer) { + serializer.writeString($SCHEMA, getValue()); + } + + /** + * Create an unknown enum variant with the given value. + * + * @param value value for the unknown variant. + */ + static TextType unknown(String value) { + return new $Unknown(value); + } + + /** + * Returns an unmodifiable list containing the constants of this enum type, in the order declared. + */ + static List values() { + return $TYPES; + } + + /** + * Returns a {@link TextType} constant with the specified value. + * + * @param value value to create {@code TextType} from. + * @throws IllegalArgumentException if value does not match a known value. + */ + static TextType from(String value) { + return switch (value) { + case "TEXT" -> TEXT; + default -> throw new IllegalArgumentException("Unknown value: " + value); + }; + } + + final class TextTypeValue implements TextType { + private TextTypeValue() {} + + @Override + public String getValue() { + return "TEXT"; + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + } + + record $Unknown(String value) implements TextType { + public $Unknown { + Objects.requireNonNull(value, "Value cannot be null"); + } + + @Override + public String getValue() { + return value; + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + private final class $Hidden implements TextType { + @Override + public String getValue() { + return null; + } + } + } + + /** + * @return returns a new Builder. + */ + static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link TextType}. + */ + final class Builder implements ShapeBuilder { + private String value; + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + private Builder value(String value) { + this.value = Objects.requireNonNull(value, "Enum value cannot be null"); + return this; + } + + @Override + public TextType build() { + return switch (value) { + case "TEXT" -> TEXT; + default -> new $Unknown(value); + }; + } + + @Override + public Builder deserialize(ShapeDeserializer de) { + return value(de.readString($SCHEMA)); + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/model/main.smithy b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/model/main.smithy index 6a9a33678..821e52762 100644 --- a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/model/main.smithy +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/model/main.smithy @@ -2,18 +2,22 @@ $version: "2" namespace smithy.java.codegen.types.naming - structure EnumStructure { enumType : EnumType intEnumType: IntEnumType } + enum EnumType { OPTION_ONE = "option-one" OPTION_TWO = "option-two" } +enum TextType { + TEXT +} + intEnum IntEnumType { FIRST = 1 SECOND = 2 FIFTH = 5 -} \ No newline at end of file +} From 1a92f581b785dbeb7b22d4982a88e83ee6dcaa9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sugawara=20=28=E2=88=A9=EF=BD=80-=C2=B4=29?= =?UTF-8?q?=E2=8A=83=E2=94=81=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E=E7=82=8E?= Date: Mon, 9 Mar 2026 09:19:15 -0700 Subject: [PATCH 2/2] Remove non-used code --- .../integrations/externaltypes/ExternalTypesIntegration.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java index 20b0c7d92..af25a32ad 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/integrations/externaltypes/ExternalTypesIntegration.java @@ -104,10 +104,6 @@ public Symbol toSymbol(Shape shape) { .references(List.of(new SymbolReference(keySymbol), new SymbolReference(valueSymbol))) .build(); } - if (shape.getId().equals(ShapeId.from("smithy.api#Unit"))) { - return symbolProvider.toSymbol(shape); - } - return symbolProvider.toSymbol(shape); }