diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/CodegenUtils.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/CodegenUtils.java index fe36c4df5..c06c6aad9 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/CodegenUtils.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/CodegenUtils.java @@ -338,6 +338,8 @@ public static String toUpperSnakeCase(String string) { */ public static Symbol getInnerTypeEnumSymbol(Symbol symbol) { return symbol.toBuilder() + .namespace(symbol.getFullName(), ".") + .putProperty(SymbolProperties.IS_LOCALLY_DEFINED, true) .name("Type") .build(); } 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 c52ccd94e..b958b848a 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 @@ -32,6 +32,11 @@ public final class SymbolProperties { */ public static final Property IS_JAVA_ARRAY = Property.named("is-java-array"); + /** + * Indicates if a symbol represents an inner class. + */ + public static final Property IS_LOCALLY_DEFINED = Property.named("is-locally-defined"); + /** * Method on {@link java.util.Collection} to use to create an immutable copy of the collection type * a symbol represents. diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/UnionGenerator.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/UnionGenerator.java index d71d6c559..1df358b54 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/UnionGenerator.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/UnionGenerator.java @@ -42,6 +42,8 @@ public void accept(GenerateUnionDirective { + var innerTypeEnumSymbol = CodegenUtils.getInnerTypeEnumSymbol(directive.symbol()); + writer.addLocallyDefinedSymbol(innerTypeEnumSymbol); writer.pushState(new ClassSection(shape)); var template = """ public abstract class ${shape:T} implements ${serializableStruct:T} { @@ -97,7 +99,7 @@ public boolean equals(${object:T} other) { } """; writer.putContext("shape", directive.symbol()); - writer.putContext("type", CodegenUtils.getInnerTypeEnumSymbol(directive.symbol())); + writer.putContext("type", innerTypeEnumSymbol); writer.putContext("serializableStruct", SerializableStruct.class); writer.putContext("shapeSerializer", ShapeSerializer.class); writer.putContext("schemaClass", Schema.class); diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaImportContainer.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaImportContainer.java index e709ae69b..70ddd9221 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaImportContainer.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaImportContainer.java @@ -26,8 +26,10 @@ final class JavaImportContainer implements ImportContainer { @Override public void importSymbol(Symbol symbol, String s) { - // Do not import primitive types or java.lang standard library imports. - if (symbol.expectProperty(SymbolProperties.IS_PRIMITIVE) || symbol.getNamespace().startsWith("java.lang")) { + // Do not import primitive types, java.lang standard library imports or inner classes. + if (symbol.expectProperty(SymbolProperties.IS_PRIMITIVE) + || symbol.getNamespace().startsWith("java.lang") + || symbol.getProperty(SymbolProperties.IS_LOCALLY_DEFINED).isPresent()) { return; } Set duplicates = imports.computeIfAbsent(symbol.getName(), sn -> new HashSet<>()); diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaWriter.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaWriter.java index 76780b4be..7fc083f8e 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaWriter.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/writer/JavaWriter.java @@ -5,6 +5,7 @@ package software.amazon.smithy.java.codegen.writer; +import java.util.HashSet; import java.util.Set; import java.util.function.BiFunction; import software.amazon.smithy.codegen.core.Symbol; @@ -33,6 +34,7 @@ public final class JavaWriter extends DeferredSymbolWriter locallyDefinedNames = new HashSet<>(); public JavaWriter(JavaCodegenSettings settings, String packageNamespace, String filename) { super(new JavaImportContainer(packageNamespace)); @@ -87,28 +89,56 @@ public void newLine() { private void putNameContext() { // Add any implicit usages from classes in the same package var packageSymbols = settings.getGeneratedSymbolsPackage(packageNamespace); - packageSymbols.forEach(this::addToSymbolTable); - for (final Set duplicates : symbolTable.values()) { + Set packageDefinedNames = new HashSet<>(); + for (Symbol packageSymbol : packageSymbols) { + packageDefinedNames.add(packageSymbol.getName()); + } + for (Set duplicates : symbolTable.values()) { // If the duplicates list has more than one entry // then duplicates are present, and we need to de-duplicate the names if (duplicates.size() > 1) { duplicates.forEach(dupe -> putContext(dupe.getFullName(), deduplicate(dupe))); } else { Symbol symbol = duplicates.iterator().next(); - putContext(symbol.getFullName().replace("[]", "Array"), symbol.getName()); + // Use fully qualified names for java.lang.* if there is duplicate names + // defined under the same package. + String symbolName = symbol.getName(); + if (packageDefinedNames.contains(symbol.getName()) && symbol.getNamespace().equals("java.lang")) { + symbolName = symbol.getFullName(); + } + putContext(symbol.getFullName(), symbolName); } } } private String deduplicate(Symbol dupe) { - // If we are in the namespace of a Symbol, use its - // short name, otherwise use the full name - if (dupe.getNamespace().equals(packageNamespace)) { + if (useSimpleName(dupe)) { return dupe.getName(); } return dupe.getFullName(); } + private boolean useSimpleName(Symbol dupe) { + // Only locally defined symbols and those symbols with non-conflicting names + // under the same namespace can use short name. + if (locallyDefinedNames.contains(dupe.getName())) { + return dupe.getProperty(SymbolProperties.IS_LOCALLY_DEFINED).isPresent(); + } + return dupe.getNamespace().equals(packageNamespace); + } + + /** + * Records the local name defined within the current file, e.g., the name of an inner class. + * The writer will use this information to decide if it should use a fully qualified + * name when referencing types with the same name in its scope. + * + * @param symbol the symbol reserved in this file. + */ + public void addLocallyDefinedSymbol(Symbol symbol) { + locallyDefinedNames.add(symbol.getName()); + symbolTable.computeIfAbsent(symbol.getName(), k -> new HashSet<>()).add(symbol); + } + /** * A factory class to create {@link JavaWriter}s. */ diff --git a/codegen/codegen-core/src/main/resources/software/amazon/smithy/java/codegen/reserved-words.txt b/codegen/codegen-core/src/main/resources/software/amazon/smithy/java/codegen/reserved-words.txt index af81e9463..8fdc6a0de 100644 --- a/codegen/codegen-core/src/main/resources/software/amazon/smithy/java/codegen/reserved-words.txt +++ b/codegen/codegen-core/src/main/resources/software/amazon/smithy/java/codegen/reserved-words.txt @@ -25,6 +25,7 @@ double else enum extends +false final finally float @@ -33,13 +34,13 @@ goto if implements import -type instanceof int interface long native new +null object package private @@ -57,9 +58,7 @@ throw throws transient try +true void volatile while -true -false -null diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/BuilderShape.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/BuilderShape.java new file mode 100644 index 000000000..107f11fa9 --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/BuilderShape.java @@ -0,0 +1,114 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class BuilderShape implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.BUILDER; + + public static final ShapeId $ID = $SCHEMA.id(); + + private BuilderShape(Builder builder) { + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + return other != null && getClass() == other.getClass(); + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link BuilderShape}. + */ + public Builder toBuilder() { + var builder = new Builder(); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link BuilderShape}. + */ + public static final class Builder implements ShapeBuilder { + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public BuilderShape build() { + return new BuilderShape(this); + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) {} + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/List.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/List.java new file mode 100644 index 000000000..5544cbcbb --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/List.java @@ -0,0 +1,114 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class List implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.LIST; + + public static final ShapeId $ID = $SCHEMA.id(); + + private List(Builder builder) { + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + return other != null && getClass() == other.getClass(); + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link List}. + */ + public Builder toBuilder() { + var builder = new Builder(); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link List}. + */ + public static final class Builder implements ShapeBuilder { + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public List build() { + return new List(this); + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) {} + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Map.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Map.java new file mode 100644 index 000000000..a8c8defd7 --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Map.java @@ -0,0 +1,114 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class Map implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.MAP; + + public static final ShapeId $ID = $SCHEMA.id(); + + private Map(Builder builder) { + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + return other != null && getClass() == other.getClass(); + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link Map}. + */ + public Builder toBuilder() { + var builder = new Builder(); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link Map}. + */ + public static final class Builder implements ShapeBuilder { + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public Map build() { + return new Map(this); + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) {} + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/NamingStruct.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/NamingStruct.java new file mode 100644 index 000000000..2beeb0c77 --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/NamingStruct.java @@ -0,0 +1,363 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Collections; +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SchemaUtils; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class NamingStruct implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.NAMING_STRUCT; + private static final Schema $SCHEMA_OTHER = $SCHEMA.member("other"); + private static final Schema $SCHEMA_BUILDER_MEMBER = $SCHEMA.member("builder"); + private static final Schema $SCHEMA_TYPE = $SCHEMA.member("type"); + private static final Schema $SCHEMA_OBJECT_MEMBER = $SCHEMA.member("object"); + private static final Schema $SCHEMA_UNION = $SCHEMA.member("union"); + private static final Schema $SCHEMA_MAP = $SCHEMA.member("map"); + private static final Schema $SCHEMA_LIST = $SCHEMA.member("list"); + private static final Schema $SCHEMA_LIST_OF_LIST = $SCHEMA.member("listOfList"); + private static final Schema $SCHEMA_MAP_OF_MAP = $SCHEMA.member("mapOfMap"); + + public static final ShapeId $ID = $SCHEMA.id(); + + private final transient String other; + private final transient BuilderShape builderMember; + private final transient Type type; + private final transient ObjectShape objectMember; + private final transient UnionWithTypeMember union; + private final transient Map map; + private final transient List list; + private final transient java.util.List listOfList; + private final transient java.util.Map mapOfMap; + + private NamingStruct(Builder builder) { + this.other = builder.other; + this.builderMember = builder.builderMember; + this.type = builder.type; + this.objectMember = builder.objectMember; + this.union = builder.union; + this.map = builder.map; + this.list = builder.list; + this.listOfList = builder.listOfList == null ? null : Collections.unmodifiableList(builder.listOfList); + this.mapOfMap = builder.mapOfMap == null ? null : Collections.unmodifiableMap(builder.mapOfMap); + } + + public String getOther() { + return other; + } + + public BuilderShape getBuilder() { + return builderMember; + } + + public Type getType() { + return type; + } + + public ObjectShape getObject() { + return objectMember; + } + + public UnionWithTypeMember getUnion() { + return union; + } + + public Map getMap() { + return map; + } + + public List getList() { + return list; + } + + public java.util.List getListOfList() { + if (listOfList == null) { + return Collections.emptyList(); + } + return listOfList; + } + + public boolean hasListOfList() { + return listOfList != null; + } + + public java.util.Map getMapOfMap() { + if (mapOfMap == null) { + return Collections.emptyMap(); + } + return mapOfMap; + } + + public boolean hasMapOfMap() { + return mapOfMap != null; + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + NamingStruct that = (NamingStruct) other; + return Objects.equals(this.other, that.other) + && Objects.equals(this.builderMember, that.builderMember) + && Objects.equals(this.type, that.type) + && Objects.equals(this.objectMember, that.objectMember) + && Objects.equals(this.union, that.union) + && Objects.equals(this.map, that.map) + && Objects.equals(this.list, that.list) + && Objects.equals(this.listOfList, that.listOfList) + && Objects.equals(this.mapOfMap, that.mapOfMap); + } + + @Override + public int hashCode() { + return Objects.hash(other, builderMember, type, objectMember, union, map, list, listOfList, mapOfMap); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + if (other != null) { + serializer.writeString($SCHEMA_OTHER, other); + } + if (builderMember != null) { + serializer.writeStruct($SCHEMA_BUILDER_MEMBER, builderMember); + } + if (type != null) { + serializer.writeStruct($SCHEMA_TYPE, type); + } + if (objectMember != null) { + serializer.writeStruct($SCHEMA_OBJECT_MEMBER, objectMember); + } + if (union != null) { + serializer.writeStruct($SCHEMA_UNION, union); + } + if (map != null) { + serializer.writeStruct($SCHEMA_MAP, map); + } + if (list != null) { + serializer.writeStruct($SCHEMA_LIST, list); + } + if (listOfList != null) { + serializer.writeList($SCHEMA_LIST_OF_LIST, listOfList, listOfList.size(), SharedSerde.ListOfListSerializer.INSTANCE); + } + if (mapOfMap != null) { + serializer.writeMap($SCHEMA_MAP_OF_MAP, mapOfMap, mapOfMap.size(), SharedSerde.MapOfMapSerializer.INSTANCE); + } + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + return switch (member.memberIndex()) { + case 0 -> (T) SchemaUtils.validateSameMember($SCHEMA_OTHER, member, other); + case 1 -> (T) SchemaUtils.validateSameMember($SCHEMA_BUILDER_MEMBER, member, builderMember); + case 2 -> (T) SchemaUtils.validateSameMember($SCHEMA_TYPE, member, type); + case 3 -> (T) SchemaUtils.validateSameMember($SCHEMA_OBJECT_MEMBER, member, objectMember); + case 4 -> (T) SchemaUtils.validateSameMember($SCHEMA_UNION, member, union); + case 5 -> (T) SchemaUtils.validateSameMember($SCHEMA_MAP, member, map); + case 6 -> (T) SchemaUtils.validateSameMember($SCHEMA_LIST, member, list); + case 7 -> (T) SchemaUtils.validateSameMember($SCHEMA_LIST_OF_LIST, member, listOfList); + case 8 -> (T) SchemaUtils.validateSameMember($SCHEMA_MAP_OF_MAP, member, mapOfMap); + default -> throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + }; + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link NamingStruct}. + */ + public Builder toBuilder() { + var builder = new Builder(); + builder.other(this.other); + builder.builderMember(this.builderMember); + builder.type(this.type); + builder.objectMember(this.objectMember); + builder.union(this.union); + builder.map(this.map); + builder.list(this.list); + builder.listOfList(this.listOfList); + builder.mapOfMap(this.mapOfMap); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link NamingStruct}. + */ + public static final class Builder implements ShapeBuilder { + private String other; + private BuilderShape builderMember; + private Type type; + private ObjectShape objectMember; + private UnionWithTypeMember union; + private Map map; + private List list; + private java.util.List listOfList; + private java.util.Map mapOfMap; + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + /** + * @return this builder. + */ + public Builder other(String other) { + this.other = other; + return this; + } + + /** + * @return this builder. + */ + public Builder builderMember(BuilderShape builderMember) { + this.builderMember = builderMember; + return this; + } + + /** + * @return this builder. + */ + public Builder type(Type type) { + this.type = type; + return this; + } + + /** + * @return this builder. + */ + public Builder objectMember(ObjectShape objectMember) { + this.objectMember = objectMember; + return this; + } + + /** + * @return this builder. + */ + public Builder union(UnionWithTypeMember union) { + this.union = union; + return this; + } + + /** + * @return this builder. + */ + public Builder map(Map map) { + this.map = map; + return this; + } + + /** + * @return this builder. + */ + public Builder list(List list) { + this.list = list; + return this; + } + + /** + * @return this builder. + */ + public Builder listOfList(java.util.List listOfList) { + this.listOfList = listOfList; + return this; + } + + /** + * @return this builder. + */ + public Builder mapOfMap(java.util.Map mapOfMap) { + this.mapOfMap = mapOfMap; + return this; + } + + @Override + public NamingStruct build() { + return new NamingStruct(this); + } + + @Override + @SuppressWarnings("unchecked") + public void setMemberValue(Schema member, Object value) { + switch (member.memberIndex()) { + case 0 -> other((String) SchemaUtils.validateSameMember($SCHEMA_OTHER, member, value)); + case 1 -> builderMember((BuilderShape) SchemaUtils.validateSameMember($SCHEMA_BUILDER_MEMBER, member, value)); + case 2 -> type((Type) SchemaUtils.validateSameMember($SCHEMA_TYPE, member, value)); + case 3 -> objectMember((ObjectShape) SchemaUtils.validateSameMember($SCHEMA_OBJECT_MEMBER, member, value)); + case 4 -> union((UnionWithTypeMember) SchemaUtils.validateSameMember($SCHEMA_UNION, member, value)); + case 5 -> map((Map) SchemaUtils.validateSameMember($SCHEMA_MAP, member, value)); + case 6 -> list((List) SchemaUtils.validateSameMember($SCHEMA_LIST, member, value)); + case 7 -> listOfList((java.util.List) SchemaUtils.validateSameMember($SCHEMA_LIST_OF_LIST, member, value)); + case 8 -> mapOfMap((java.util.Map) SchemaUtils.validateSameMember($SCHEMA_MAP_OF_MAP, member, value)); + default -> ShapeBuilder.super.setMemberValue(member, value); + } + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) { + switch (member.memberIndex()) { + case 0 -> builder.other(de.readString(member)); + case 1 -> builder.builderMember(BuilderShape.builder().deserializeMember(de, member).build()); + case 2 -> builder.type(Type.builder().deserializeMember(de, member).build()); + case 3 -> builder.objectMember(ObjectShape.builder().deserializeMember(de, member).build()); + case 4 -> builder.union(UnionWithTypeMember.builder().deserializeMember(de, member).build()); + case 5 -> builder.map(Map.builder().deserializeMember(de, member).build()); + case 6 -> builder.list(List.builder().deserializeMember(de, member).build()); + case 7 -> builder.listOfList(SharedSerde.deserializeListOfList(member, de)); + case 8 -> builder.mapOfMap(SharedSerde.deserializeMapOfMap(member, de)); + default -> throw new IllegalArgumentException("Unexpected member: " + member.memberName()); + } + } + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/ObjectShape.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/ObjectShape.java new file mode 100644 index 000000000..bf7c8ad95 --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/ObjectShape.java @@ -0,0 +1,348 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SchemaUtils; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class ObjectShape implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.OBJECT; + private static final Schema $SCHEMA_CLASS_MEMBER = $SCHEMA.member("class"); + private static final Schema $SCHEMA_GET_CLASS_MEMBER = $SCHEMA.member("getClass"); + private static final Schema $SCHEMA_HASH_CODE_MEMBER = $SCHEMA.member("hashCode"); + private static final Schema $SCHEMA_CLONE_MEMBER = $SCHEMA.member("clone"); + private static final Schema $SCHEMA_TO_STRING_MEMBER = $SCHEMA.member("toString"); + private static final Schema $SCHEMA_NOTIFY_MEMBER = $SCHEMA.member("notify"); + private static final Schema $SCHEMA_NOTIFY_ALL_MEMBER = $SCHEMA.member("notifyAll"); + private static final Schema $SCHEMA_WAIT_MEMBER = $SCHEMA.member("wait"); + private static final Schema $SCHEMA_FINALIZE_MEMBER = $SCHEMA.member("finalize"); + + public static final ShapeId $ID = $SCHEMA.id(); + + private final transient String classMember; + private final transient String getClassMember; + private final transient String hashCodeMember; + private final transient String cloneMember; + private final transient String toStringMember; + private final transient String notifyMember; + private final transient String notifyAllMember; + private final transient String waitMember; + private final transient String finalizeMember; + + private ObjectShape(Builder builder) { + this.classMember = builder.classMember; + this.getClassMember = builder.getClassMember; + this.hashCodeMember = builder.hashCodeMember; + this.cloneMember = builder.cloneMember; + this.toStringMember = builder.toStringMember; + this.notifyMember = builder.notifyMember; + this.notifyAllMember = builder.notifyAllMember; + this.waitMember = builder.waitMember; + this.finalizeMember = builder.finalizeMember; + } + + public String getClassMember() { + return classMember; + } + + public String getGetClass() { + return getClassMember; + } + + public String getHashCode() { + return hashCodeMember; + } + + public String getClone() { + return cloneMember; + } + + public String getToString() { + return toStringMember; + } + + public String getNotify() { + return notifyMember; + } + + public String getNotifyAll() { + return notifyAllMember; + } + + public String getWait() { + return waitMember; + } + + public String getFinalize() { + return finalizeMember; + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + ObjectShape that = (ObjectShape) other; + return Objects.equals(this.classMember, that.classMember) + && Objects.equals(this.getClassMember, that.getClassMember) + && Objects.equals(this.hashCodeMember, that.hashCodeMember) + && Objects.equals(this.cloneMember, that.cloneMember) + && Objects.equals(this.toStringMember, that.toStringMember) + && Objects.equals(this.notifyMember, that.notifyMember) + && Objects.equals(this.notifyAllMember, that.notifyAllMember) + && Objects.equals(this.waitMember, that.waitMember) + && Objects.equals(this.finalizeMember, that.finalizeMember); + } + + @Override + public int hashCode() { + return Objects.hash(classMember, getClassMember, hashCodeMember, cloneMember, toStringMember, notifyMember, notifyAllMember, waitMember, finalizeMember); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + if (classMember != null) { + serializer.writeString($SCHEMA_CLASS_MEMBER, classMember); + } + if (getClassMember != null) { + serializer.writeString($SCHEMA_GET_CLASS_MEMBER, getClassMember); + } + if (hashCodeMember != null) { + serializer.writeString($SCHEMA_HASH_CODE_MEMBER, hashCodeMember); + } + if (cloneMember != null) { + serializer.writeString($SCHEMA_CLONE_MEMBER, cloneMember); + } + if (toStringMember != null) { + serializer.writeString($SCHEMA_TO_STRING_MEMBER, toStringMember); + } + if (notifyMember != null) { + serializer.writeString($SCHEMA_NOTIFY_MEMBER, notifyMember); + } + if (notifyAllMember != null) { + serializer.writeString($SCHEMA_NOTIFY_ALL_MEMBER, notifyAllMember); + } + if (waitMember != null) { + serializer.writeString($SCHEMA_WAIT_MEMBER, waitMember); + } + if (finalizeMember != null) { + serializer.writeString($SCHEMA_FINALIZE_MEMBER, finalizeMember); + } + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + return switch (member.memberIndex()) { + case 0 -> (T) SchemaUtils.validateSameMember($SCHEMA_CLASS_MEMBER, member, classMember); + case 1 -> (T) SchemaUtils.validateSameMember($SCHEMA_GET_CLASS_MEMBER, member, getClassMember); + case 2 -> (T) SchemaUtils.validateSameMember($SCHEMA_HASH_CODE_MEMBER, member, hashCodeMember); + case 3 -> (T) SchemaUtils.validateSameMember($SCHEMA_CLONE_MEMBER, member, cloneMember); + case 4 -> (T) SchemaUtils.validateSameMember($SCHEMA_TO_STRING_MEMBER, member, toStringMember); + case 5 -> (T) SchemaUtils.validateSameMember($SCHEMA_NOTIFY_MEMBER, member, notifyMember); + case 6 -> (T) SchemaUtils.validateSameMember($SCHEMA_NOTIFY_ALL_MEMBER, member, notifyAllMember); + case 7 -> (T) SchemaUtils.validateSameMember($SCHEMA_WAIT_MEMBER, member, waitMember); + case 8 -> (T) SchemaUtils.validateSameMember($SCHEMA_FINALIZE_MEMBER, member, finalizeMember); + default -> throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + }; + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link ObjectShape}. + */ + public Builder toBuilder() { + var builder = new Builder(); + builder.classMember(this.classMember); + builder.getClassMember(this.getClassMember); + builder.hashCodeMember(this.hashCodeMember); + builder.cloneMember(this.cloneMember); + builder.toStringMember(this.toStringMember); + builder.notifyMember(this.notifyMember); + builder.notifyAllMember(this.notifyAllMember); + builder.waitMember(this.waitMember); + builder.finalizeMember(this.finalizeMember); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link ObjectShape}. + */ + public static final class Builder implements ShapeBuilder { + private String classMember; + private String getClassMember; + private String hashCodeMember; + private String cloneMember; + private String toStringMember; + private String notifyMember; + private String notifyAllMember; + private String waitMember; + private String finalizeMember; + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + /** + * @return this builder. + */ + public Builder classMember(String classMember) { + this.classMember = classMember; + return this; + } + + /** + * @return this builder. + */ + public Builder getClassMember(String getClassMember) { + this.getClassMember = getClassMember; + return this; + } + + /** + * @return this builder. + */ + public Builder hashCodeMember(String hashCodeMember) { + this.hashCodeMember = hashCodeMember; + return this; + } + + /** + * @return this builder. + */ + public Builder cloneMember(String cloneMember) { + this.cloneMember = cloneMember; + return this; + } + + /** + * @return this builder. + */ + public Builder toStringMember(String toStringMember) { + this.toStringMember = toStringMember; + return this; + } + + /** + * @return this builder. + */ + public Builder notifyMember(String notifyMember) { + this.notifyMember = notifyMember; + return this; + } + + /** + * @return this builder. + */ + public Builder notifyAllMember(String notifyAllMember) { + this.notifyAllMember = notifyAllMember; + return this; + } + + /** + * @return this builder. + */ + public Builder waitMember(String waitMember) { + this.waitMember = waitMember; + return this; + } + + /** + * @return this builder. + */ + public Builder finalizeMember(String finalizeMember) { + this.finalizeMember = finalizeMember; + return this; + } + + @Override + public ObjectShape build() { + return new ObjectShape(this); + } + + @Override + @SuppressWarnings("unchecked") + public void setMemberValue(Schema member, Object value) { + switch (member.memberIndex()) { + case 0 -> classMember((String) SchemaUtils.validateSameMember($SCHEMA_CLASS_MEMBER, member, value)); + case 1 -> getClassMember((String) SchemaUtils.validateSameMember($SCHEMA_GET_CLASS_MEMBER, member, value)); + case 2 -> hashCodeMember((String) SchemaUtils.validateSameMember($SCHEMA_HASH_CODE_MEMBER, member, value)); + case 3 -> cloneMember((String) SchemaUtils.validateSameMember($SCHEMA_CLONE_MEMBER, member, value)); + case 4 -> toStringMember((String) SchemaUtils.validateSameMember($SCHEMA_TO_STRING_MEMBER, member, value)); + case 5 -> notifyMember((String) SchemaUtils.validateSameMember($SCHEMA_NOTIFY_MEMBER, member, value)); + case 6 -> notifyAllMember((String) SchemaUtils.validateSameMember($SCHEMA_NOTIFY_ALL_MEMBER, member, value)); + case 7 -> waitMember((String) SchemaUtils.validateSameMember($SCHEMA_WAIT_MEMBER, member, value)); + case 8 -> finalizeMember((String) SchemaUtils.validateSameMember($SCHEMA_FINALIZE_MEMBER, member, value)); + default -> ShapeBuilder.super.setMemberValue(member, value); + } + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) { + switch (member.memberIndex()) { + case 0 -> builder.classMember(de.readString(member)); + case 1 -> builder.getClassMember(de.readString(member)); + case 2 -> builder.hashCodeMember(de.readString(member)); + case 3 -> builder.cloneMember(de.readString(member)); + case 4 -> builder.toStringMember(de.readString(member)); + case 5 -> builder.notifyMember(de.readString(member)); + case 6 -> builder.notifyAllMember(de.readString(member)); + case 7 -> builder.waitMember(de.readString(member)); + case 8 -> builder.finalizeMember(de.readString(member)); + default -> throw new IllegalArgumentException("Unexpected member: " + member.memberName()); + } + } + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Type.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Type.java new file mode 100644 index 000000000..2d3600eff --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/Type.java @@ -0,0 +1,114 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 final class Type implements SerializableStruct { + + public static final Schema $SCHEMA = Schemas.TYPE; + + public static final ShapeId $ID = $SCHEMA.id(); + + private Type(Builder builder) { + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + return other != null && getClass() == other.getClass(); + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + + } + + @Override + @SuppressWarnings("unchecked") + public T getMemberValue(Schema member) { + throw new IllegalArgumentException("Attempted to get non-existent member: " + member.id()); + } + + /** + * Create a new builder containing all the current property values of this object. + * + *

Note: This method performs only a shallow copy of the original properties. + * + * @return a builder for {@link Type}. + */ + public Builder toBuilder() { + var builder = new Builder(); + return builder; + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link Type}. + */ + public static final class Builder implements ShapeBuilder { + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public Type build() { + return new Type(this); + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) {} + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/UnionWithTypeMember.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/UnionWithTypeMember.java new file mode 100644 index 000000000..0ff5b3d0b --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/expected/UnionWithTypeMember.java @@ -0,0 +1,212 @@ + +package software.amazon.smithy.java.example.standalone.model; + +import java.util.Objects; +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SchemaUtils; +import software.amazon.smithy.java.core.schema.SerializableStruct; +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 abstract class UnionWithTypeMember implements SerializableStruct { + public static final Schema $SCHEMA = Schemas.UNION_WITH_TYPE_MEMBER; + private static final Schema $SCHEMA_TYPE = $SCHEMA.member("type"); + + public static final ShapeId $ID = $SCHEMA.id(); + + private final Type type; + + private UnionWithTypeMember(Type type) { + this.type = type; + } + + public Type type() { + return type; + } + + /** + * Enum representing the possible variants of {@link UnionWithTypeMember}. + */ + public enum Type { + $UNKNOWN, + type + } + + @Override + public String toString() { + return ToStringSerializer.serialize(this); + } + + @Override + public Schema schema() { + return $SCHEMA; + } + + @Override + public T getMemberValue(Schema member) { + return SchemaUtils.validateMemberInSchema($SCHEMA, member, getValue()); + } + + public abstract T getValue(); + + @SmithyGenerated + public static final class TypeMember extends UnionWithTypeMember { + private final transient software.amazon.smithy.java.example.standalone.model.Type value; + + public TypeMember(software.amazon.smithy.java.example.standalone.model.Type value) { + super(Type.type); + this.value = Objects.requireNonNull(value, "Union value cannot be null"); + } + + @Override + public void serializeMembers(ShapeSerializer serializer) { + serializer.writeStruct($SCHEMA_TYPE, value); + } + + public software.amazon.smithy.java.example.standalone.model.Type getType() { + return value; + } + + @Override + @SuppressWarnings("unchecked") + public T getValue() { + return (T) value; + } + } + + public static final class $UnknownMember extends UnionWithTypeMember { + private final String memberName; + + public $UnknownMember(String memberName) { + super(Type.$UNKNOWN); + this.memberName = memberName; + } + + public String memberName() { + return memberName; + } + + @Override + public void serialize(ShapeSerializer serializer) { + throw new UnsupportedOperationException("Cannot serialize union with unknown member " + this.memberName); + } + + @Override + public void serializeMembers(ShapeSerializer serializer) {} + + @Override + @SuppressWarnings("unchecked") + public T getValue() { + return (T) memberName; + } + } + + @Override + public int hashCode() { + return Objects.hash(type, getValue()); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + return Objects.equals(getValue(), ((UnionWithTypeMember) other).getValue()); + } + + public interface BuildStage { + UnionWithTypeMember build(); + } + + /** + * @return returns a new Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link UnionWithTypeMember}. + */ + public static final class Builder implements ShapeBuilder, BuildStage { + private UnionWithTypeMember value; + + private Builder() {} + + @Override + public Schema schema() { + return $SCHEMA; + } + + public BuildStage type(software.amazon.smithy.java.example.standalone.model.Type value) { + return setValue(new TypeMember(value)); + } + + public BuildStage $unknownMember(String memberName) { + return setValue(new $UnknownMember(memberName)); + } + + private BuildStage setValue(UnionWithTypeMember value) { + if (this.value != null) { + if (this.value.type() == Type.$UNKNOWN) { + throw new IllegalArgumentException("Cannot change union from unknown to known variant"); + } + throw new IllegalArgumentException("Only one value may be set for unions"); + } + this.value = value; + return this; + } + + @Override + public UnionWithTypeMember build() { + return Objects.requireNonNull(value, "no union value set"); + } + + @Override + @SuppressWarnings("unchecked") + public void setMemberValue(Schema member, Object value) { + switch (member.memberIndex()) { + case 0 -> type((software.amazon.smithy.java.example.standalone.model.Type) SchemaUtils.validateSameMember($SCHEMA_TYPE, member, value)); + default -> ShapeBuilder.super.setMemberValue(member, value); + } + } + + @Override + public Builder deserialize(ShapeDeserializer decoder) { + decoder.readStruct($SCHEMA, this, $InnerDeserializer.INSTANCE); + return this; + } + + @Override + public Builder deserializeMember(ShapeDeserializer decoder, Schema schema) { + decoder.readStruct(schema.assertMemberTargetIs($SCHEMA), this, $InnerDeserializer.INSTANCE); + return this; + } + + private static final class $InnerDeserializer implements ShapeDeserializer.StructMemberConsumer { + private static final $InnerDeserializer INSTANCE = new $InnerDeserializer(); + + @Override + public void accept(Builder builder, Schema member, ShapeDeserializer de) { + switch (member.memberIndex()) { + case 0 -> builder.type(software.amazon.smithy.java.example.standalone.model.Type.builder().deserializeMember(de, member).build()); + default -> throw new IllegalArgumentException("Unexpected member: " + member.memberName()); + } + } + + @Override + public void unknownMember(Builder builder, String memberName) { + builder.$unknownMember(memberName); + } + } + } +} + diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/model/main.smithy b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/model/main.smithy new file mode 100644 index 000000000..a0f2d83ad --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/model/main.smithy @@ -0,0 +1,57 @@ +$version: "2" + +namespace smithy.java.codegen.types.naming + +structure NamingStruct { + // Collides with `other` in equals + other: String + + builder: Builder + + type: Type + + object: Object + + union: UnionWithTypeMember + + map: Map + + list: List + + listOfList: ListOfList + + mapOfMap: MapOfMap +} + +list ListOfList{ + member:List +} + +map MapOfMap { + key: String + value: Map +} + +structure Builder {} + +structure Type {} + +structure Object { + class: String + getClass: String + hashCode: String + clone: String + toString: String + notify: String + notifyAll: String + wait: String + finalize: String +} + +union UnionWithTypeMember { + type: Type +} + +structure Map {} + +structure List {} diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/smithy-build.json b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/smithy-build.json new file mode 100644 index 000000000..18f2e820d --- /dev/null +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/naming-conflict/smithy-build.json @@ -0,0 +1,8 @@ +{ + "version": "1.0", + "plugins": { + "java-type-codegen": { + "namespace": "software.amazon.smithy.java.example.standalone" + } + } +} diff --git a/examples/end-to-end/src/main/java/software/amazon/smithy/java/server/example/GetMenu.java b/examples/end-to-end/src/main/java/software/amazon/smithy/java/server/example/GetMenu.java index 40b054caa..2f30670b9 100644 --- a/examples/end-to-end/src/main/java/software/amazon/smithy/java/server/example/GetMenu.java +++ b/examples/end-to-end/src/main/java/software/amazon/smithy/java/server/example/GetMenu.java @@ -19,7 +19,7 @@ final class GetMenu implements GetMenuOperation { private static final List MENU = List.of( CoffeeItem.builder() - .typeMember(CoffeeType.DRIP) + .type(CoffeeType.DRIP) .description(""" A clean-bodied, rounder, and more simplistic flavour profile. Often praised for mellow and less intense notes. @@ -27,14 +27,14 @@ final class GetMenu implements GetMenuOperation { """) .build(), CoffeeItem.builder() - .typeMember(CoffeeType.POUR_OVER) + .type(CoffeeType.POUR_OVER) .description(""" Similar to drip coffee, but with a process that brings out more subtle nuances in flavor. More concentrated than drip, but less than espresso. """) .build(), CoffeeItem.builder() - .typeMember(CoffeeType.LATTE) + .type(CoffeeType.LATTE) .description(""" A creamier, milk-based drink made with espresso. A subtle coffee taste, with smooth texture. @@ -42,7 +42,7 @@ final class GetMenu implements GetMenuOperation { """) .build(), CoffeeItem.builder() - .typeMember(CoffeeType.ESPRESSO) + .type(CoffeeType.ESPRESSO) .description(""" A highly concentrated form of coffee, brewed under high pressure. Syrupy, thick liquid in a small serving size. diff --git a/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpService.java b/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpService.java index ca76157d0..c69d31573 100644 --- a/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpService.java +++ b/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/McpService.java @@ -466,7 +466,7 @@ private static JsonPrimitiveSchema createJsonPrimitiveSchema(Schema member) { }; return JsonPrimitiveSchema.builder() - .typeMember(type) + .type(type) .description(memberDescription(member)) .build(); } diff --git a/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/PromptProcessor.java b/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/PromptProcessor.java index 5cecfe95c..a0c28baac 100644 --- a/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/PromptProcessor.java +++ b/mcp/mcp-server/src/main/java/software/amazon/smithy/java/mcp/server/PromptProcessor.java @@ -46,7 +46,7 @@ public GetPromptResult buildPromptResult(Prompt prompt, Document arguments) { PromptMessage.builder() .role(PromptRole.ASSISTANT.getValue()) .content(PromptMessageContent.builder() - .typeMember(PromptMessageContentType.TEXT) + .type(PromptMessageContentType.TEXT) .text("Template is required for the prompt:" + prompt.promptInfo().getName()) .build()) @@ -62,7 +62,7 @@ public GetPromptResult buildPromptResult(Prompt prompt, Document arguments) { .messages(List.of(PromptMessage.builder() .role(PromptRole.USER.getValue()) .content(PromptMessageContent.builder() - .typeMember(PromptMessageContentType.TEXT) + .type(PromptMessageContentType.TEXT) .text("Tell user that there are missing arguments for the prompt : " + requiredArguments) .build()) @@ -78,7 +78,7 @@ public GetPromptResult buildPromptResult(Prompt prompt, Document arguments) { PromptMessage.builder() .role(PromptRole.USER.getValue()) .content(PromptMessageContent.builder() - .typeMember(PromptMessageContentType.TEXT) + .type(PromptMessageContentType.TEXT) .text(processedText) .build()) .build()))