diff --git a/.chronus/changes/fix-java-duplicate-discriminators-2026-09-02.md b/.chronus/changes/fix-java-duplicate-discriminators-2026-09-02.md new file mode 100644 index 00000000000..6acbebea6c0 --- /dev/null +++ b/.chronus/changes/fix-java-duplicate-discriminators-2026-09-02.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-java" +--- + +Prevent duplicate Java discriminator members while preserving inherited discriminators in stream-style XML serialization. diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/GoblinShark.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/GoblinShark.java index 9a1a50089f8..f99fea4f3fd 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/GoblinShark.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/GoblinShark.java @@ -16,7 +16,7 @@ public final class GoblinShark extends Shark { * Discriminator property for Fish. */ @Metadata(properties = { MetadataProperties.GENERATED }) - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/SawShark.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/SawShark.java index e98a415de70..41df495e8c2 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/SawShark.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/SawShark.java @@ -16,7 +16,7 @@ public final class SawShark extends Shark { * Discriminator property for Fish. */ @Metadata(properties = { MetadataProperties.GENERATED }) - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/Shark.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/Shark.java index 55e73652485..6b42d9c1ccb 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/Shark.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/type/model/inheritance/nesteddiscriminator/Shark.java @@ -16,7 +16,7 @@ public class Shark extends Fish { * Discriminator property for Fish. */ @Metadata(properties = { MetadataProperties.GENERATED }) - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/ClientModelPropertiesManager.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/ClientModelPropertiesManager.java index 4f29e64c65e..2278c272192 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/ClientModelPropertiesManager.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/ClientModelPropertiesManager.java @@ -22,6 +22,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Manages metadata about properties in a {@link ClientModel} and how they correlate with model class generation. @@ -124,10 +125,13 @@ public ClientModelPropertiesManager(ClientModel model, JavaSettings settings) { xmlRootElementNamespace = model.getXmlNamespace(); } - Set thisModelPropertySerializeNames = model.getProperties() - .stream() + Set thisModelPropertySerializeNames = Stream.concat( // discriminator property is known to be redefined in subclass - .filter(property -> !property.isPolymorphicDiscriminator()) + model.getProperties().stream().filter(property -> !property.isPolymorphicDiscriminator()), + // For example, after a child's fixed "type" property is removed from model.getProperties(), the fixed + // "type" entry in model.getParentPolymorphicDiscriminators() is included here so the inherited parent + // "type" property is masked. Otherwise, the generated child has two "type" members. + model.getParentPolymorphicDiscriminators().stream()) .map(ClientModelProperty::getSerializedName) .filter(name -> Objects.nonNull(name) && !name.isEmpty()) .collect(Collectors.toSet()); diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/PolymorphicDiscriminatorHandler.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/PolymorphicDiscriminatorHandler.java index 7f212bafd50..3be6e0e3102 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/PolymorphicDiscriminatorHandler.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/implementation/PolymorphicDiscriminatorHandler.java @@ -12,6 +12,7 @@ import com.microsoft.typespec.http.client.generator.core.model.javamodel.JavaFile; import com.microsoft.typespec.http.client.generator.core.model.javamodel.JavaVisibility; import com.microsoft.typespec.http.client.generator.core.util.ClientModelUtil; +import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; @@ -116,7 +117,13 @@ private static void declareFieldInternal(ClientModelProperty discriminator, Clie && settings.isShareJsonSerializableCode()) { classBlock.memberVariable(JavaVisibility.PackagePrivate, fieldSignature); } else if (!allPolymorphicModelsInSamePackage || !settings.isShareJsonSerializableCode()) { - classBlock.privateMemberVariable(fieldSignature); + // Active discriminators stay mutable to preserve unknown values during fallback deserialization. + if (discriminator.isConstant() + && !Objects.equals(discriminator.getSerializedName(), model.getPolymorphicDiscriminatorName())) { + classBlock.privateFinalMemberVariable(fieldSignature); + } else { + classBlock.privateMemberVariable(fieldSignature); + } } } } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/mapper/ModelMapper.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/mapper/ModelMapper.java index 068a9e19d6a..21d26276009 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/mapper/ModelMapper.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/mapper/ModelMapper.java @@ -363,11 +363,13 @@ public ClientModel map(ObjectSchema compositeType) { // the correct serialization in multi-level polymorphic structures. for (ClientModel derivedType : derivedTypes) { if (!Objects.equals(polymorphicDiscriminator, derivedType.getPolymorphicDiscriminatorName())) { + // The child hierarchy stays in one fixed parent discriminator branch. ClientModelProperty parentDiscriminator = result.getPolymorphicDiscriminator() .newBuilder() .defaultValue(result.getPolymorphicDiscriminator() .getClientType() .defaultValueExpression(derivedType.getSerializedName())) + .constant(true) .build(); passPolymorphicDiscriminatorToChildren(parentDiscriminator, derivedType); @@ -383,13 +385,47 @@ public ClientModel map(ObjectSchema compositeType) { private static void passPolymorphicDiscriminatorToChildren(ClientModelProperty parentDiscriminator, ClientModel child) { - // Due to the execution order of ModelMapper, where children models complete mapping before the parent model, - // the parent polymorphic discriminator needs to be added at index 0. Reason, given an example where there are - // three models, where model #1 is the root parent with discriminator type, model #2 is a child of model #2 with - // discriminator kind, and model #3 is a child of model #3 with discriminator form. The order if this running - // will have model #2 add its discriminator to model #3 before model #1 runs adding its discriminator to #2 and - // #3. We want #3 to have the ordering of [type, kind], to represent the ordering of the parent models. - child.getParentPolymorphicDiscriminators().add(0, parentDiscriminator); + // A child that introduces a different discriminator still needs the fixed discriminator value selected by the + // parent hierarchy. For example, a parent may discriminate on "type", while a child fixes type="message" and + // discriminates its children on "role". The child branch must retain type="message" while dispatching by + // "role". + // + // If child.getProperties() contains a fixed property with the same serialized name and value as + // parentDiscriminator, use the matching property to build the parent discriminator entry. Then remove the + // matching property from child.getProperties() so the generated model does not contain "type" as both a normal + // property and a parent discriminator. + ClientModelProperty discriminatorForChild = parentDiscriminator; + for (int i = 0; i < child.getProperties().size(); i++) { + ClientModelProperty childProperty = child.getProperties().get(i); + if (!Objects.equals(parentDiscriminator.getSerializedName(), childProperty.getSerializedName())) { + continue; + } + + if (!childProperty.isConstant() + || !Objects.equals(parentDiscriminator.getWireType(), childProperty.getWireType()) + || !Objects.equals(parentDiscriminator.getClientType(), childProperty.getClientType()) + || !Objects.equals(parentDiscriminator.getDefaultValue(), childProperty.getDefaultValue())) { + throw new IllegalStateException("Property '" + childProperty.getSerializedName() + "' on model '" + + child.getName() + "' does not match its inherited polymorphic discriminator. Expected (type=" + + parentDiscriminator.getClientType() + ", value=" + + String.valueOf(parentDiscriminator.getDefaultValue()) + "), but found (type=" + + childProperty.getClientType() + ", value=" + String.valueOf(childProperty.getDefaultValue()) + + ")."); + } + + discriminatorForChild = childProperty.newBuilder() + .name(parentDiscriminator.getName()) + .readOnly(true) + .required(false) + .polymorphicDiscriminator(true) + .build(); + child.getProperties().remove(i); + break; + } + + // Children are mapped before their parents, so insert at index 0 to preserve outer-to-inner discriminator + // order. + child.getParentPolymorphicDiscriminators().add(0, discriminatorForChild); for (ClientModel derived : child.getDerivedModels()) { passPolymorphicDiscriminatorToChildren(parentDiscriminator, derived); diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTemplate.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTemplate.java index 69dac758321..59b1f2527f9 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTemplate.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTemplate.java @@ -886,18 +886,18 @@ private void addModelConstructor(ClientModel model, ClientModelPropertiesManager * * we use the property in this model to initiate the superclass */ - ClientModelProperty propertyInThisModel = model.getProperties() - .stream() + ClientModelProperty overridingProperty = Stream + .concat(model.getProperties().stream(), model.getParentPolymorphicDiscriminators().stream()) .filter(p -> Objects.equals(p.getSerializedName(), property.getSerializedName())) .findFirst() .orElse(null); - if (propertyInThisModel != null) { - if (propertyInThisModel.isConstant() && !property.isConstant()) { + if (overridingProperty != null) { + if (overridingProperty.isConstant() && !property.isConstant()) { // property changed to constant in this model, use constant value to initiate super // class - superProperties.append(propertyInThisModel.getDefaultValue()); + superProperties.append(overridingProperty.getDefaultValue()); } else { - superProperties.append(propertyInThisModel.getName()); + superProperties.append(overridingProperty.getName()); } } else { // this should not happen diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java index 49f72130dcc..e30051536ab 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java @@ -2059,8 +2059,16 @@ private void writeToXml(JavaClass classBlock) { + propertiesManager.getXmlNamespaceConstant(namespace) + ");")); // Assumption for XML is polymorphic discriminators are attributes. - if (propertiesManager.getDiscriminatorProperty() != null) { - serializeXml(methodBlock, propertiesManager.getDiscriminatorProperty().getProperty(), false); + ClientModelPropertyWithMetadata discriminatorProperty + = propertiesManager.getDiscriminatorProperty(); + model.getParentPolymorphicDiscriminators() + .stream() + .filter(discriminator -> discriminatorProperty == null + || !Objects.equals(discriminator.getSerializedName(), + discriminatorProperty.getProperty().getSerializedName())) + .forEach(discriminator -> serializeXml(methodBlock, discriminator, false)); + if (discriminatorProperty != null) { + serializeXml(methodBlock, discriminatorProperty.getProperty(), false); } propertiesManager.forEachSuperXmlAttribute(property -> serializeXml(methodBlock, property, true)); @@ -2214,7 +2222,7 @@ private void writeSuperTypeFromXml(JavaClass classBlock) { + propertiesManager.getXmlNamespaceConstant(discriminatorProperty.getXmlNamespace()) + ", " + "\"" + discriminatorProperty.getSerializedName() + "\");"); } else { - methodBlock.line("String discriminatorValue = reader.getStringAttribute(" + "\"" + methodBlock.line("String discriminatorValue = reader.getStringAttribute(null, " + "\"" + discriminatorProperty.getSerializedName() + "\");"); } @@ -2226,12 +2234,18 @@ private void writeSuperTypeFromXml(JavaClass classBlock) { // Add deserialization for all child types. List childTypes = getAllChildTypes(model, new ArrayList<>()); for (ClientModel childType : childTypes) { + boolean sameDiscriminator = Objects.equals(childType.getPolymorphicDiscriminatorName(), + model.getPolymorphicDiscriminatorName()); + if (!sameDiscriminator && !Objects.equals(childType.getParentModelName(), model.getName())) { + continue; + } + + String deserializationMethod = (isSuperTypeWithDiscriminator(childType) && sameDiscriminator) + ? ".fromXmlInternal(reader, finalRootElementName)" + : ".fromXml(reader, finalRootElementName)"; ifBlock = ifOrElseIf(methodBlock, ifBlock, "\"" + childType.getSerializedName() + "\".equals(discriminatorValue)", - ifStatement -> ifStatement - .methodReturn(childType.getName() + (isSuperTypeWithDiscriminator(childType) - ? ".fromXmlInternal(reader, finalRootElementName)" - : ".fromXml(reader, finalRootElementName)"))); + ifStatement -> ifStatement.methodReturn(childType.getName() + deserializationMethod)); } if (ifBlock == null) { @@ -2439,6 +2453,10 @@ private void writeFromXmlDeserialization(JavaBlock methodBlock) { } private void deserializeXmlAttribute(JavaBlock methodBlock, ClientModelProperty attribute, boolean fromSuper) { + if (attribute.isRequired() && attribute.isConstant() && !attribute.isPolymorphicDiscriminator()) { + return; + } + String xmlAttributeDeserialization = getSimpleXmlDeserialization(attribute.getWireType(), null, attribute.getXmlName(), propertiesManager.getXmlNamespaceConstant(attribute.getXmlNamespace()), true); diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/GoblinShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/GoblinShark.java index e1645e48e6d..a5e522627f7 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/GoblinShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/GoblinShark.java @@ -21,7 +21,7 @@ public final class GoblinShark extends Shark { /* * Discriminator property for Fish. */ - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/SawShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/SawShark.java index 49590e9c112..f5231b952cc 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/SawShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/SawShark.java @@ -21,7 +21,7 @@ public final class SawShark extends Shark { /* * Discriminator property for Fish. */ - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/Shark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/Shark.java index 556d445d45b..4a970c53a8e 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/Shark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/Shark.java @@ -22,7 +22,7 @@ public class Shark extends FishInner { /* * Discriminator property for Fish. */ - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java index e0b4fb1f882..da52b57562c 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java @@ -103,6 +103,8 @@ public static ChildWithRequiredPropertyAsDiscriminator fromJson(JsonReader jsonR // Use the discriminator value to determine which subtype should be deserialized. if ("aValue".equals(discriminatorValue)) { return GrandChildWithRequiredProperty.fromJson(readerToUse.reset()); + } else if ("nested".equals(discriminatorValue)) { + return GrandChildWithNestedDiscriminator.fromJson(readerToUse.reset()); } else { return fromJsonKnownDiscriminator(readerToUse.reset()); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithNestedDiscriminator.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithNestedDiscriminator.java new file mode 100644 index 00000000000..c023265b5e6 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithNestedDiscriminator.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.discriminatoredgecases.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The GrandChildWithNestedDiscriminator model. + */ +@Immutable +public class GrandChildWithNestedDiscriminator extends ChildWithRequiredPropertyAsDiscriminator { + /* + * Discriminator property for ChildWithRequiredPropertyAsDiscriminator. + */ + @Generated + private final String discriminator = "nested"; + + /* + * The nestedDiscriminator property. + */ + @Generated + private String nestedDiscriminator = "nested"; + + /** + * Creates an instance of GrandChildWithNestedDiscriminator class. + * + * @param aProperty the aProperty value to set. + * @param anotherProperty the anotherProperty value to set. + */ + @Generated + protected GrandChildWithNestedDiscriminator(String aProperty, String anotherProperty) { + super("nested", aProperty, anotherProperty); + } + + /** + * Get the discriminator property: Discriminator property for ChildWithRequiredPropertyAsDiscriminator. + * + * @return the discriminator value. + */ + @Generated + @Override + public String getDiscriminator() { + return this.discriminator; + } + + /** + * Get the nestedDiscriminator property: The nestedDiscriminator property. + * + * @return the nestedDiscriminator value. + */ + @Generated + public String getNestedDiscriminator() { + return this.nestedDiscriminator; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("discriminator", this.discriminator); + jsonWriter.writeStringField("aProperty", getAProperty()); + jsonWriter.writeStringField("anotherProperty", getAnotherProperty()); + jsonWriter.writeStringField("nestedDiscriminator", this.nestedDiscriminator); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of GrandChildWithNestedDiscriminator from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of GrandChildWithNestedDiscriminator if the JsonReader was pointing to an instance of it, or + * null if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the GrandChildWithNestedDiscriminator. + */ + @Generated + public static GrandChildWithNestedDiscriminator fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String discriminatorValue = null; + try (JsonReader readerToUse = reader.bufferObject()) { + readerToUse.nextToken(); // Prepare for reading + while (readerToUse.nextToken() != JsonToken.END_OBJECT) { + String fieldName = readerToUse.getFieldName(); + readerToUse.nextToken(); + if ("nestedDiscriminator".equals(fieldName)) { + discriminatorValue = readerToUse.getString(); + break; + } else { + readerToUse.skipChildren(); + } + } + // Use the discriminator value to determine which subtype should be deserialized. + if ("leaf".equals(discriminatorValue)) { + return GreatGrandChildWithDuplicateDiscriminator.fromJson(readerToUse.reset()); + } else { + return fromJsonKnownDiscriminator(readerToUse.reset()); + } + } + }); + } + + @Generated + static GrandChildWithNestedDiscriminator fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String aProperty = null; + String anotherProperty = null; + String nestedDiscriminator = "nested"; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("aProperty".equals(fieldName)) { + aProperty = reader.getString(); + } else if ("anotherProperty".equals(fieldName)) { + anotherProperty = reader.getString(); + } else if ("nestedDiscriminator".equals(fieldName)) { + nestedDiscriminator = reader.getString(); + } else { + reader.skipChildren(); + } + } + GrandChildWithNestedDiscriminator deserializedGrandChildWithNestedDiscriminator + = new GrandChildWithNestedDiscriminator(aProperty, anotherProperty); + deserializedGrandChildWithNestedDiscriminator.nestedDiscriminator = nestedDiscriminator; + + return deserializedGrandChildWithNestedDiscriminator; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GreatGrandChildWithDuplicateDiscriminator.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GreatGrandChildWithDuplicateDiscriminator.java new file mode 100644 index 00000000000..fcf9aff8124 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/GreatGrandChildWithDuplicateDiscriminator.java @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.discriminatoredgecases.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The GreatGrandChildWithDuplicateDiscriminator model. + */ +@Immutable +public final class GreatGrandChildWithDuplicateDiscriminator extends GrandChildWithNestedDiscriminator { + /* + * The discriminator property. + */ + @Generated + private final String discriminator = "nested"; + + /* + * The nestedDiscriminator property. + */ + @Generated + private String nestedDiscriminator = "leaf"; + + /** + * Creates an instance of GreatGrandChildWithDuplicateDiscriminator class. + * + * @param aProperty the aProperty value to set. + * @param anotherProperty the anotherProperty value to set. + */ + @Generated + private GreatGrandChildWithDuplicateDiscriminator(String aProperty, String anotherProperty) { + super(aProperty, anotherProperty); + } + + /** + * Get the discriminator property: The discriminator property. + * + * @return the discriminator value. + */ + @Generated + @Override + public String getDiscriminator() { + return this.discriminator; + } + + /** + * Get the nestedDiscriminator property: The nestedDiscriminator property. + * + * @return the nestedDiscriminator value. + */ + @Generated + @Override + public String getNestedDiscriminator() { + return this.nestedDiscriminator; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("discriminator", this.discriminator); + jsonWriter.writeStringField("aProperty", getAProperty()); + jsonWriter.writeStringField("anotherProperty", getAnotherProperty()); + jsonWriter.writeStringField("nestedDiscriminator", this.nestedDiscriminator); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of GreatGrandChildWithDuplicateDiscriminator from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of GreatGrandChildWithDuplicateDiscriminator if the JsonReader was pointing to an instance of + * it, or null if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the GreatGrandChildWithDuplicateDiscriminator. + */ + @Generated + public static GreatGrandChildWithDuplicateDiscriminator fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String aProperty = null; + String anotherProperty = null; + String nestedDiscriminator = "leaf"; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("aProperty".equals(fieldName)) { + aProperty = reader.getString(); + } else if ("anotherProperty".equals(fieldName)) { + anotherProperty = reader.getString(); + } else if ("nestedDiscriminator".equals(fieldName)) { + nestedDiscriminator = reader.getString(); + } else { + reader.skipChildren(); + } + } + GreatGrandChildWithDuplicateDiscriminator deserializedGreatGrandChildWithDuplicateDiscriminator + = new GreatGrandChildWithDuplicateDiscriminator(aProperty, anotherProperty); + deserializedGreatGrandChildWithDuplicateDiscriminator.nestedDiscriminator = nestedDiscriminator; + + return deserializedGreatGrandChildWithDuplicateDiscriminator; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorAssistant.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorAssistant.java new file mode 100644 index 00000000000..78ab5dba285 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorAssistant.java @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.discriminatoredgecases.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.stream.XMLStreamException; + +/** + * The NestedDiscriminatorAssistant model. + */ +@Immutable +public final class NestedDiscriminatorAssistant extends NestedDiscriminatorMessage { + /* + * The type property. + */ + @Generated + private final String type = "message"; + + /* + * The role property. + */ + @Generated + private String role = "assistant"; + + /** + * Creates an instance of NestedDiscriminatorAssistant class. + */ + @Generated + private NestedDiscriminatorAssistant() { + } + + /** + * Get the type property: The type property. + * + * @return the type value. + */ + @Generated + @Override + public String getType() { + return this.type; + } + + /** + * Get the role property: The role property. + * + * @return the role value. + */ + @Generated + @Override + public String getRole() { + return this.role; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeStringAttribute("type", this.type); + xmlWriter.writeStringAttribute("role", this.role); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of NestedDiscriminatorAssistant from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of NestedDiscriminatorAssistant if the XmlReader was pointing to an instance of it, or null + * if it was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorAssistant. + */ + @Generated + public static NestedDiscriminatorAssistant fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of NestedDiscriminatorAssistant from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of NestedDiscriminatorAssistant if the XmlReader was pointing to an instance of it, or null + * if it was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorAssistant. + */ + @Generated + public static NestedDiscriminatorAssistant fromXml(XmlReader xmlReader, String rootElementName) + throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + NestedDiscriminatorAssistant deserializedNestedDiscriminatorAssistant = new NestedDiscriminatorAssistant(); + String discriminatorValue = reader.getStringAttribute(null, "role"); + if (!"assistant".equals(discriminatorValue)) { + throw new IllegalStateException( + "'role' was expected to be non-null and equal to 'assistant'. The found 'role' was '" + + discriminatorValue + "'."); + } + deserializedNestedDiscriminatorAssistant.role = discriminatorValue; + while (reader.nextElement() != XmlToken.END_ELEMENT) { + reader.skipElement(); + } + + return deserializedNestedDiscriminatorAssistant; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorBase.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorBase.java new file mode 100644 index 00000000000..62bc785739a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorBase.java @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.discriminatoredgecases.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlSerializable; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.stream.XMLStreamException; + +/** + * The NestedDiscriminatorBase model. + */ +@Immutable +public class NestedDiscriminatorBase implements XmlSerializable { + /* + * The type property. + */ + @Generated + private String type = "NestedDiscriminatorBase"; + + /** + * Creates an instance of NestedDiscriminatorBase class. + */ + @Generated + protected NestedDiscriminatorBase() { + } + + /** + * Get the type property: The type property. + * + * @return the type value. + */ + @Generated + public String getType() { + return this.type; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeStringAttribute("type", this.type); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of NestedDiscriminatorBase from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of NestedDiscriminatorBase if the XmlReader was pointing to an instance of it, or null if it + * was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorBase. + */ + @Generated + public static NestedDiscriminatorBase fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of NestedDiscriminatorBase from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of NestedDiscriminatorBase if the XmlReader was pointing to an instance of it, or null if it + * was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorBase. + */ + @Generated + public static NestedDiscriminatorBase fromXml(XmlReader xmlReader, String rootElementName) + throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + // Get the XML discriminator attribute. + String discriminatorValue = reader.getStringAttribute(null, "type"); + // Use the discriminator value to determine which subtype should be deserialized. + if ("message".equals(discriminatorValue)) { + return NestedDiscriminatorMessage.fromXml(reader, finalRootElementName); + } else { + return fromXmlInternal(reader, finalRootElementName); + } + }); + } + + @Generated + static NestedDiscriminatorBase fromXmlInternal(XmlReader xmlReader, String rootElementName) + throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + NestedDiscriminatorBase deserializedNestedDiscriminatorBase = new NestedDiscriminatorBase(); + deserializedNestedDiscriminatorBase.type = reader.getStringAttribute(null, "type"); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + reader.skipElement(); + } + + return deserializedNestedDiscriminatorBase; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorMessage.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorMessage.java new file mode 100644 index 00000000000..7a44887afaa --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorMessage.java @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.discriminatoredgecases.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.xml.XmlReader; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; +import javax.xml.stream.XMLStreamException; + +/** + * The NestedDiscriminatorMessage model. + */ +@Immutable +public class NestedDiscriminatorMessage extends NestedDiscriminatorBase { + /* + * The type property. + */ + @Generated + private final String type = "message"; + + /* + * The role property. + */ + @Generated + private String role = "message"; + + /** + * Creates an instance of NestedDiscriminatorMessage class. + */ + @Generated + protected NestedDiscriminatorMessage() { + } + + /** + * Get the type property: The type property. + * + * @return the type value. + */ + @Generated + @Override + public String getType() { + return this.type; + } + + /** + * Get the role property: The role property. + * + * @return the role value. + */ + @Generated + public String getRole() { + return this.role; + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException { + return toXml(xmlWriter, null); + } + + @Generated + @Override + public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException { + rootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + xmlWriter.writeStartElement(rootElementName); + xmlWriter.writeStringAttribute("type", this.type); + xmlWriter.writeStringAttribute("role", this.role); + return xmlWriter.writeEndElement(); + } + + /** + * Reads an instance of NestedDiscriminatorMessage from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @return An instance of NestedDiscriminatorMessage if the XmlReader was pointing to an instance of it, or null if + * it was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorMessage. + */ + @Generated + public static NestedDiscriminatorMessage fromXml(XmlReader xmlReader) throws XMLStreamException { + return fromXml(xmlReader, null); + } + + /** + * Reads an instance of NestedDiscriminatorMessage from the XmlReader. + * + * @param xmlReader The XmlReader being read. + * @param rootElementName Optional root element name to override the default defined by the model. Used to support + * cases where the model can deserialize from different root element names. + * @return An instance of NestedDiscriminatorMessage if the XmlReader was pointing to an instance of it, or null if + * it was pointing to XML null. + * @throws IllegalStateException If the deserialized XML object has an invalid polymorphic discriminator value. + * @throws XMLStreamException If an error occurs while reading the NestedDiscriminatorMessage. + */ + @Generated + public static NestedDiscriminatorMessage fromXml(XmlReader xmlReader, String rootElementName) + throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + // Get the XML discriminator attribute. + String discriminatorValue = reader.getStringAttribute(null, "role"); + // Use the discriminator value to determine which subtype should be deserialized. + if ("assistant".equals(discriminatorValue)) { + return NestedDiscriminatorAssistant.fromXml(reader, finalRootElementName); + } else { + return fromXmlInternal(reader, finalRootElementName); + } + }); + } + + @Generated + static NestedDiscriminatorMessage fromXmlInternal(XmlReader xmlReader, String rootElementName) + throws XMLStreamException { + String finalRootElementName + = rootElementName == null || rootElementName.isEmpty() ? "NestedDiscriminatorBase" : rootElementName; + return xmlReader.readObject(finalRootElementName, reader -> { + NestedDiscriminatorMessage deserializedNestedDiscriminatorMessage = new NestedDiscriminatorMessage(); + deserializedNestedDiscriminatorMessage.role = reader.getStringAttribute(null, "role"); + while (reader.nextElement() != XmlToken.END_ELEMENT) { + reader.skipElement(); + } + + return deserializedNestedDiscriminatorMessage; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/GoblinShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/GoblinShark.java index 323da63dc43..47d04cfc429 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/GoblinShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/GoblinShark.java @@ -20,7 +20,7 @@ public final class GoblinShark extends Shark { * discriminator property */ @Generated - private FishKind kind = FishKind.SHARK; + private final FishKind kind = FishKind.SHARK; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/SawShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/SawShark.java index f8225d9fc6e..73bd60c3712 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/SawShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/SawShark.java @@ -20,7 +20,7 @@ public final class SawShark extends Shark { * discriminator property */ @Generated - private FishKind kind = FishKind.SHARK; + private final FishKind kind = FishKind.SHARK; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/Shark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/Shark.java index f149c82c31b..2c611473348 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/Shark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/enumnesteddiscriminator/models/Shark.java @@ -20,7 +20,7 @@ public class Shark extends Fish { * discriminator property */ @Generated - private FishKind kind = FishKind.SHARK; + private final FishKind kind = FishKind.SHARK; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/SawShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/SawShark.java index 55a2e636f98..8188419c604 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/SawShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/SawShark.java @@ -23,7 +23,7 @@ public final class SawShark extends Shark { * Discriminator property for Fish. */ @Generated - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/Shark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/Shark.java index 65ce4de7ffc..1a7926bc2a5 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/Shark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/patch/models/Shark.java @@ -23,7 +23,7 @@ public class Shark extends Fish { * Discriminator property for Fish. */ @Generated - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java index c852ed3cb50..a17b47eb4f8 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java @@ -20,7 +20,7 @@ public final class GoblinShark extends Shark { * Discriminator property for Fish. */ @Generated - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/SawShark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/SawShark.java index a1f4a21c76d..ddf9f42ab29 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/SawShark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/SawShark.java @@ -20,7 +20,7 @@ public final class SawShark extends Shark { * Discriminator property for Fish. */ @Generated - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/Shark.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/Shark.java index 3b9f02f8e18..964024ad7c8 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/Shark.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/type/model/inheritance/nesteddiscriminator/models/Shark.java @@ -20,7 +20,7 @@ public class Shark extends Fish { * Discriminator property for Fish. */ @Generated - private String kind = "shark"; + private final String kind = "shark"; /* * The sharktype property. diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/tsptest-discriminatoredgecases_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/tsptest-discriminatoredgecases_metadata.json index 21ae133f1dc..4f0daf02fcc 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/tsptest-discriminatoredgecases_metadata.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/tsptest-discriminatoredgecases_metadata.json @@ -1 +1 @@ -{"flavor":"Azure","apiVersions":{},"crossLanguagePackageId":"TspTest.DiscriminatorEdgeCases","crossLanguageVersion":"c89ca21b286d","crossLanguageDefinitions":{"tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildNewDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildNewDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildRequiredDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildRequiredDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getNoSubtypes":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getNoSubtypesWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildNewDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildNewDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildRequiredDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildRequiredDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getNoSubtypes":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getNoSubtypesWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClientBuilder":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.models.ChildWithAnotherDiscriminator":"TspTest.DiscriminatorEdgeCases.ChildWithAnotherDiscriminator","tsptest.discriminatoredgecases.models.ChildWithRequiredPropertyAsDiscriminator":"TspTest.DiscriminatorEdgeCases.ChildWithRequiredPropertyAsDiscriminator","tsptest.discriminatoredgecases.models.GrandChildWithAnotherDiscriminator":"TspTest.DiscriminatorEdgeCases.GrandChildWithAnotherDiscriminator","tsptest.discriminatoredgecases.models.GrandChildWithRequiredProperty":"TspTest.DiscriminatorEdgeCases.GrandChildWithRequiredProperty","tsptest.discriminatoredgecases.models.ModelWithDiscriminatorNoSubtypes":"TspTest.DiscriminatorEdgeCases.ModelWithDiscriminatorNoSubtypes","tsptest.discriminatoredgecases.models.ParentWithRequiredProperty":"TspTest.DiscriminatorEdgeCases.ParentWithRequiredProperty"},"generatedFiles":["src/main/java/module-info.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesAsyncClient.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesClient.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesClientBuilder.java","src/main/java/tsptest/discriminatoredgecases/implementation/DiscriminatorEdgeCasesClientImpl.java","src/main/java/tsptest/discriminatoredgecases/implementation/package-info.java","src/main/java/tsptest/discriminatoredgecases/models/ChildWithAnotherDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithAnotherDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithRequiredProperty.java","src/main/java/tsptest/discriminatoredgecases/models/ModelWithDiscriminatorNoSubtypes.java","src/main/java/tsptest/discriminatoredgecases/models/ParentWithRequiredProperty.java","src/main/java/tsptest/discriminatoredgecases/models/package-info.java","src/main/java/tsptest/discriminatoredgecases/package-info.java"]} \ No newline at end of file +{"flavor":"Azure","apiVersions":{},"crossLanguagePackageId":"TspTest.DiscriminatorEdgeCases","crossLanguageVersion":"f7a3bf40b2af","crossLanguageDefinitions":{"tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildNewDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildNewDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildRequiredDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getChildRequiredDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getNoSubtypes":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesAsyncClient.getNoSubtypesWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildNewDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildNewDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildNewDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildRequiredDiscrim":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getChildRequiredDiscrimWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getChildRequiredDiscrim","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getNoSubtypes":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClient.getNoSubtypesWithResponse":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp.getNoSubtypes","tsptest.discriminatoredgecases.DiscriminatorEdgeCasesClientBuilder":"TspTest.DiscriminatorEdgeCases.DiscriminatorEdgeCasesOp","tsptest.discriminatoredgecases.models.ChildWithAnotherDiscriminator":"TspTest.DiscriminatorEdgeCases.ChildWithAnotherDiscriminator","tsptest.discriminatoredgecases.models.ChildWithRequiredPropertyAsDiscriminator":"TspTest.DiscriminatorEdgeCases.ChildWithRequiredPropertyAsDiscriminator","tsptest.discriminatoredgecases.models.GrandChildWithAnotherDiscriminator":"TspTest.DiscriminatorEdgeCases.GrandChildWithAnotherDiscriminator","tsptest.discriminatoredgecases.models.GrandChildWithNestedDiscriminator":"TspTest.DiscriminatorEdgeCases.GrandChildWithNestedDiscriminator","tsptest.discriminatoredgecases.models.GrandChildWithRequiredProperty":"TspTest.DiscriminatorEdgeCases.GrandChildWithRequiredProperty","tsptest.discriminatoredgecases.models.GreatGrandChildWithDuplicateDiscriminator":"TspTest.DiscriminatorEdgeCases.GreatGrandChildWithDuplicateDiscriminator","tsptest.discriminatoredgecases.models.ModelWithDiscriminatorNoSubtypes":"TspTest.DiscriminatorEdgeCases.ModelWithDiscriminatorNoSubtypes","tsptest.discriminatoredgecases.models.NestedDiscriminatorAssistant":"TspTest.DiscriminatorEdgeCases.NestedDiscriminatorAssistant","tsptest.discriminatoredgecases.models.NestedDiscriminatorBase":"TspTest.DiscriminatorEdgeCases.NestedDiscriminatorBase","tsptest.discriminatoredgecases.models.NestedDiscriminatorMessage":"TspTest.DiscriminatorEdgeCases.NestedDiscriminatorMessage","tsptest.discriminatoredgecases.models.ParentWithRequiredProperty":"TspTest.DiscriminatorEdgeCases.ParentWithRequiredProperty"},"generatedFiles":["src/main/java/module-info.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesAsyncClient.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesClient.java","src/main/java/tsptest/discriminatoredgecases/DiscriminatorEdgeCasesClientBuilder.java","src/main/java/tsptest/discriminatoredgecases/implementation/DiscriminatorEdgeCasesClientImpl.java","src/main/java/tsptest/discriminatoredgecases/implementation/XmlSerializer.java","src/main/java/tsptest/discriminatoredgecases/implementation/XmlSerializerProviders.java","src/main/java/tsptest/discriminatoredgecases/implementation/package-info.java","src/main/java/tsptest/discriminatoredgecases/models/ChildWithAnotherDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/ChildWithRequiredPropertyAsDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithAnotherDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithNestedDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/GrandChildWithRequiredProperty.java","src/main/java/tsptest/discriminatoredgecases/models/GreatGrandChildWithDuplicateDiscriminator.java","src/main/java/tsptest/discriminatoredgecases/models/ModelWithDiscriminatorNoSubtypes.java","src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorAssistant.java","src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorBase.java","src/main/java/tsptest/discriminatoredgecases/models/NestedDiscriminatorMessage.java","src/main/java/tsptest/discriminatoredgecases/models/ParentWithRequiredProperty.java","src/main/java/tsptest/discriminatoredgecases/models/package-info.java","src/main/java/tsptest/discriminatoredgecases/package-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/tsp/discriminator-edge-cases.tsp b/packages/http-client-java/generator/http-client-generator-test/tsp/discriminator-edge-cases.tsp index bb8982abd9e..ce8a79150f4 100644 --- a/packages/http-client-java/generator/http-client-generator-test/tsp/discriminator-edge-cases.tsp +++ b/packages/http-client-java/generator/http-client-generator-test/tsp/discriminator-edge-cases.tsp @@ -1,8 +1,10 @@ import "@typespec/rest"; +import "@typespec/xml"; import "@azure-tools/typespec-azure-core"; import "@azure-tools/typespec-client-generator-core"; using TypeSpec.Http; +using TypeSpec.Xml; using Azure.Core; using Azure.ClientGenerator.Core; @@ -28,6 +30,42 @@ model GrandChildWithRequiredProperty extends ChildWithRequiredPropertyAsDiscrimi discriminator: "aValue"; } +@discriminator("nestedDiscriminator") +model GrandChildWithNestedDiscriminator extends ChildWithRequiredPropertyAsDiscriminator { + discriminator: "nested"; + + // Activates a nested hierarchy so the outer discriminator is propagated and masks the base property. + nestedDiscriminator: string; +} + +model GreatGrandChildWithDuplicateDiscriminator extends GrandChildWithNestedDiscriminator { + // Repeats the propagated outer discriminator to exercise duplicate merging. + discriminator: "nested"; + + nestedDiscriminator: "leaf"; +} + +@usage(Usage.output) +@access(Access.public) +@name("NestedDiscriminatorBase") +@discriminator("type") +model NestedDiscriminatorBase { + @attribute type: string; +} + +@name("NestedDiscriminatorMessage") +@discriminator("role") +model NestedDiscriminatorMessage extends NestedDiscriminatorBase { + @attribute type: "message"; + @attribute role: string; +} + +@name("NestedDiscriminatorAssistant") +model NestedDiscriminatorAssistant extends NestedDiscriminatorMessage { + @attribute type: "message"; + @attribute role: "assistant"; +} + model GrandChildWithAnotherDiscriminator extends ChildWithAnotherDiscriminator { differentDiscriminator: "anotherValue"; }