Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Generate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ $job = @(
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-boolean.json --namespace=fixtures.bodyboolean --client-logger",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-boolean.quirks.json --namespace=fixtures.bodyboolean.quirks",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.bodycomplex --required-fields-as-ctor-args --client-logger --output-model-immutable --generate-tests",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserialization --enable-sync-stack --stream-style-serialization --client-logger --pass-discriminator-to-child-deserialization",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationimmutableoutput --enable-sync-stack --output-model-immutable --stream-style-serialization --client-logger --pass-discriminator-to-child-deserialization",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationctorargs --enable-sync-stack --stream-style-serialization --required-fields-as-ctor-args --client-logger --pass-discriminator-to-child-deserialization",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserialization --enable-sync-stack --stream-style-serialization --client-logger",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationimmutableoutput --enable-sync-stack --output-model-immutable --stream-style-serialization --client-logger",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationctorargs --enable-sync-stack --stream-style-serialization --required-fields-as-ctor-args --client-logger",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-file.json --namespace=fixtures.bodyfile",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-string.json --namespace=fixtures.bodystring --generate-client-interfaces",
"$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/custom-baseUrl.json --namespace=fixtures.custombaseuri",
Expand Down Expand Up @@ -138,8 +138,7 @@ $job = @(
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/discriminator-flattening.json --namespace=fixtures.discriminatorflattening.noflatten --modelerfour.flatten-models=false",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/discriminator-flattening.json --namespace=fixtures.discriminatorflattening.clientflatten --modelerfour.flatten-models=false --client-flattened-annotation-target=NONE",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/client-default-value.json --namespace=fixtures.clientdefaultvalue --modelerfour.flatten-models=false",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/discriminator-flattening.json --namespace=fixtures.inheritance.donotpassdiscriminator --stream-style-serialization=false",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/discriminator-flattening.json --namespace=fixtures.inheritance.passdiscriminator --pass-discriminator-to-child-deserialization=true --stream-style-serialization=false",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/discriminator-flattening.json --namespace=fixtures.inheritance.passdiscriminator --stream-style-serialization=false",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/client-default-value.json --namespace=fixtures.annotatedgettersandsetters --annotate-getters-and-setters-for-serialization=true",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/xml-tag-with-attribute-and-value.json --namespace=fixtures.complexxmltag",
"$VANILLA_ARGUMENTS --input-file=vanilla-tests/swagger/xml-tag-with-attribute-and-value.json --namespace=fixtures.complexstreamstylexmlserialization --stream-style-serialization",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ public static JavaSettings getInstance() {
getBooleanValue(host, "generate-tests", false),
false, //getBooleanValue(host, "generate-send-request-method", false),
getBooleanValue(host, "generate-models", false),
getBooleanValue(host, "pass-discriminator-to-child-deserialization", false),
getBooleanValue(host, "annotate-getters-and-setters-for-serialization", false),
getStringValue(host, "default-http-exception-type"),
getBooleanValue(host, "use-default-http-status-code-to-exception-type-mapping", false),
Expand Down Expand Up @@ -309,7 +308,6 @@ private JavaSettings(AutorestSettings autorestSettings,
boolean generateTests,
boolean generateSendRequestMethod,
boolean generateModels,
boolean passDiscriminatorToChildDeserialization,
boolean annotateGettersAndSettersForSerialization,
String defaultHttpExceptionType,
boolean useDefaultHttpStatusCodeToExceptionTypeMapping,
Expand Down Expand Up @@ -400,7 +398,6 @@ private JavaSettings(AutorestSettings autorestSettings,
this.generateTests = generateTests;
this.generateSendRequestMethod = generateSendRequestMethod;
this.generateModels = generateModels;
this.passDiscriminatorToChildDeserialization = passDiscriminatorToChildDeserialization;
this.annotateGettersAndSettersForSerialization = annotateGettersAndSettersForSerialization;

// Error HTTP status code exception type handling.
Expand Down Expand Up @@ -987,12 +984,6 @@ public PollingDetails getPollingConfig(String operation) {
return pollingConfig.get("default");
}

private final boolean passDiscriminatorToChildDeserialization;

public boolean isDiscriminatorPassedToChildDeserialization() {
return passDiscriminatorToChildDeserialization;
}

private final boolean annotateGettersAndSettersForSerialization;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,12 +449,6 @@ private ParentSchemaInfo getParentSchemaInfo(ObjectSchema compositeType) {
*/
protected ClientModelProperty createDiscriminatorProperty(JavaSettings settings, boolean hasChildren,
ObjectSchema compositeType, Function<String, String> annotationArgumentsMapper, String serializedName) {
// Don't create a discriminator property for the model if the discriminator shouldn't be passed to subtype
// deserialization or the model type has children and stream-style serialization isn't being used.
if ((!settings.isDiscriminatorPassedToChildDeserialization() || hasChildren)
&& !settings.isStreamStyleSerialization()) {
return null;
}
ClientModelProperty discriminatorProperty = Mappers.getModelPropertyMapper()
.map(SchemaUtil.getDiscriminatorProperty(compositeType));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public final void write(ClientModel model, JavaFile javaFile) {
boolean treatAsXml = model.isUsedInXml();

// Handle adding annotations if the model is polymorphic.
handlePolymorphism(model, hasDerivedModels, settings.isDiscriminatorPassedToChildDeserialization(), javaFile);
handlePolymorphism(model, hasDerivedModels, javaFile);

// Add class level annotations for serialization formats such as XML.
addClassLevelAnnotations(model, javaFile, settings);
Expand Down Expand Up @@ -199,8 +199,9 @@ public final void write(ClientModel model, JavaFile javaFile) {
methodBlock -> addSetterMethod(propertyWireType, propertyClientType, property, treatAsXml,
methodBlock, settings, ClientModelUtil.isJsonMergePatchModel(model) && settings.isStreamStyleSerialization()));
} else {
// If stream-style serialization is being generated, some additional setters may need to be added
// to support read-only properties that aren't included in the constructor.
// If stream-style serialization is being generated or the property is the polymorphic
// discriminator, some additional setters may need to be added to support read-only properties that
// aren't included in the constructor.
// Jackson handles this by reflectively setting the value in the parent model, but stream-style
// serialization doesn't perform reflective cracking like Jackson Databind does, so it needs a way
// to access the readonly property (aka one without a public setter method).
Expand All @@ -212,7 +213,8 @@ public final void write(ClientModel model, JavaFile javaFile) {
boolean notIncludedInConstructor = !ClientModelUtil.includePropertyInConstructor(property,
settings);
boolean definedByModel = modelDefinesProperty(model, property);
if (streamStyle && hasDerivedTypes && notIncludedInConstructor && definedByModel) {
if (hasDerivedTypes && notIncludedInConstructor && definedByModel
&& (settings.isStreamStyleSerialization() || property.isPolymorphicDiscriminator())) {
generateSetterJavadoc(classBlock, model, property);
addGeneratedAnnotation(classBlock);
classBlock.method(JavaVisibility.PackagePrivate, null,
Expand Down Expand Up @@ -420,50 +422,31 @@ protected List<ClientModelPropertyAccess> getParentSettersToOverride(ClientModel
*
* @param model The client model.
* @param hasDerivedModels Whether this model has children types.
* @param isDiscriminatorPassedToChildDeserialization Whether the deserialization discriminator, such as
* {@code odata.type}, is passed to children types during deserialization.
* @param javaFile The JavaFile being generated.
*/
protected void handlePolymorphism(ClientModel model, boolean hasDerivedModels,
boolean isDiscriminatorPassedToChildDeserialization, JavaFile javaFile) {
protected void handlePolymorphism(ClientModel model, boolean hasDerivedModels, JavaFile javaFile) {
// Model isn't polymorphic, no work to do here.
if (!model.isPolymorphic()) {
return;
}

StringBuilder jsonTypeInfo = new StringBuilder("JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = ");
// After removing the concept of passing discriminator to children models and always doing it, there is no need
// to set the 'include' property of the JsonTypeInfo annotation. We use 'JsonTypeInfo.As.PROPERTY' as the value,
// which is the default value, so it doesn't need to be declared.
// And to support unknown subtypes, we always set a default implementation to the class being generated.
// And the discriminator is passed to child models, so the discriminator property needs to be set to visible.
String jsonTypeInfo = "JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = \""
+ model.getPolymorphicDiscriminatorName() + "\", defaultImpl = " + model.getName()
+ ".class, visible = true)";

// If the discriminator isn't being passed to child models or this model has derived, children, models
// include the discriminator property using JsonTypeInfo.As.PROPERTY. Using this will serialize the
// property using the property attribute of the annotation instead of looking for a @JsonProperty.
if (!isDiscriminatorPassedToChildDeserialization || hasDerivedModels) {
jsonTypeInfo.append("JsonTypeInfo.As.PROPERTY, property = \"");
} else {
// Otherwise, serialize the discriminator property with an existing property on the class.
jsonTypeInfo.append("JsonTypeInfo.As.EXISTING_PROPERTY, property = \"");
}

jsonTypeInfo.append(model.getPolymorphicDiscriminatorName()).append("\"");

// If the class has derived models add itself as a default implementation.
if (hasDerivedModels) {
jsonTypeInfo.append(", defaultImpl = ").append(model.getName()).append(".class");
}

// If the discriminator is passed to child models the discriminator property needs to be set to visible.
if (isDiscriminatorPassedToChildDeserialization) {
jsonTypeInfo.append(", visible = true");
}

javaFile.annotation(jsonTypeInfo.append(")").toString());
javaFile.annotation(String.format("JsonTypeName(\"%1$s\")", model.getSerializedName()));
javaFile.annotation(jsonTypeInfo);
javaFile.annotation("JsonTypeName(\"" + model.getSerializedName() + "\")");

if (hasDerivedModels) {
javaFile.line("@JsonSubTypes({");
javaFile.indent(() -> {
Function<ClientModel, String> getDerivedTypeAnnotation = (ClientModel derivedType) ->
String.format("@JsonSubTypes.Type(name = \"%1$s\", value = %2$s.class)",
derivedType.getSerializedName(), derivedType.getName());
Function<ClientModel, String> getDerivedTypeAnnotation = derivedType -> "@JsonSubTypes.Type(name = \""
+ derivedType.getSerializedName() + "\", value = " + derivedType.getName() + ".class)";

for (int i = 0; i != model.getDerivedModels().size() - 1; i++) {
ClientModel derivedModel = model.getDerivedModels().get(i);
Expand Down Expand Up @@ -614,9 +597,7 @@ private void addProperties(ClientModel model, JavaClass classBlock, JavaSettings
addGeneratedAnnotation(classBlock);
addFieldAnnotations(model, property, classBlock, settings);

if (property.isPolymorphicDiscriminator() && !settings.isStreamStyleSerialization()) {
classBlock.privateStaticFinalVariable(fieldSignature);
} else if (ClientModelUtil.includePropertyInConstructor(property, settings)) {
if (ClientModelUtil.includePropertyInConstructor(property, settings)) {
classBlock.privateFinalMemberVariable(fieldSignature);
} else {
classBlock.privateMemberVariable(fieldSignature);
Expand Down Expand Up @@ -828,11 +809,9 @@ private void addModelConstructor(ClientModel model, JavaVisibility constructorVi
constructor.line("super(" + superProperties + ");");
}

// If there is a polymorphic discriminator and stream-style serialization is being used, add a line to
// initialize the discriminator.
// If there is a polymorphic discriminator , add a line to initialize the discriminator.
ClientModelProperty polymorphicProperty = model.getPolymorphicDiscriminator();
if (polymorphicProperty != null && !polymorphicProperty.isRequired()
&& settings.isStreamStyleSerialization()) {
if (polymorphicProperty != null && !polymorphicProperty.isRequired()) {
String discriminatorValue = polymorphicProperty.getDefaultValue() != null
? polymorphicProperty.getDefaultValue()
: polymorphicProperty.getClientType().defaultValueExpression(model.getSerializedName());
Expand Down Expand Up @@ -953,9 +932,7 @@ private static void addGetterMethod(IType propertyWireType, IType propertyClient
boolean treatAsXml, JavaBlock methodBlock, JavaSettings settings) {
String sourceTypeName = propertyWireType.toString();
String targetTypeName = propertyClientType.toString();
String expression = (property.isPolymorphicDiscriminator() && !settings.isStreamStyleSerialization())
? CodeNamer.getEnumMemberName(property.getName())
: "this." + property.getName();
String expression = "this." + property.getName();
if (propertyWireType.equals(ArrayType.BYTE_ARRAY)) {
expression = TemplateHelper.getByteCloneExpression(expression);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ protected void addSerializationImports(Set<String> imports, ClientModel model, J
}

@Override
protected void handlePolymorphism(ClientModel model, boolean hasDerivedModels,
boolean isDiscriminatorPassedToChildDeserialization, JavaFile javaFile) {
protected void handlePolymorphism(ClientModel model, boolean hasDerivedModels, JavaFile javaFile) {
// no-op as stream-style serialization doesn't need to add anything for polymorphic types.
}

Expand Down
1 change: 0 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ Settings can be provided on the command line through `--name:value` or in a READ
|`--polling`|Configures how to generate long running operations. See [Polling Configuration](#polling-configuration) to see more details on how to use this flag.|
|`--service-name`|Service name used in Client class and other documentations. If not provided, service name is deduced from `title` configure (from swagger or readme).|
|`--partial-update`|Indicates whether to support partial update for `Client`/`AsyncClient` classes and `ClientBuilder` class.|
|`--pass-discriminator-to-child-deserialization`|Indicates whether the discriminator property is passed to subclass deserialization. Default is false.|
|`--default-http-exception-type`|The fully-qualified class name that should be used as the default HTTP exception type. The class must extend from `HttpResponseException`.|
|`--use-default-http-status-code-to-exception-type-mapping`|Indicates whether a default HTTP status code to exception mapping should be used if one isn't provided.|
|`--http-status-code-to-exception-type-mapping`|The HTTP status code to exception mapping that should be used. All exception types must be fully-qualified and extend from `HttpResponseException`.|
Expand Down
Loading