From 432c07d12ffc180ef6c3e6610ced4834bb06d57e Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:18:28 -0400 Subject: [PATCH 1/3] Simplify StreamSerializationModelTemplate --- ...StreamStyleSerializationModelTemplate.java | 3 +- .../ClientModelPropertiesManager.java | 11 + .../autorest/template/ModelTemplate.java | 24 +- .../StreamSerializationModelTemplate.java | 3975 ++++++++--------- 4 files changed, 1968 insertions(+), 2045 deletions(-) diff --git a/fluentgen/src/main/java/com/azure/autorest/fluent/template/FluentStreamStyleSerializationModelTemplate.java b/fluentgen/src/main/java/com/azure/autorest/fluent/template/FluentStreamStyleSerializationModelTemplate.java index f4831a661e..c77cd7dc1d 100644 --- a/fluentgen/src/main/java/com/azure/autorest/fluent/template/FluentStreamStyleSerializationModelTemplate.java +++ b/fluentgen/src/main/java/com/azure/autorest/fluent/template/FluentStreamStyleSerializationModelTemplate.java @@ -3,7 +3,6 @@ package com.azure.autorest.fluent.template; -import com.azure.autorest.extension.base.plugin.JavaSettings; import com.azure.autorest.fluent.model.arm.ErrorClientModel; import com.azure.autorest.fluent.util.FluentUtils; import com.azure.autorest.model.clientmodel.ClientModel; @@ -32,7 +31,7 @@ protected boolean parentModelHasValidate(String parentModelName) { } @Override - protected boolean isManagementErrorSubclass(ClientModel model, JavaSettings settings) { + protected boolean isManagementErrorSubclass(ClientModel model) { if (CoreUtils.isNullOrEmpty(model.getParentModelName())) { return false; } diff --git a/javagen/src/main/java/com/azure/autorest/implementation/ClientModelPropertiesManager.java b/javagen/src/main/java/com/azure/autorest/implementation/ClientModelPropertiesManager.java index 0881ed2afe..72c21c316f 100644 --- a/javagen/src/main/java/com/azure/autorest/implementation/ClientModelPropertiesManager.java +++ b/javagen/src/main/java/com/azure/autorest/implementation/ClientModelPropertiesManager.java @@ -39,6 +39,7 @@ */ public final class ClientModelPropertiesManager { private final ClientModel model; + private final JavaSettings settings; private final String deserializedModelName; private final boolean hasRequiredProperties; @@ -88,6 +89,7 @@ public ClientModelPropertiesManager(ClientModel model, JavaSettings settings) { Set possibleXmlNameVariableNames = new LinkedHashSet<>(Arrays.asList( "elementName", "xmlElementName", "deserializationElementName")); this.model = model; + this.settings = settings; this.deserializedModelName = "deserialized" + model.getName(); this.expectedDiscriminator = model.getSerializedName(); @@ -293,6 +295,15 @@ public ClientModel getModel() { return model; } + /** + * The {@link JavaSettings} being used to determine code generation. + * + * @return The {@link JavaSettings} being used to determine code generation. + */ + public JavaSettings getSettings() { + return settings; + } + /** * Gets the name of the variable used when deserializing an instance of the {@link #getModel() model}. * diff --git a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java index 91727fed3e..67de23a745 100644 --- a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java @@ -4,6 +4,7 @@ package com.azure.autorest.template; import com.azure.autorest.extension.base.plugin.JavaSettings; +import com.azure.autorest.implementation.ClientModelPropertiesManager; import com.azure.autorest.implementation.PolymorphicDiscriminatorHandler; import com.azure.autorest.model.clientmodel.Annotation; import com.azure.autorest.model.clientmodel.ArrayType; @@ -74,6 +75,7 @@ public final void write(ClientModel model, JavaFile javaFile) { final boolean requireSerialization = modelRequireSerialization(model); JavaSettings settings = JavaSettings.getInstance(); + ClientModelPropertiesManager propertiesManager = new ClientModelPropertiesManager(model, settings); Set imports = settings.isStreamStyleSerialization() ? new StreamStyleImports() : new HashSet<>(); addImports(imports, model, settings); @@ -144,7 +146,7 @@ public final void write(ClientModel model, JavaFile javaFile) { discriminator -> addFieldAnnotations(model, discriminator, classBlock, settings), settings); // properties - addProperties(model, classBlock, settings); + addProperties(propertiesManager, classBlock); // add jsonMergePatch related properties and accessors if (ClientModelUtil.isJsonMergePatchModel(model, settings)) { @@ -157,7 +159,7 @@ public final void write(ClientModel model, JavaFile javaFile) { : JavaVisibility.Public; addModelConstructor(model, modelConstructorVisibility, settings, classBlock); - for (ClientModelProperty property : getFieldProperties(model, settings)) { + for (ClientModelProperty property : getFieldProperties(propertiesManager)) { final boolean propertyIsReadOnly = immutableModel || property.isReadOnly(); IType propertyWireType = property.getWireType(); @@ -523,13 +525,11 @@ protected void addXmlNamespaceConstants(ClientModel model, JavaClass classBlock) /** * Adds the property fields to a class. * - * @param model The client model. * @param classBlock The Java class. - * @param settings AutoRest configuration settings. */ - private void addProperties(ClientModel model, JavaClass classBlock, JavaSettings settings) { - for (ClientModelProperty property : getFieldProperties(model, settings)) { - addProperty(property, model, classBlock, settings); + private void addProperties(ClientModelPropertiesManager propertiesManager, JavaClass classBlock) { + for (ClientModelProperty property : getFieldProperties(propertiesManager)) { + addProperty(property, propertiesManager.getModel(), classBlock, propertiesManager.getSettings()); } } @@ -607,14 +607,12 @@ private void addProperty(ClientModelProperty property, ClientModel model, JavaCl /** * Get properties to generate as fields of the class. - * @param model the model to generate class of - * @param settings JavaSettings + * @param propertiesManager The properties manager. * @return properties to generate as fields of the class */ - protected List getFieldProperties(ClientModel model, JavaSettings settings) { - return Stream.concat( - model.getParentPolymorphicDiscriminators().stream(), - model.getProperties().stream() + protected List getFieldProperties(ClientModelPropertiesManager propertiesManager) { + ClientModel model = propertiesManager.getModel(); + return Stream.concat(model.getParentPolymorphicDiscriminators().stream(), model.getProperties().stream() ).collect(Collectors.toList()); } diff --git a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java index 36f7bdacd3..ca6585f794 100644 --- a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java @@ -44,6 +44,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -142,121 +143,130 @@ static void xmlWrapperClassXmlSerializableImplementation(JavaClass classBlock, S addGeneratedAnnotation.accept(classBlock); classBlock.annotation("Override"); - classBlock.publicMethod("XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException", writerMethod -> { - writerMethod.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + xmlRootElementName + "\" : rootElementName;"); - String writeStartElement = (xmlRootElementNamespace != null) - ? "xmlWriter.writeStartElement(\"" + xmlRootElementNamespace + "\", rootElementName);" - : "xmlWriter.writeStartElement(rootElementName);"; - writerMethod.line(writeStartElement); - - writerMethod.ifBlock(xmlElementNameCamelCase + " != null", ifAction -> { - String xmlWrite = elementType.xmlSerializationMethodCall("xmlWriter", xmlListElementName, - xmlListElementNamespace, "element", false, false, false); - ifAction.line("for (%s element : %s) {", elementType, xmlElementNameCamelCase); - ifAction.indent(() -> ifAction.line(xmlWrite + ";")); - ifAction.line("}"); - }); + classBlock.publicMethod( + "XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException", writerMethod -> { + writerMethod.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + xmlRootElementName + + "\" : rootElementName;"); + String writeStartElement = (xmlRootElementNamespace != null) + ? "xmlWriter.writeStartElement(\"" + xmlRootElementNamespace + "\", rootElementName);" + : "xmlWriter.writeStartElement(rootElementName);"; + writerMethod.line(writeStartElement); + + writerMethod.ifBlock(xmlElementNameCamelCase + " != null", ifAction -> { + String xmlWrite = elementType.xmlSerializationMethodCall("xmlWriter", xmlListElementName, + xmlListElementNamespace, "element", false, false, false); + ifAction.line("for (%s element : %s) {", elementType, xmlElementNameCamelCase); + ifAction.indent(() -> ifAction.line(xmlWrite + ";")); + ifAction.line("}"); + }); - writerMethod.methodReturn("xmlWriter.writeEndElement()"); - }); + writerMethod.methodReturn("xmlWriter.writeEndElement()"); + }); addGeneratedAnnotation.accept(classBlock); classBlock.publicStaticMethod(wrapperClassName + " fromXml(XmlReader xmlReader) throws XMLStreamException", readerMethod -> readerMethod.methodReturn("fromXml(xmlReader, null)")); addGeneratedAnnotation.accept(classBlock); - classBlock.publicStaticMethod(wrapperClassName + " fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException", readerMethod -> { - readerMethod.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + xmlRootElementName + "\" : rootElementName;"); - String readObject = (xmlRootElementNamespace != null) - ? "return xmlReader.readObject(\"" + xmlRootElementNamespace + "\", rootElementName, reader -> {" - : "return xmlReader.readObject(rootElementName, reader -> {"; - - readerMethod.line(readObject); - readerMethod.indent(() -> { - readerMethod.line(iterableType + " items = null;"); - readerMethod.line(); - readerMethod.line("while (reader.nextElement() != XmlToken.END_ELEMENT) {"); + classBlock.publicStaticMethod( + wrapperClassName + " fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException", + readerMethod -> { + readerMethod.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + xmlRootElementName + + "\" : rootElementName;"); + String readObject = (xmlRootElementNamespace != null) + ? "return xmlReader.readObject(\"" + xmlRootElementNamespace + "\", rootElementName, reader -> {" + : "return xmlReader.readObject(rootElementName, reader -> {"; + + readerMethod.line(readObject); readerMethod.indent(() -> { - readerMethod.line("QName elementName = reader.getElementName();"); - String condition = getXmlNameConditional(xmlListElementName, xmlListElementNamespace, "elementName", false); + readerMethod.line(iterableType + " items = null;"); readerMethod.line(); - readerMethod.ifBlock(condition, ifBlock -> { - ifBlock.ifBlock("items == null", ifBlock2 -> ifBlock2.line("items = new ArrayList<>();")); - ifBlock.line(); - - // TODO (alzimmer): Insert XML object reading logic. - ifBlock.line("items.add(" + getSimpleXmlDeserialization(elementType, "reader", null, null, - null, false) + ");"); - }).elseBlock(elseBlock -> elseBlock.line("reader.nextElement();")); - }); - readerMethod.line("}"); + readerMethod.line("while (reader.nextElement() != XmlToken.END_ELEMENT) {"); + readerMethod.indent(() -> { + readerMethod.line("QName elementName = reader.getElementName();"); + String condition = getXmlNameConditional(xmlListElementName, xmlListElementNamespace, + "elementName", false); + readerMethod.line(); + readerMethod.ifBlock(condition, ifBlock -> { + ifBlock.ifBlock("items == null", ifBlock2 -> ifBlock2.line("items = new ArrayList<>();")); + ifBlock.line(); + + // TODO (alzimmer): Insert XML object reading logic. + ifBlock.line( + "items.add(" + getSimpleXmlDeserialization(elementType, null, null, null, + false) + ");"); + }).elseBlock(elseBlock -> elseBlock.line("reader.nextElement();")); + }); + readerMethod.line("}"); - readerMethod.methodReturn("new " + wrapperClassName + "(items)"); + readerMethod.methodReturn("new " + wrapperClassName + "(items)"); + }); + readerMethod.line("});"); }); - readerMethod.line("});"); - }); } - @Override - protected void addFieldAnnotations(ClientModel model, ClientModelProperty property, JavaClass classBlock, JavaSettings settings) { - // no-op as stream-style serialization doesn't add any field-level annotations. - } - - @Override - protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModel model, JavaSettings settings) { - // Early out as strongly-typed headers do their own thing. - if (model.isStronglyTypedHeader()) { - return; + private static String getXmlNameConditional(String localPart, String namespace, String elementName, + boolean namespaceIsConstant) { + String condition = "\"" + localPart + "\".equals(" + elementName + ".getLocalPart())"; + if (!CoreUtils.isNullOrEmpty(namespace)) { + if (namespaceIsConstant) { + condition += " && " + namespace + ".equals(" + elementName + ".getNamespaceURI())"; + } else { + condition += " && \"" + namespace + "\".equals(" + elementName + ".getNamespaceURI())"; + } } - ClientModelPropertiesManager propertiesManager = new ClientModelPropertiesManager(model, settings); + return condition; + } - if (model.getXmlName() != null) { - writeToXml(classBlock, propertiesManager, Templates.getModelTemplate()::addGeneratedAnnotation); - writeFromXml(classBlock, model, propertiesManager, settings, - Templates.getModelTemplate()::addGeneratedAnnotation); + private static String getSimpleXmlDeserialization(IType wireType, String elementName, String attributeName, + String attributeNamespace, boolean namespaceIsConstant) { + if (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { + return CoreUtils.isNullOrEmpty(elementName) + ? wireType + ".fromXml(reader)" + : wireType + ".fromXml(reader, \"" + elementName + "\")"; } else { - if (ClientModelUtil.isJsonMergePatchModel(model, settings)) { - writeToJson(classBlock, propertiesManager, true, Templates.getModelTemplate()::addGeneratedAnnotation); - writeToJsonMergePatch(classBlock, propertiesManager, - Templates.getModelTemplate()::addGeneratedAnnotation); - } else { - writeToJson(classBlock, propertiesManager, false, Templates.getModelTemplate()::addGeneratedAnnotation); - } - writeFromJson(classBlock, model, propertiesManager, settings, - Templates.getModelTemplate()::addGeneratedAnnotation); - if (isManagementErrorSubclass(model, settings)) { - writeManagementErrorDeserializationMethod(classBlock, propertiesManager, settings, - Templates.getModelTemplate()::addGeneratedAnnotation); - } + return wireType.xmlDeserializationMethod("reader", attributeName, attributeNamespace, + namespaceIsConstant); } } + @Override + protected void addFieldAnnotations(ClientModel model, ClientModelProperty property, JavaClass classBlock, + JavaSettings settings) { + // no-op as stream-style serialization doesn't add any field-level annotations. + } + /** - * For stream-style-serialization, we generate shadow properties for read-only properties that's not in constructor. - * @param model the model to generate class of - * @param settings JavaSettings + * For stream-style-serialization, we generate shadow properties for read-only properties that's not in + * constructor. + * + * @param propertiesManager the properties manager * @return properties to generate as fields of the class */ @Override - protected List getFieldProperties(ClientModel model, JavaSettings settings) { - List fieldProperties = super.getFieldProperties(model, settings); + protected List getFieldProperties(ClientModelPropertiesManager propertiesManager) { + List fieldProperties = super.getFieldProperties(propertiesManager); // If the model is polymorphic and all the models in the polymorphic hierarchy are in the same package we don't // need to shade parent properties. - if (model.isPolymorphic() && model.isAllPolymorphicModelsInSamePackage()) { + if (canUseFromJsonShared(propertiesManager)) { return fieldProperties; } - Set propertySerializedNames = fieldProperties.stream().map(ClientModelProperty::getSerializedName) + Set propertySerializedNames = fieldProperties.stream() + .map(ClientModelProperty::getSerializedName) .collect(Collectors.toSet()); + ClientModel model = propertiesManager.getModel(); for (ClientModelProperty parentProperty : ClientModelUtil.getParentProperties(model, false)) { if (propertySerializedNames.contains(parentProperty.getSerializedName())) { continue; } propertySerializedNames.add(parentProperty.getSerializedName()); - if (!parentProperty.isPolymorphicDiscriminator() // parent discriminators are already passed to children, see @see in method javadoc - && ClientModelUtil.readOnlyNotInCtor(model, parentProperty, settings) // we shadow parent read-only properties in child class + if (!parentProperty.isPolymorphicDiscriminator() + // parent discriminators are already passed to children, see @see in method javadoc + && ClientModelUtil.readOnlyNotInCtor(model, parentProperty, propertiesManager.getSettings()) + // we shadow parent read-only properties in child class || parentProperty.getClientFlatten()) { // we shadow parent flattened property in child class fieldProperties.add(parentProperty); } @@ -264,12 +274,20 @@ protected List getFieldProperties(ClientModel model, JavaSe return fieldProperties; } + private static boolean canUseFromJsonShared(ClientModelPropertiesManager propertiesManager) { + // If the model is part of a polymorphic hierarchy and all models in the polymorphic hierarchy are in the same + // package we can generate a package-private 'toJsonShared' method that can handle deserializing properties + // defined in the parent class(es). + // This will prevent duplicating the deserialization logic for parent properties in each subclass. + return !propertiesManager.hasConstructorArguments() + && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage(); + } + /** - * Get the property reference referring to the local(field) flattened property. - * Additionally, in Stream-Style, parent property reference count as well. Since in Stream-Style, the flattened model property - * will be shadowed in child class. - * For example, for the property1FromParent collected by {@link #getClientModelPropertyReferences(ClientModel)} on model2, - * it looks like: + * Get the property reference referring to the local(field) flattened property. Additionally, in Stream-Style, + * parent property reference count as well. Since in Stream-Style, the flattened model property will be shadowed in + * child class. For example, for the property1FromParent collected by + * {@link #getClientModelPropertyReferences(ClientModel)} on model2, it looks like: *
{@code
      *         FlattenedProperties
      *          - property1                    <--------------
@@ -286,20 +304,22 @@ protected List getFieldProperties(ClientModel model, JavaSe
      *              - targetProperty -> null
      * }
      * 
- * If called on property1FromParent collected from Model2, property1FromFlatten will be returned. - * If this method is called on property1FromFlatten collected from Model1, itself will be returned. + * If called on property1FromParent collected from Model2, property1FromFlatten will be returned. If this method is + * called on property1FromFlatten collected from Model1, itself will be returned. * * @param propertyReference propertyReference collected by {@link #getClientModelPropertyReferences(ClientModel)} - * @return the property reference referring to the local(field) flattened property, or parent flattening property reference, - * null if neither + * @return the property reference referring to the local(field) flattened property, or parent flattening property + * reference, null if neither */ @Override - protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference(ClientModelPropertyReference propertyReference) { + protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference( + ClientModelPropertyReference propertyReference) { if (propertyReference.isFromFlattenedProperty()) { return propertyReference; } else if (propertyReference.isFromParentModel()) { ClientModelPropertyAccess parentProperty = propertyReference.getReferenceProperty(); // parent property - if (parentProperty instanceof ClientModelPropertyReference && ((ClientModelPropertyReference) parentProperty).isFromFlattenedProperty()) { + if (parentProperty instanceof ClientModelPropertyReference + && ((ClientModelPropertyReference) parentProperty).isFromFlattenedProperty()) { return (ClientModelPropertyReference) parentProperty; } } @@ -308,15 +328,15 @@ protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference(C } @Override - protected List getSuperSetters(ClientModel model, JavaSettings settings, List propertyReferences) { + protected List getSuperSetters(ClientModel model, JavaSettings settings, + List propertyReferences) { return super.getSuperSetters(model, settings, propertyReferences) - .stream() - // If the propertyReference is flattening property, then in Stream-Style we generate local getter/setter - // for it, thus we don't need to generate super setter. - .filter(propertyReference -> - !((propertyReference instanceof ClientModelPropertyReference) - && ((ClientModelPropertyReference) propertyReference).isFromFlattenedProperty())) - .collect(Collectors.toList()); + .stream() + // If the propertyReference is flattening property, then in Stream-Style we generate local getter/setter + // for it, thus we don't need to generate super setter. + .filter(propertyReference -> !((propertyReference instanceof ClientModelPropertyReference) + && ((ClientModelPropertyReference) propertyReference).isFromFlattenedProperty())) + .collect(Collectors.toList()); } @Override @@ -329,1280 +349,1137 @@ protected boolean callParentValidate(String parentModelName) { protected List getValidationProperties(ClientModel model) { // in stream-style-serialization, since there are shadowing involved, we validate all properties locally return Stream.concat(model.getProperties().stream(), ClientModelUtil.getParentProperties(model).stream()) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } /** - * write toJson() method. - *

- * If it is a JsonMergePatch model, toJson() should first check jsonMergePatch flag value and then do serialization - * accordingly. + * Whether the given model is subclass of ManagementError, which needs special deserialization adaption. * - * @param classBlock The class block to write the toJson method to. - * @param propertiesManager The properties manager for the model. - * @param isJsonMergePatch Whether the serialization is for a JSON merge patch. - * @param addGeneratedAnnotation The consumer to add the generated annotation to the class block. + * @param model the model to check + * @return whether the given model is subclass of ManagementError */ - private static void writeToJson(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - boolean isJsonMergePatch, Consumer addGeneratedAnnotation) { - boolean callToJsonSharedForParentProperties = !isJsonMergePatch - && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage() - && !CoreUtils.isNullOrEmpty(propertiesManager.getModel().getParentModelName()); - boolean callToJsonSharedForThisProperties = !isJsonMergePatch - && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage() - && propertiesManager.getModel().isPolymorphicParent(); - - classBlock.javadocComment(JavaJavadocComment::inheritDoc); - addGeneratedAnnotation.accept(classBlock); - classBlock.annotation("Override"); - classBlock.publicMethod("JsonWriter toJson(JsonWriter jsonWriter) throws IOException", methodBlock -> { - if (isJsonMergePatch) { - // If the model is the root parent use the JSON merge patch serialization tracking property directly, - // otherwise use the access helper to determine whether to use JSON merge patch serialization. - ClientModel rootParent = ClientModelUtil.getRootParent(propertiesManager.getModel()); - String ifStatement = (rootParent == propertiesManager.getModel()) - ? "jsonMergePatch" - : JSON_MERGE_PATCH_HELPER_CLASS_NAME + ".get" + rootParent.getName() + "Accessor().isJsonMergePatch(this)"; - - methodBlock.ifBlock(ifStatement, ifBlock -> ifBlock.methodReturn("toJsonMergePatch(jsonWriter)")) - .elseBlock(elseBlock -> serializeJsonProperties(methodBlock, propertiesManager, false, false, false)); - } else { - // For polymorphic models, when all models are contained in the same package, a package-private 'toJsonShared' - // method will be generated by parent models that handles serialization of properties defined by the parent - // model. - // So, if we have that case, we skip serializing the properties defined by the parent model(s) and instead call - // the 'toJsonShared' method to serialize those properties. And, for properties defined by this model, if the - // model is a parent model generate a 'toJsonShared' method to serialize those properties. - // - // At this time, due to implementation complexity and the low value add, JSON merge patch serialization won't - // support 'toJsonMergePatchShared'. JSON merge patch serialization has low usage, and combined with the low - // usage of polymorphism as well, there isn't a large expectation for this feature. - serializeJsonProperties(methodBlock, propertiesManager, false, callToJsonSharedForParentProperties, - callToJsonSharedForThisProperties); - } - }); - - // If this model is defining a 'toJsonShared' method, write it. - if (callToJsonSharedForThisProperties) { - classBlock.packagePrivateMethod("void toJsonShared(JsonWriter jsonWriter) throws IOException", methodBlock -> { - if (callToJsonSharedForParentProperties) { - methodBlock.line("super.toJsonShared(jsonWriter);"); - } + protected boolean isManagementErrorSubclass(ClientModel model) { + return false; + } - serializeThisJsonProperties(propertiesManager, (property, fromSuper) -> serializeJsonProperty( - methodBlock, property, property.getSerializedName(), fromSuper, true, false), methodBlock, - callToJsonSharedForParentProperties); - }); + @Override + protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModel model, JavaSettings settings) { + // Early out as strongly-typed headers do their own thing. + if (model.isStronglyTypedHeader()) { + return; } - } - /** - * write toJsonMergePatch() method - * - * @param classBlock The class block to write the toJsonMergePatch method to. - * @param propertiesManager The properties manager for the model. - * @param addGeneratedAnnotation The consumer to add the generated annotation to the class block. - */ - private static void writeToJsonMergePatch(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - Consumer addGeneratedAnnotation) { - addGeneratedAnnotation.accept(classBlock); - classBlock.privateMethod("JsonWriter toJsonMergePatch(JsonWriter jsonWriter) throws IOException", - methodBlock -> serializeJsonProperties(methodBlock, propertiesManager, true, false, false)); + new StreamSerializationGenerator(model, settings, + this::isManagementErrorSubclass).writeStreamStyleSerialization(classBlock); } - /** - * Serializes the properties of a model to JSON. - * @param methodBlock The method block to write the serialization method to. - * @param propertiesManager The properties manager for the model. - * @param isJsonMergePatch Whether the serialization is for a JSON merge patch. - */ - private static void serializeJsonProperties(JavaBlock methodBlock, ClientModelPropertiesManager propertiesManager, - boolean isJsonMergePatch, boolean callToJsonSharedForParentProperties, - boolean callToJsonSharedForThisProperties) { - methodBlock.line("jsonWriter.writeStartObject();"); - - // If we're calling toJsonShared for this model and for parent properties, this is an early out. - if (callToJsonSharedForParentProperties && callToJsonSharedForThisProperties) { - methodBlock.line("toJsonShared(jsonWriter);"); - methodBlock.methodReturn("jsonWriter.writeEndObject()"); - return; - } + private static final class StreamSerializationGenerator { + private final ClientModelPropertiesManager propertiesManager; + private final ClientModel model; + private final JavaSettings settings; + private final Predicate isManagementErrorSubclass; - BiConsumer serializeJsonProperty = (property, fromSuper) -> serializeJsonProperty( - methodBlock, property, property.getSerializedName(), fromSuper, true, isJsonMergePatch); + private final Consumer addGeneratedAnnotation; + private final boolean isJsonMergePatchModel; + private final boolean useFromJsonShared; - if (callToJsonSharedForParentProperties) { - methodBlock.line("toJsonShared(jsonWriter);"); - } else { - serializeParentJsonProperties(propertiesManager, serializeJsonProperty); - } + private StreamSerializationGenerator(ClientModel model, JavaSettings settings, + Predicate isManagementErrorSubclass) { + this.propertiesManager = new ClientModelPropertiesManager(model, settings); + this.model = model; + this.settings = settings; + this.isManagementErrorSubclass = isManagementErrorSubclass; - if (callToJsonSharedForThisProperties) { - methodBlock.line("toJsonShared(jsonWriter);"); - } else { - serializeThisJsonProperties(propertiesManager, serializeJsonProperty, methodBlock, - callToJsonSharedForParentProperties); + this.addGeneratedAnnotation = Templates.getModelTemplate()::addGeneratedAnnotation; + this.isJsonMergePatchModel = ClientModelUtil.isJsonMergePatchModel(model, settings); + this.useFromJsonShared = canUseFromJsonShared(propertiesManager); } + private void writeStreamStyleSerialization(JavaClass classBlock) { + if (model.getXmlName() != null) { + writeToXml(classBlock); + if (isSuperTypeWithDiscriminator(model)) { + writeSuperTypeFromXml(classBlock); + } else { + writeTerminalTypeFromXml(classBlock); + } + } else { + if (isJsonMergePatchModel) { + writeToJson(classBlock, true); + addGeneratedAnnotation.accept(classBlock); + classBlock.privateMethod("JsonWriter toJsonMergePatch(JsonWriter jsonWriter) throws IOException", + methodBlock -> serializeJsonProperties(methodBlock, true, false, false)); + } else { + writeToJson(classBlock, false); + } - methodBlock.methodReturn("jsonWriter.writeEndObject()"); - } - - private static void serializeParentJsonProperties(ClientModelPropertiesManager propertiesManager, - BiConsumer serializeJsonProperty) { - propertiesManager.getModel() - .getParentPolymorphicDiscriminators() - .forEach(discriminator -> serializeJsonProperty.accept(discriminator, false)); - propertiesManager.forEachSuperRequiredProperty(property -> serializeJsonProperty.accept(property, true)); - propertiesManager.forEachSuperSetterProperty(property -> serializeJsonProperty.accept(property, true)); - } + // All classes will create a public fromJson(JsonReader) method that initiates reading. + // How the implementation looks depends on whether the type is a super type, subtype, both, or is a + // stand-alone type. + // + // Intermediate types, those that are both a super type and subtype, will pass null as the type discriminator + // value. This is done as super types are written to only support themselves or their subtypes, passing a + // discriminator into its own super type would confuse this scenario. For example, one of the test Swaggers + // generates the following hierarchy + // + // Fish + // Salmon Shark + // SmartSalmon Sawshark GoblinShark Cookiecuttershark + // + // If Salmon called into Fish with its discriminator and an error occurred it would mention the Shark subtypes + // as potential legal values for deserialization, confusing the Salmon deserializer. So, calling into Salmon + // will only attempt to handle Salmon and SmartSalmon, and same goes for Shark with Shark, Sawshark, + // GoblinShark, and Cookiecuttershark. It's only Fish that will handle all subtypes, as this is the most generic + // super type. This also creates a well-defined bounds for code generation in regard to type hierarchies. + // + // In a real scenario someone deserializing to Salmon should have an exception about discriminator types + // if the JSON payload is a Shark and not get a ClassCastException as it'd be more confusing on why a Shark + // was trying to be converted to a Salmon. + if (isSuperTypeWithDiscriminator(model)) { + writeSuperTypeFromJson(classBlock); + } else { + readJsonObject(classBlock, false, this::writeFromJsonDeserialization); + } - private static void serializeThisJsonProperties(ClientModelPropertiesManager propertiesManager, - BiConsumer serializeJsonProperty, JavaBlock methodBlock, - boolean callToJsonSharedForParentProperties) { - Consumer wrappedSerializer = property -> { - // Skip serializing the polymorphic discriminator if 'toJsonShared' is called to serialize properties - // defined by the parent model(s), the polymorphic discriminator isn't defined by this property, and - // all polymorphic models are in the same package. - // In this scenario, the logic for polymorphism is that the defining model has a package-private, non-final - // field for the discriminator which is set by either the deserialization logic or the constructor. - if (callToJsonSharedForParentProperties && property.isPolymorphicDiscriminator() - && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage() - && !propertiesManager.getModel().isPolymorphicDiscriminatorDefinedByModel()) { - return; + if (isManagementErrorSubclass.test(model)) { + addGeneratedAnnotation.accept(classBlock); + classBlock.staticMethod(JavaVisibility.Private, model.getName() + " " + + READ_MANAGEMENT_ERROR_METHOD_NAME + "(JsonReader jsonReader) throws IOException", + methodBlock -> readJsonObjectMethodBody(methodBlock, this::writeFromJsonDeserialization0)); + } } + } - serializeJsonProperty.accept(property, false); - }; - - propertiesManager.forEachRequiredProperty(wrappedSerializer); - propertiesManager.forEachSetterProperty(wrappedSerializer); - - handleFlattenedPropertiesSerialization(methodBlock, propertiesManager.getJsonFlattenedPropertiesTree(), false, - callToJsonSharedForParentProperties); - - if (getAdditionalPropertiesPropertyInModelOrFromSuper(propertiesManager) != null) { - String additionalPropertiesAccessExpr = propertiesManager.getAdditionalProperties() != null - ? propertiesManager.getAdditionalProperties().getName() - : propertiesManager.getSuperAdditionalPropertiesProperty().getGetterName() + "()"; - IType wireType = propertiesManager.getAdditionalProperties() != null - ? propertiesManager.getAdditionalProperties().getWireType() - : propertiesManager.getSuperAdditionalPropertiesProperty().getWireType(); - - methodBlock.ifBlock(additionalPropertiesAccessExpr + " != null", ifAction -> { - IType valueType = ((MapType) wireType).getValueType().asNullable(); - ifAction.line("for (Map.Entry additionalProperty : %s.entrySet()) {", valueType, additionalPropertiesAccessExpr); - ifAction.indent(() -> { - if (valueType == ClassType.BINARY_DATA) { - // Special handling for BinaryData - ifAction.line("jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue() == null ? null : additionalProperty.getValue().toObject(Object.class));"); - } else { - ifAction.line("jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue());"); - } - }); - ifAction.line("}"); + /** + * write toJson() method. + *

+ * If it is a JsonMergePatch model, toJson() should first check jsonMergePatch flag value and then do + * serialization accordingly. + * + * @param classBlock The class block to write the toJson method to. + * @param isJsonMergePatch Whether the serialization is for a JSON merge patch. + */ + private void writeToJson(JavaClass classBlock, boolean isJsonMergePatch) { + boolean callToJsonSharedForParentProperties = !isJsonMergePatch + && model.isAllPolymorphicModelsInSamePackage() && !CoreUtils.isNullOrEmpty(model.getParentModelName()); + boolean callToJsonSharedForThisProperties = !isJsonMergePatch && model.isAllPolymorphicModelsInSamePackage() + && model.isPolymorphicParent(); + + classBlock.javadocComment(JavaJavadocComment::inheritDoc); + addGeneratedAnnotation.accept(classBlock); + classBlock.annotation("Override"); + classBlock.publicMethod("JsonWriter toJson(JsonWriter jsonWriter) throws IOException", methodBlock -> { + if (isJsonMergePatch) { + // If the model is the root parent use the JSON merge patch serialization tracking property directly, + // otherwise use the access helper to determine whether to use JSON merge patch serialization. + ClientModel rootParent = ClientModelUtil.getRootParent(model); + String ifStatement = (rootParent == model) + ? "jsonMergePatch" + : JSON_MERGE_PATCH_HELPER_CLASS_NAME + ".get" + rootParent.getName() + + "Accessor().isJsonMergePatch(this)"; + + methodBlock.ifBlock(ifStatement, ifBlock -> ifBlock.methodReturn("toJsonMergePatch(jsonWriter)")) + .elseBlock(elseBlock -> serializeJsonProperties(methodBlock, false, false, false)); + } else { + // For polymorphic models, when all models are contained in the same package, a package-private 'toJsonShared' + // method will be generated by parent models that handles serialization of properties defined by the parent + // model. + // So, if we have that case, we skip serializing the properties defined by the parent model(s) and instead call + // the 'toJsonShared' method to serialize those properties. And, for properties defined by this model, if the + // model is a parent model generate a 'toJsonShared' method to serialize those properties. + // + // At this time, due to implementation complexity and the low value add, JSON merge patch serialization won't + // support 'toJsonMergePatchShared'. JSON merge patch serialization has low usage, and combined with the low + // usage of polymorphism as well, there isn't a large expectation for this feature. + serializeJsonProperties(methodBlock, false, callToJsonSharedForParentProperties, + callToJsonSharedForThisProperties); + } }); - } - } - /** - * Serializes a non-flattened, non-additional properties JSON property. - *

- * If the JSON property needs to be flattened or is additional properties this is a no-op as those require special - * handling that will occur later. - * - * @param methodBlock The method handling serialization. - * @param property The property being serialized. - * @param serializedName The serialized JSON property name. Generally, this is just the {@code property property's} - * serialized name but if a flattened property is being serialized it'll be the last segment of the flattened JSON - * name. - * @param fromSuperType Whether the property is defined by a super type of the model. If the property is declared by - * a super type a getter method will be used to retrieve the value instead of accessing the field directly. - * @param ignoreFlattening Whether flattened properties should be skipped. Will only be false when handling the - * terminal location of a flattened structure. - * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. - */ - private static void serializeJsonProperty(JavaBlock methodBlock, ClientModelProperty property, - String serializedName, boolean fromSuperType, boolean ignoreFlattening, boolean isJsonMergePatch) { - if ((ignoreFlattening && property.getNeedsFlatten()) || property.isAdditionalProperties()) { - // Property will be handled later by flattened or additional properties serialization. - return; - } + // If this model is defining a 'toJsonShared' method, write it. + if (callToJsonSharedForThisProperties) { + classBlock.packagePrivateMethod("void toJsonShared(JsonWriter jsonWriter) throws IOException", + methodBlock -> { + if (callToJsonSharedForParentProperties) { + methodBlock.line("super.toJsonShared(jsonWriter);"); + } - if (property.isReadOnly() && !property.isPolymorphicDiscriminator()) { - // Non-polymorphic discriminator, readonly properties are never serialized. - return; + serializeThisJsonProperties( + (property, fromSuper) -> serializeJsonProperty(methodBlock, property, + property.getSerializedName(), fromSuper, true, false), methodBlock, + callToJsonSharedForParentProperties); + }); + } } - if (isJsonMergePatch) { - if (!property.isPolymorphicDiscriminator()) { - methodBlock.ifBlock("updatedProperties.contains(\"" + property.getName() + "\")", codeBlock -> { - if (property.getClientType().isNullable()) { - codeBlock.ifBlock(getPropertyGetterStatement(property, fromSuperType) + " == null", - ifBlock -> ifBlock.line("jsonWriter.writeNullField(\"" + property.getSerializedName() + "\");")) - .elseBlock(elseBlock -> serializeJsonProperty(codeBlock, property, serializedName, fromSuperType, true)); - } else { - serializeJsonProperty(codeBlock, property, serializedName, fromSuperType, true, false); - } - }); - } else { - serializeJsonProperty(methodBlock, property, serializedName, fromSuperType, true); + /** + * Serializes the properties of a model to JSON. + * + * @param methodBlock The method block to write the serialization method to. + * @param isJsonMergePatch Whether the serialization is for a JSON merge patch. + */ + private void serializeJsonProperties(JavaBlock methodBlock, boolean isJsonMergePatch, + boolean callToJsonSharedForParentProperties, boolean callToJsonSharedForThisProperties) { + methodBlock.line("jsonWriter.writeStartObject();"); + + // If we're calling toJsonShared for this model and for parent properties, this is an early out. + if (callToJsonSharedForParentProperties && callToJsonSharedForThisProperties) { + methodBlock.line("toJsonShared(jsonWriter);"); + methodBlock.methodReturn("jsonWriter.writeEndObject()"); + return; } - } else { - serializeJsonProperty(methodBlock, property, serializedName, fromSuperType, false); - } - } - /** - * Serializes a non-flattened, non-additional properties JSON property. - *

- * If the JSON property needs to be flattened or is additional properties this is a no-op as those require special - * handling that will occur later. - * - * @param methodBlock The method handling serialization. - * @param property The property being serialized. - * @param serializedName The serialized JSON property name. Generally, this is just the {@code property property's} - * serialized name but if a flattened property is being serialized it'll be the last segment of the flattened JSON - * name. - * @param fromSuperType Whether the property is defined by a super type of the model. If the property is declared by - * a super type a getter method will be used to retrieve the value instead of accessing the field directly. - * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. - */ - private static void serializeJsonProperty(JavaBlock methodBlock, ClientModelProperty property, - String serializedName, boolean fromSuperType, boolean isJsonMergePatch) { - IType clientType = property.getClientType(); - IType wireType = property.getWireType(); - String propertyValueGetter = getPropertyGetterStatement(property, fromSuperType); - - // Attempt to determine whether the wire type is simple serialization. - // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. - String fieldSerializationMethod = wireType.jsonSerializationMethodCall("jsonWriter", serializedName, - propertyValueGetter, isJsonMergePatch); - if (wireType == ClassType.BINARY_DATA) { - // Special handling for BinaryData (instead of using "serializationMethodBase" and "serializationValueGetterModifier") - // The reason is that some backend would fail the request on "null" value (e.g. OpenAI) - String writeBinaryDataExpr = "jsonWriter.writeUntypedField(\"" + serializedName + "\", " + propertyValueGetter + ".toObject(Object.class));"; - if (!property.isRequired()) { - methodBlock.ifBlock(propertyValueGetter + " != null", ifAction -> ifAction.line(writeBinaryDataExpr)); + BiConsumer serializeJsonProperty + = (property, fromSuper) -> serializeJsonProperty(methodBlock, property, property.getSerializedName(), + fromSuper, true, isJsonMergePatch); + + if (callToJsonSharedForParentProperties) { + methodBlock.line("toJsonShared(jsonWriter);"); } else { - methodBlock.line(writeBinaryDataExpr); - } - } else if (fieldSerializationMethod != null) { - if (isJsonMergePatch && wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { - methodBlock.line("JsonMergePatchHelper.get" + clientType.toString() + "Accessor().prepareModelForJsonMergePatch(" + propertyValueGetter + ", true);"); + serializeParentJsonProperties(serializeJsonProperty); } - if (fromSuperType && clientType != wireType && clientType.isNullable()) { - // If the property is from a super type and the client type is different from the wire type then a null - // check is required to prevent a NullPointerException when converting the value. - methodBlock.ifBlock(property.getGetterName() + "() != null", - ifAction -> ifAction.line(fieldSerializationMethod + ";")); + + if (callToJsonSharedForThisProperties) { + methodBlock.line("toJsonShared(jsonWriter);"); } else { - methodBlock.line(fieldSerializationMethod + ";"); - } - if (isJsonMergePatch && wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { - methodBlock.line("JsonMergePatchHelper.get" + clientType.toString() + "Accessor().prepareModelForJsonMergePatch(" + propertyValueGetter + ", false);"); + serializeThisJsonProperties(serializeJsonProperty, methodBlock, callToJsonSharedForParentProperties); } - } else if (wireType == ClassType.OBJECT) { - methodBlock.line("jsonWriter.writeUntypedField(\"" + serializedName + "\", " + propertyValueGetter + ");"); - } else if (wireType instanceof IterableType) { - serializeJsonContainerProperty(methodBlock, "writeArrayField", wireType, ((IterableType) wireType).getElementType(), - serializedName, propertyValueGetter, 0, isJsonMergePatch); - } else if (wireType instanceof MapType) { - // Assumption is that the key type for the Map is a String. This may not always hold true and when that - // becomes reality this will need to be reworked to handle that case. - serializeJsonContainerProperty(methodBlock, "writeMapField", wireType, ((MapType) wireType).getValueType(), - serializedName, propertyValueGetter, 0, isJsonMergePatch); - } else { - // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. - throw new RuntimeException("Unknown wire type " + wireType + " in serialization. Need to add support for it."); - } - } - /** - * Helper function to get property getter statement. - *

- * If the value is from super type, then we will return "getProperty()", otherwise, return "this.property" - * - * @param property The property being serialized. - * @param fromSuperType Whether the property is defined by a super type of the model. - * @return The property getter statement. - */ - private static String getPropertyGetterStatement(ClientModelProperty property, boolean fromSuperType) { - IType clientType = property.getClientType(); - IType wireType = property.getWireType(); - if (fromSuperType) { - return (clientType != wireType) - ? wireType.convertFromClientType(property.getGetterName() + "()") : property.getGetterName() + "()"; - } else { - return "this." + property.getName(); + methodBlock.methodReturn("jsonWriter.writeEndObject()"); } - } - /** - * Helper method to serialize a JSON container property (such as {@link List} and {@link Map}). - * - * @param methodBlock The method handling serialization. - * @param utilityMethod The method aiding in the serialization of the container. - * @param containerType The container type. - * @param elementType The element type for the container, for a {@link List} this is the element type and for a - * {@link Map} this is the value type. - * @param serializedName The serialized property name. - * @param propertyValueGetter The property or property getter for the field being serialized. - * @param depth Depth of recursion for container types, such as {@code Map>} would be 0 when - * {@code Map} is being handled and then 1 when {@code List} is being handled. - * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. - */ - private static void serializeJsonContainerProperty(JavaBlock methodBlock, String utilityMethod, IType containerType, - IType elementType, String serializedName, String propertyValueGetter, int depth, boolean isJsonMergePatch) { - String callingWriterName = depth == 0 ? "jsonWriter" : (depth == 1) ? "writer" : "writer" + (depth - 1); - String lambdaWriterName = depth == 0 ? "writer" : "writer" + depth; - String elementName = depth == 0 ? "element" : "element" + depth; - String valueSerializationMethod = elementType.jsonSerializationMethodCall(lambdaWriterName, null, elementName, - isJsonMergePatch); - String serializeValue = depth == 0 ? propertyValueGetter - : ((depth == 1) ? "element" : "element" + (depth - 1)); - - // First call into serialize container property will need to write the property name. Subsequent calls must - // not write the property name as that would be invalid, ex "myList":["myList":["innerListElement"]]. - if (depth == 0) { - // Container property shouldn't be written if it's null. - methodBlock.line("%s.%s(\"%s\", %s, (%s, %s) -> ", callingWriterName, utilityMethod, serializedName, - serializeValue, lambdaWriterName, elementName); - } else { - // But the inner container should be written if it's null. - methodBlock.line("%s.%s(%s, (%s, %s) -> ", callingWriterName, utilityMethod, serializeValue, - lambdaWriterName, elementName); - } + private void serializeParentJsonProperties(BiConsumer serializeJsonProperty) { + model.getParentPolymorphicDiscriminators() + .forEach(discriminator -> serializeJsonProperty.accept(discriminator, false)); + propertiesManager.forEachSuperRequiredProperty(property -> serializeJsonProperty.accept(property, true)); + propertiesManager.forEachSuperSetterProperty(property -> serializeJsonProperty.accept(property, true)); + } + + private void serializeThisJsonProperties(BiConsumer serializeJsonProperty, + JavaBlock methodBlock, boolean callToJsonSharedForParentProperties) { + Consumer wrappedSerializer = property -> { + // Skip serializing the polymorphic discriminator if 'toJsonShared' is called to serialize properties + // defined by the parent model(s), the polymorphic discriminator isn't defined by this property, and + // all polymorphic models are in the same package. + // In this scenario, the logic for polymorphism is that the defining model has a package-private, non-final + // field for the discriminator which is set by either the deserialization logic or the constructor. + if (callToJsonSharedForParentProperties && property.isPolymorphicDiscriminator() + && model.isAllPolymorphicModelsInSamePackage() + && !model.isPolymorphicDiscriminatorDefinedByModel()) { + return; + } + + serializeJsonProperty.accept(property, false); + }; + + propertiesManager.forEachRequiredProperty(wrappedSerializer); + propertiesManager.forEachSetterProperty(wrappedSerializer); - methodBlock.indent(() -> { - if (valueSerializationMethod != null) { - if (isJsonMergePatch && containerType instanceof MapType) { - methodBlock.block("", codeBlock -> codeBlock.ifBlock(elementName + "!= null", ifBlock -> { - if (elementType instanceof ClassType && ((ClassType) elementType).isSwaggerType()) { - methodBlock.line("JsonMergePatchHelper.get" + ((ClassType) elementType).getName() + "Accessor().prepareModelForJsonMergePatch(" + elementName + ", true);"); + handleFlattenedPropertiesSerialization(methodBlock, callToJsonSharedForParentProperties); + + if (getAdditionalPropertiesPropertyInModelOrFromSuper() != null) { + String additionalPropertiesAccessExpr = propertiesManager.getAdditionalProperties() != null + ? propertiesManager.getAdditionalProperties().getName() + : propertiesManager.getSuperAdditionalPropertiesProperty().getGetterName() + "()"; + IType wireType = propertiesManager.getAdditionalProperties() != null + ? propertiesManager.getAdditionalProperties().getWireType() + : propertiesManager.getSuperAdditionalPropertiesProperty().getWireType(); + + methodBlock.ifBlock(additionalPropertiesAccessExpr + " != null", ifAction -> { + IType valueType = ((MapType) wireType).getValueType().asNullable(); + ifAction.line("for (Map.Entry additionalProperty : %s.entrySet()) {", valueType, + additionalPropertiesAccessExpr); + ifAction.indent(() -> { + if (valueType == ClassType.BINARY_DATA) { + // Special handling for BinaryData + ifAction.line( + "jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue() == null ? null : additionalProperty.getValue().toObject(Object.class));"); + } else { + ifAction.line( + "jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue());"); } - ifBlock.line(valueSerializationMethod + ";"); - if (elementType instanceof ClassType && ((ClassType) elementType).isSwaggerType()) { - methodBlock.line("JsonMergePatchHelper.get" + ((ClassType) elementType).getName() + "Accessor().prepareModelForJsonMergePatch(" + elementName + ", false);"); + }); + ifAction.line("}"); + }); + } + } + + /** + * Serializes a non-flattened, non-additional properties JSON property. + *

+ * If the JSON property needs to be flattened or is additional properties this is a no-op as those require + * special handling that will occur later. + * + * @param methodBlock The method handling serialization. + * @param property The property being serialized. + * @param serializedName The serialized JSON property name. Generally, this is just the + * {@code property property's} serialized name but if a flattened property is being serialized it'll be the last + * segment of the flattened JSON name. + * @param fromSuperType Whether the property is defined by a super type of the model. If the property is + * declared by a super type a getter method will be used to retrieve the value instead of accessing the field + * directly. + * @param ignoreFlattening Whether flattened properties should be skipped. Will only be false when handling the + * terminal location of a flattened structure. + * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. + */ + private static void serializeJsonProperty(JavaBlock methodBlock, ClientModelProperty property, + String serializedName, boolean fromSuperType, boolean ignoreFlattening, boolean isJsonMergePatch) { + if ((ignoreFlattening && property.getNeedsFlatten()) || property.isAdditionalProperties()) { + // Property will be handled later by flattened or additional properties serialization. + return; + } + + if (property.isReadOnly() && !property.isPolymorphicDiscriminator()) { + // Non-polymorphic discriminator, readonly properties are never serialized. + return; + } + + if (isJsonMergePatch) { + if (!property.isPolymorphicDiscriminator()) { + methodBlock.ifBlock("updatedProperties.contains(\"" + property.getName() + "\")", codeBlock -> { + if (property.getClientType().isNullable()) { + codeBlock.ifBlock(getPropertyGetterStatement(property, fromSuperType) + " == null", + ifBlock -> ifBlock.line( + "jsonWriter.writeNullField(\"" + property.getSerializedName() + "\");")) + .elseBlock(elseBlock -> serializeJsonProperty(codeBlock, property, serializedName, + fromSuperType, true)); + } else { + serializeJsonProperty(codeBlock, property, serializedName, fromSuperType, true, false); } - }).elseBlock(elseBlock -> elseBlock.line(lambdaWriterName + ".writeNull();"))); + }); + } else { + serializeJsonProperty(methodBlock, property, serializedName, fromSuperType, true); + } + } else { + serializeJsonProperty(methodBlock, property, serializedName, fromSuperType, false); + } + } + + /** + * Serializes a non-flattened, non-additional properties JSON property. + *

+ * If the JSON property needs to be flattened or is additional properties this is a no-op as those require + * special handling that will occur later. + * + * @param methodBlock The method handling serialization. + * @param property The property being serialized. + * @param serializedName The serialized JSON property name. Generally, this is just the + * {@code property property's} serialized name but if a flattened property is being serialized it'll be the last + * segment of the flattened JSON name. + * @param fromSuperType Whether the property is defined by a super type of the model. If the property is + * declared by a super type a getter method will be used to retrieve the value instead of accessing the field + * directly. + * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. + */ + private static void serializeJsonProperty(JavaBlock methodBlock, ClientModelProperty property, + String serializedName, boolean fromSuperType, boolean isJsonMergePatch) { + IType clientType = property.getClientType(); + IType wireType = property.getWireType(); + String propertyValueGetter = getPropertyGetterStatement(property, fromSuperType); + + // Attempt to determine whether the wire type is simple serialization. + // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. + String fieldSerializationMethod = wireType.jsonSerializationMethodCall("jsonWriter", serializedName, + propertyValueGetter, isJsonMergePatch); + if (wireType == ClassType.BINARY_DATA) { + // Special handling for BinaryData (instead of using "serializationMethodBase" and "serializationValueGetterModifier") + // The reason is that some backend would fail the request on "null" value (e.g. OpenAI) + String writeBinaryDataExpr = "jsonWriter.writeUntypedField(\"" + serializedName + "\", " + + propertyValueGetter + ".toObject(Object.class));"; + if (!property.isRequired()) { + methodBlock.ifBlock(propertyValueGetter + " != null", + ifAction -> ifAction.line(writeBinaryDataExpr)); + } else { + methodBlock.line(writeBinaryDataExpr); + } + } else if (fieldSerializationMethod != null) { + if (isJsonMergePatch && wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { + methodBlock.line( + "JsonMergePatchHelper.get" + clientType.toString() + "Accessor().prepareModelForJsonMergePatch(" + + propertyValueGetter + ", true);"); + } + if (fromSuperType && clientType != wireType && clientType.isNullable()) { + // If the property is from a super type and the client type is different from the wire type then a null + // check is required to prevent a NullPointerException when converting the value. + methodBlock.ifBlock(property.getGetterName() + "() != null", + ifAction -> ifAction.line(fieldSerializationMethod + ";")); } else { - methodBlock.line(valueSerializationMethod); + methodBlock.line(fieldSerializationMethod + ";"); } - } else if (elementType == ClassType.OBJECT) { - methodBlock.line(lambdaWriterName + ".writeUntyped(" + elementName + ")"); - } else if (elementType instanceof IterableType) { - serializeJsonContainerProperty(methodBlock, "writeArray", elementType, ((IterableType) elementType).getElementType(), - serializedName, propertyValueGetter, depth + 1, isJsonMergePatch); - } else if (elementType instanceof MapType) { + if (isJsonMergePatch && wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { + methodBlock.line( + "JsonMergePatchHelper.get" + clientType.toString() + "Accessor().prepareModelForJsonMergePatch(" + + propertyValueGetter + ", false);"); + } + } else if (wireType == ClassType.OBJECT) { + methodBlock.line( + "jsonWriter.writeUntypedField(\"" + serializedName + "\", " + propertyValueGetter + ");"); + } else if (wireType instanceof IterableType) { + serializeJsonContainerProperty(methodBlock, "writeArrayField", wireType, + ((IterableType) wireType).getElementType(), serializedName, propertyValueGetter, 0, + isJsonMergePatch); + } else if (wireType instanceof MapType) { // Assumption is that the key type for the Map is a String. This may not always hold true and when that // becomes reality this will need to be reworked to handle that case. - serializeJsonContainerProperty(methodBlock, "writeMap", elementType, ((MapType) elementType).getValueType(), - serializedName, propertyValueGetter, depth + 1, isJsonMergePatch); - } else if (elementType == ClassType.BINARY_DATA) { - methodBlock.line(lambdaWriterName + ".writeUntyped(" + elementName + ")"); + serializeJsonContainerProperty(methodBlock, "writeMapField", wireType, + ((MapType) wireType).getValueType(), serializedName, propertyValueGetter, 0, isJsonMergePatch); } else { - throw new RuntimeException("Unknown value type " + elementType + " in " + containerType - + " serialization. Need to add support for it."); + // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. + throw new RuntimeException( + "Unknown wire type " + wireType + " in serialization. Need to add support for it."); } - }); - - if (depth > 0) { - methodBlock.line(")"); - } else { - methodBlock.line(");"); } - } - /** - * Helper method to serialize flattened properties in a model. - *

- * Flattened properties are unique as for each level of flattening they'll create a JSON sub-object. But before a - * sub-object is created any field needs to be checked for either being a primitive value or non-null. Primitive - * values are usually serialized no matter their value so those will automatically trigger the JSON sub-object to be - * created, nullable values will be checked for being non-null. - *

- * In addition to primitive or non-null checking fields, all properties from the same JSON sub-object must be - * written at the same time to prevent an invalid JSON structure. For example if a model has three flattened - * properties with JSON paths "im.flattened", "im.deeper.flattened", and "im.deeper.flattenedtoo" this will create - * the following structure: - * - *

-     * im -> flattened
-     *     | deeper -> flattened
-     *               | flattenedtoo
-     * 
- * - * So, "im.deeper.flattened" and "im.deeper.flattenedtoo" will need to be serialized at the same time to get the - * correct JSON where there is only one "im: deeper" JSON sub-object. - * - * @param methodBlock The method handling serialization. - * @param flattenedProperties The flattened properties structure. - * @param isJsonMergePatch Whether the serialization is for a JSON merge patch model. - */ - private static void handleFlattenedPropertiesSerialization(JavaBlock methodBlock, - JsonFlattenedPropertiesTree flattenedProperties, boolean isJsonMergePatch, - boolean callToJsonSharedForParentProperties) { - // The initial call to handle flattened properties is using the base node which is just a holder. - for (JsonFlattenedPropertiesTree flattened : flattenedProperties.getChildrenNodes().values()) { - handleFlattenedPropertiesSerializationHelper(methodBlock, flattened, isJsonMergePatch, - callToJsonSharedForParentProperties); + /** + * Helper function to get property getter statement. + *

+ * If the value is from super type, then we will return "getProperty()", otherwise, return "this.property" + * + * @param property The property being serialized. + * @param fromSuperType Whether the property is defined by a super type of the model. + * @return The property getter statement. + */ + private static String getPropertyGetterStatement(ClientModelProperty property, boolean fromSuperType) { + IType clientType = property.getClientType(); + IType wireType = property.getWireType(); + if (fromSuperType) { + return (clientType != wireType) + ? wireType.convertFromClientType(property.getGetterName() + "()") + : property.getGetterName() + "()"; + } else { + return "this." + property.getName(); + } } - } - private static void handleFlattenedPropertiesSerializationHelper(JavaBlock methodBlock, - JsonFlattenedPropertiesTree flattenedProperties, boolean isJsonMergePatch, - boolean callToJsonSharedForParentProperties) { - ClientModelPropertyWithMetadata flattenedProperty = flattenedProperties.getProperty(); - if (flattenedProperty != null) { - // This is a terminal location, only need to add property serialization. - serializeJsonProperty(methodBlock, flattenedProperty.getProperty(), flattenedProperties.getNodeName(), - flattenedProperty.isFromSuperClass(), false, isJsonMergePatch); - } else { - // Otherwise this is an intermediate location. - // Check for either any of the properties in this subtree being primitives or add an if block checking that - // any of the properties are non-null. - List propertiesInFlattenedGroup = - getClientModelPropertiesInJsonTree(flattenedProperties); - boolean hasPrimitivePropertyInGroup = false; - boolean allPropertiesInGroupFromParent = true; - for (ClientModelPropertyWithMetadata propertyInFlattenedGroup : propertiesInFlattenedGroup) { - hasPrimitivePropertyInGroup |= propertyInFlattenedGroup.getProperty().getWireType() instanceof PrimitiveType; - allPropertiesInGroupFromParent &= propertyInFlattenedGroup.isFromSuperClass(); + /** + * Helper method to serialize a JSON container property (such as {@link List} and {@link Map}). + * + * @param methodBlock The method handling serialization. + * @param utilityMethod The method aiding in the serialization of the container. + * @param containerType The container type. + * @param elementType The element type for the container, for a {@link List} this is the element type and for a + * {@link Map} this is the value type. + * @param serializedName The serialized property name. + * @param propertyValueGetter The property or property getter for the field being serialized. + * @param depth Depth of recursion for container types, such as {@code Map>} would be 0 + * when {@code Map} is being handled and then 1 when {@code List} is being handled. + * @param isJsonMergePatch Whether the serialization is for a JSON Merge Patch model. + */ + private static void serializeJsonContainerProperty(JavaBlock methodBlock, String utilityMethod, + IType containerType, IType elementType, String serializedName, String propertyValueGetter, int depth, + boolean isJsonMergePatch) { + String callingWriterName = depth == 0 ? "jsonWriter" : (depth == 1) ? "writer" : "writer" + (depth - 1); + String lambdaWriterName = depth == 0 ? "writer" : "writer" + depth; + String elementName = depth == 0 ? "element" : "element" + depth; + String valueSerializationMethod = elementType.jsonSerializationMethodCall(lambdaWriterName, null, + elementName, isJsonMergePatch); + String serializeValue = depth == 0 + ? propertyValueGetter + : ((depth == 1) ? "element" : "element" + (depth - 1)); + + // First call into serialize container property will need to write the property name. Subsequent calls must + // not write the property name as that would be invalid, ex "myList":["myList":["innerListElement"]]. + if (depth == 0) { + // Container property shouldn't be written if it's null. + methodBlock.line("%s.%s(\"%s\", %s, (%s, %s) -> ", callingWriterName, utilityMethod, serializedName, + serializeValue, lambdaWriterName, elementName); + } else { + // But the inner container should be written if it's null. + methodBlock.line("%s.%s(%s, (%s, %s) -> ", callingWriterName, utilityMethod, serializeValue, + lambdaWriterName, elementName); } - if (callToJsonSharedForParentProperties && allPropertiesInGroupFromParent) { - // If all properties in the flattened group are from the parent model, then the call to the parent's - // 'toJsonShared' method will serialize the properties, skip writing serialization logic for this - // method. - return; + methodBlock.indent(() -> { + if (valueSerializationMethod != null) { + if (isJsonMergePatch && containerType instanceof MapType) { + methodBlock.block("", codeBlock -> codeBlock.ifBlock(elementName + "!= null", ifBlock -> { + if (elementType instanceof ClassType && ((ClassType) elementType).isSwaggerType()) { + methodBlock.line("JsonMergePatchHelper.get" + ((ClassType) elementType).getName() + + "Accessor().prepareModelForJsonMergePatch(" + elementName + ", true);"); + } + ifBlock.line(valueSerializationMethod + ";"); + if (elementType instanceof ClassType && ((ClassType) elementType).isSwaggerType()) { + methodBlock.line("JsonMergePatchHelper.get" + ((ClassType) elementType).getName() + + "Accessor().prepareModelForJsonMergePatch(" + elementName + ", false);"); + } + }).elseBlock(elseBlock -> elseBlock.line(lambdaWriterName + ".writeNull();"))); + } else { + methodBlock.line(valueSerializationMethod); + } + } else if (elementType == ClassType.OBJECT) { + methodBlock.line(lambdaWriterName + ".writeUntyped(" + elementName + ")"); + } else if (elementType instanceof IterableType) { + serializeJsonContainerProperty(methodBlock, "writeArray", elementType, + ((IterableType) elementType).getElementType(), serializedName, propertyValueGetter, depth + 1, + isJsonMergePatch); + } else if (elementType instanceof MapType) { + // Assumption is that the key type for the Map is a String. This may not always hold true and when that + // becomes reality this will need to be reworked to handle that case. + serializeJsonContainerProperty(methodBlock, "writeMap", elementType, + ((MapType) elementType).getValueType(), serializedName, propertyValueGetter, depth + 1, + isJsonMergePatch); + } else if (elementType == ClassType.BINARY_DATA) { + methodBlock.line(lambdaWriterName + ".writeUntyped(" + elementName + ")"); + } else { + throw new RuntimeException("Unknown value type " + elementType + " in " + containerType + + " serialization. Need to add support for it."); + } + }); + + if (depth > 0) { + methodBlock.line(")"); + } else { + methodBlock.line(");"); } + } - if (hasPrimitivePropertyInGroup) { - // Simple case where the flattened group has a primitive type where non-null checking doesn't need - // to be done. - methodBlock.line("jsonWriter.writeStartObject(\"" + flattenedProperties.getNodeName() + "\");"); - for (JsonFlattenedPropertiesTree flattened : flattenedProperties.getChildrenNodes().values()) { - handleFlattenedPropertiesSerializationHelper(methodBlock, flattened, isJsonMergePatch, - callToJsonSharedForParentProperties); - } - methodBlock.line("jsonWriter.writeEndObject();"); + /** + * Helper method to serialize flattened properties in a model. + *

+ * Flattened properties are unique as for each level of flattening they'll create a JSON sub-object. But before + * a sub-object is created any field needs to be checked for either being a primitive value or non-null. + * Primitive values are usually serialized no matter their value so those will automatically trigger the JSON + * sub-object to be created, nullable values will be checked for being non-null. + *

+ * In addition to primitive or non-null checking fields, all properties from the same JSON sub-object must be + * written at the same time to prevent an invalid JSON structure. For example if a model has three flattened + * properties with JSON paths "im.flattened", "im.deeper.flattened", and "im.deeper.flattenedtoo" this will + * create the following structure: + * + *

+         * im -> flattened
+         *     | deeper -> flattened
+         *               | flattenedtoo
+         * 
+ * + * So, "im.deeper.flattened" and "im.deeper.flattenedtoo" will need to be serialized at the same time to get the + * correct JSON where there is only one "im: deeper" JSON sub-object. + * + * @param methodBlock The method handling serialization. + */ + private void handleFlattenedPropertiesSerialization(JavaBlock methodBlock, + boolean callToJsonSharedForParentProperties) { + // The initial call to handle flattened properties is using the base node which is just a holder. + for (JsonFlattenedPropertiesTree flattened : propertiesManager.getJsonFlattenedPropertiesTree().getChildrenNodes().values()) { + handleFlattenedPropertiesSerializationHelper(methodBlock, flattened, false, + callToJsonSharedForParentProperties); + } + } + + private static void handleFlattenedPropertiesSerializationHelper(JavaBlock methodBlock, + JsonFlattenedPropertiesTree flattenedProperties, boolean isJsonMergePatch, + boolean callToJsonSharedForParentProperties) { + ClientModelPropertyWithMetadata flattenedProperty = flattenedProperties.getProperty(); + if (flattenedProperty != null) { + // This is a terminal location, only need to add property serialization. + serializeJsonProperty(methodBlock, flattenedProperty.getProperty(), flattenedProperties.getNodeName(), + flattenedProperty.isFromSuperClass(), false, isJsonMergePatch); } else { - // Complex case where all properties in the flattened group are nullable and a check needs to be made - // if any value is non-null. - String condition = propertiesInFlattenedGroup.stream() - .map(property -> (property.isFromSuperClass()) - ? property.getProperty().getGetterName() + "() != null" - : property.getProperty().getName() + " != null") - .collect(Collectors.joining(" || ")); - - methodBlock.ifBlock(condition, ifAction -> { - ifAction.line("jsonWriter.writeStartObject(\"" + flattenedProperties.getNodeName() + "\");"); + // Otherwise this is an intermediate location. + // Check for either any of the properties in this subtree being primitives or add an if block checking that + // any of the properties are non-null. + List propertiesInFlattenedGroup = getClientModelPropertiesInJsonTree( + flattenedProperties); + boolean hasPrimitivePropertyInGroup = false; + boolean allPropertiesInGroupFromParent = true; + for (ClientModelPropertyWithMetadata propertyInFlattenedGroup : propertiesInFlattenedGroup) { + hasPrimitivePropertyInGroup |= propertyInFlattenedGroup.getProperty() + .getWireType() instanceof PrimitiveType; + allPropertiesInGroupFromParent &= propertyInFlattenedGroup.isFromSuperClass(); + } + + if (callToJsonSharedForParentProperties && allPropertiesInGroupFromParent) { + // If all properties in the flattened group are from the parent model, then the call to the parent's + // 'toJsonShared' method will serialize the properties, skip writing serialization logic for this + // method. + return; + } + + if (hasPrimitivePropertyInGroup) { + // Simple case where the flattened group has a primitive type where non-null checking doesn't need + // to be done. + methodBlock.line("jsonWriter.writeStartObject(\"" + flattenedProperties.getNodeName() + "\");"); for (JsonFlattenedPropertiesTree flattened : flattenedProperties.getChildrenNodes().values()) { - handleFlattenedPropertiesSerializationHelper(ifAction, flattened, isJsonMergePatch, + handleFlattenedPropertiesSerializationHelper(methodBlock, flattened, isJsonMergePatch, callToJsonSharedForParentProperties); } - ifAction.line("jsonWriter.writeEndObject();"); - }); + methodBlock.line("jsonWriter.writeEndObject();"); + } else { + // Complex case where all properties in the flattened group are nullable and a check needs to be made + // if any value is non-null. + String condition = propertiesInFlattenedGroup.stream() + .map(property -> (property.isFromSuperClass()) ? property.getProperty().getGetterName() + + "() != null" : property.getProperty().getName() + " != null") + .collect(Collectors.joining(" || ")); + + methodBlock.ifBlock(condition, ifAction -> { + ifAction.line("jsonWriter.writeStartObject(\"" + flattenedProperties.getNodeName() + "\");"); + for (JsonFlattenedPropertiesTree flattened : flattenedProperties.getChildrenNodes().values()) { + handleFlattenedPropertiesSerializationHelper(ifAction, flattened, isJsonMergePatch, + callToJsonSharedForParentProperties); + } + ifAction.line("jsonWriter.writeEndObject();"); + }); + } } } - } - - /* - * Writes the fromJson(JsonReader) implementation. - */ - private void writeFromJson(JavaClass classBlock, ClientModel model, - ClientModelPropertiesManager propertiesManager, JavaSettings settings, - Consumer addGeneratedAnnotation) { - // All classes will create a public fromJson(JsonReader) method that initiates reading. - // How the implementation looks depends on whether the type is a super type, subtype, both, or is a - // stand-alone type. - // - // Intermediate types, those that are both a super type and subtype, will pass null as the type discriminator - // value. This is done as super types are written to only support themselves or their subtypes, passing a - // discriminator into its own super type would confuse this scenario. For example, one of the test Swaggers - // generates the following hierarchy - // - // Fish - // Salmon Shark - // SmartSalmon Sawshark GoblinShark Cookiecuttershark - // - // If Salmon called into Fish with its discriminator and an error occurred it would mention the Shark subtypes - // as potential legal values for deserialization, confusing the Salmon deserializer. So, calling into Salmon - // will only attempt to handle Salmon and SmartSalmon, and same goes for Shark with Shark, Sawshark, - // GoblinShark, and Cookiecuttershark. It's only Fish that will handle all subtypes, as this is the most generic - // super type. This also creates a well-defined bounds for code generation in regard to type hierarchies. - // - // In a real scenario someone deserializing to Salmon should have an exception about discriminator types - // if the JSON payload is a Shark and not get a ClassCastException as it'd be more confusing on why a Shark - // was trying to be converted to a Salmon. - if (isSuperTypeWithDiscriminator(model)) { - writeSuperTypeFromJson(classBlock, model, propertiesManager, settings, addGeneratedAnnotation); - } else { - writeTerminalTypeFromJson(classBlock, propertiesManager, settings, addGeneratedAnnotation); - } - } - - /* - * Writes the readManagementError(JsonReader) implementation for ManagementError subclass. - */ - private void writeManagementErrorDeserializationMethod(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - JavaSettings settings, Consumer addGeneratedAnnotation) { - addGeneratedAnnotation.accept(classBlock); - classBlock.staticMethod( - JavaVisibility.Private, - propertiesManager.getModel().getName() + " " + READ_MANAGEMENT_ERROR_METHOD_NAME + "(JsonReader jsonReader) throws IOException", - methodBlock -> readJsonObjectMethodBody(methodBlock, - deserializationBlock -> writeFromJsonDeserialization0(deserializationBlock, propertiesManager, settings))); - } - /** - * Writes a super type's {@code fromJson(JsonReader)} method. - * - * @param classBlock The class having {@code fromJson(JsonReader)} written to it. - * @param model The Autorest representation of the model. - * @param propertiesManager The properties for the model. - * @param settings The Autorest generation settings. - * @param addGeneratedAnnotation Callback that adds {@code @Generated} annotation to a code block. - */ - private void writeSuperTypeFromJson(JavaClass classBlock, ClientModel model, - ClientModelPropertiesManager propertiesManager, JavaSettings settings, - Consumer addGeneratedAnnotation) { - // Handling polymorphic fields while determining which subclass, or the class itself, to deserialize handles the - // discriminator type always as a String. This is permissible as the found discriminator is never being used in - // a setter or for setting a field, unlike in the actual deserialization method where it needs to be the same - // type as the field. - String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); - ClientModelPropertyWithMetadata discriminatorProperty = propertiesManager.getDiscriminatorProperty(); - readJsonObject(classBlock, propertiesManager, false, methodBlock -> { - // For now, reading polymorphic types will always buffer the current object. - // In the future this can be enhanced to switch if the first property is the discriminator field and to use - // a Map to contain all properties found while searching for the discriminator field. - // TODO (alzimmer): Need to handle non-string wire type discriminator types. - methodBlock.line("String discriminatorValue = null;"); - methodBlock.tryBlock("JsonReader readerToUse = reader.bufferObject()", tryStatement -> { - tryStatement.line("readerToUse.nextToken(); // Prepare for reading"); - tryStatement.line("while (readerToUse.nextToken() != JsonToken.END_OBJECT) {"); - tryStatement.increaseIndent(); - tryStatement.line("String " + fieldNameVariableName + " = readerToUse.getFieldName();"); - tryStatement.line("readerToUse.nextToken();"); - tryStatement.ifBlock( - "\"" + discriminatorProperty.getProperty().getSerializedName() + "\".equals(" + fieldNameVariableName + ")", - ifStatement -> { + /** + * Writes a super type's {@code fromJson(JsonReader)} method. + * + * @param classBlock The class having {@code fromJson(JsonReader)} written to it. + */ + private void writeSuperTypeFromJson(JavaClass classBlock) { + // Handling polymorphic fields while determining which subclass, or the class itself, to deserialize handles the + // discriminator type always as a String. This is permissible as the found discriminator is never being used in + // a setter or for setting a field, unlike in the actual deserialization method where it needs to be the same + // type as the field. + String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); + ClientModelPropertyWithMetadata discriminatorProperty = propertiesManager.getDiscriminatorProperty(); + readJsonObject(classBlock, false, methodBlock -> { + // For now, reading polymorphic types will always buffer the current object. + // In the future this can be enhanced to switch if the first property is the discriminator field and to use + // a Map to contain all properties found while searching for the discriminator field. + // TODO (alzimmer): Need to handle non-string wire type discriminator types. + methodBlock.line("String discriminatorValue = null;"); + methodBlock.tryBlock("JsonReader readerToUse = reader.bufferObject()", tryStatement -> { + tryStatement.line("readerToUse.nextToken(); // Prepare for reading"); + tryStatement.line("while (readerToUse.nextToken() != JsonToken.END_OBJECT) {"); + tryStatement.increaseIndent(); + tryStatement.line("String " + fieldNameVariableName + " = readerToUse.getFieldName();"); + tryStatement.line("readerToUse.nextToken();"); + tryStatement.ifBlock("\"" + discriminatorProperty.getProperty().getSerializedName() + "\".equals(" + + fieldNameVariableName + ")", ifStatement -> { ifStatement.line("discriminatorValue = readerToUse.getString();"); ifStatement.line("break;"); }).elseBlock(elseBlock -> elseBlock.line("readerToUse.skipChildren();")); - tryStatement.decreaseIndent(); - tryStatement.line("}"); + tryStatement.decreaseIndent(); + tryStatement.line("}"); + + tryStatement.line( + "// Use the discriminator value to determine which subtype should be deserialized."); + + // Add deserialization for the super type itself. + JavaIfBlock ifBlock = null; + + // Add deserialization for all child types. + List childTypes = getAllChildTypes(model, new ArrayList<>()); + for (ClientModel childType : childTypes) { + // Determine which serialization method to use based on whether the child type is also a polymorphic + // parent and the child shares the same polymorphic discriminator as this model. + // If the child and parent have different discriminator names then the child will need to be + // deserialized checking the multi-level polymorphic discriminator. + // Using the nested discriminator sample, there is + // Fish : kind + // - Salmon : kind + // - Shark : sharktype + // - Sawshark : sharktype + // So, if deserialization enters Fish and the "kind" is "Shark" then it needs to check the + // "sharktype" to determine if it's a Sawshark or another subtype of Shark. + boolean sameDiscimrinator = Objects.equals(childType.getPolymorphicDiscriminatorName(), + model.getPolymorphicDiscriminatorName()); + + if (!sameDiscimrinator && !Objects.equals(childType.getParentModelName(), model.getName())) { + // Child model and parent model don't share the same discriminator and the child isn't a direct + // child of the parent model, so skip this child model. This is done as the child model should + // be deserialized by the subtype that defines the different polymorphic discriminator. Using + // the sample above, Fish can't use "kind" to deserialize to a Shark subtype, it needs to use + // "sharktype". + continue; + } - tryStatement.line("// Use the discriminator value to determine which subtype should be deserialized."); + String deserializationMethod = (isSuperTypeWithDiscriminator(childType) && sameDiscimrinator) + ? ".fromJsonKnownDiscriminator(readerToUse.reset())" + : ".fromJson(readerToUse.reset())"; - // Add deserialization for the super type itself. - JavaIfBlock ifBlock = null; + ifBlock = ifOrElseIf(tryStatement, ifBlock, + "\"" + childType.getSerializedName() + "\".equals(discriminatorValue)", + ifStatement -> ifStatement.methodReturn(childType.getName() + deserializationMethod)); + } - // Add deserialization for all child types. - List childTypes = getAllChildTypes(model, new ArrayList<>()); - for (ClientModel childType : childTypes) { - // Determine which serialization method to use based on whether the child type is also a polymorphic - // parent and the child shares the same polymorphic discriminator as this model. - // If the child and parent have different discriminator names then the child will need to be - // deserialized checking the multi-level polymorphic discriminator. - // Using the nested discriminator sample, there is - // Fish : kind - // - Salmon : kind - // - Shark : sharktype - // - Sawshark : sharktype - // So, if deserialization enters Fish and the "kind" is "Shark" then it needs to check the - // "sharktype" to determine if it's a Sawshark or another subtype of Shark. - boolean sameDiscimrinator = Objects.equals(childType.getPolymorphicDiscriminatorName(), - model.getPolymorphicDiscriminatorName()); - - if (!sameDiscimrinator && !Objects.equals(childType.getParentModelName(), model.getName())) { - // Child model and parent model don't share the same discriminator and the child isn't a direct - // child of the parent model, so skip this child model. This is done as the child model should - // be deserialized by the subtype that defines the different polymorphic discriminator. Using - // the sample above, Fish can't use "kind" to deserialize to a Shark subtype, it needs to use - // "sharktype". - continue; + if (ifBlock == null) { + tryStatement.methodReturn("fromJsonKnownDiscriminator(readerToUse.reset())"); + } else { + ifBlock.elseBlock( + elseBlock -> elseBlock.methodReturn("fromJsonKnownDiscriminator(readerToUse.reset())")); } + }); + }); - String deserializationMethod = (isSuperTypeWithDiscriminator(childType) && sameDiscimrinator) - ? ".fromJsonKnownDiscriminator(readerToUse.reset())" - : ".fromJson(readerToUse.reset())"; + readJsonObject(classBlock, true, this::writeFromJsonDeserialization); + } - ifBlock = ifOrElseIf(tryStatement, ifBlock, - "\"" + childType.getSerializedName() + "\".equals(discriminatorValue)", - ifStatement -> ifStatement.methodReturn(childType.getName() + deserializationMethod)); + private static List getAllChildTypes(ClientModel model, List childTypes) { + for (ClientModel childType : model.getDerivedModels()) { + childTypes.add(childType); + if (!CoreUtils.isNullOrEmpty(childType.getDerivedModels())) { + getAllChildTypes(childType, childTypes); } + } - if (ifBlock == null) { - tryStatement.methodReturn("fromJsonKnownDiscriminator(readerToUse.reset())"); + return childTypes; + } + + /** + * Gets the additionalProperty model property from this model or its superclass. + * + * @return the additionalProperty model property from this model or its superclass. + */ + private ClientModelProperty getAdditionalPropertiesPropertyInModelOrFromSuper() { + return propertiesManager.getAdditionalProperties() != null + ? propertiesManager.getAdditionalProperties() + : propertiesManager.getSuperAdditionalPropertiesProperty(); + } + + private void writeFromJsonDeserialization(JavaBlock methodBlock) { + // Add the deserialization logic. + methodBlock.indent(() -> { + if (isManagementErrorSubclass.test(model)) { + methodBlock.line("JsonReader bufferedReader = reader.bufferObject();"); + methodBlock.line("bufferedReader.nextToken();"); + + addReaderWhileLoop("bufferedReader", methodBlock, true, false, whileBlock -> methodBlock.ifBlock( + "\"error\".equals(" + propertiesManager.getJsonReaderFieldNameVariableName() + ")", + ifAction -> ifAction.line("return " + READ_MANAGEMENT_ERROR_METHOD_NAME + "(bufferedReader);")) + .elseBlock(elseAction -> elseAction.line("bufferedReader.skipChildren();"))); + + methodBlock.methodReturn(READ_MANAGEMENT_ERROR_METHOD_NAME + "(bufferedReader.reset())"); } else { - ifBlock.elseBlock( - elseBlock -> elseBlock.methodReturn("fromJsonKnownDiscriminator(readerToUse.reset())")); + writeFromJsonDeserialization0(methodBlock); } }); - }, addGeneratedAnnotation, settings); + } - readJsonObject(classBlock, propertiesManager, true, - methodBlock -> writeFromJsonDeserialization(methodBlock, propertiesManager, settings), - addGeneratedAnnotation, settings); - } - - private static List getAllChildTypes(ClientModel model, List childTypes) { - for (ClientModel childType : model.getDerivedModels()) { - childTypes.add(childType); - if (!CoreUtils.isNullOrEmpty(childType.getDerivedModels())) { - getAllChildTypes(childType, childTypes); - } - } + private void writeFromJsonDeserialization0(JavaBlock methodBlock) { + // Initialize local variables to track what has been deserialized. + initializeLocalVariables(methodBlock, false); + String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); - return childTypes; - } + // Add the outermost while loop to read the JSON object. + addReaderWhileLoop(methodBlock, true, false, whileBlock -> { + if (useFromJsonShared && model.isPolymorphicParent()) { + // If we can use 'fromJsonShared' and this model is a super type, then we can use a customized + // 'fromJson' / 'fromJsonKnownDiscriminator' method to handle deserialization. + // This will generate the following logic: + // + // if (!fromJsonShared(reader, fieldName, deserializedModel)) { + // handleUnknownProperty + // } + String ifBlockCondition = "!" + model.getName() + ".fromJsonShared(reader, " + + fieldNameVariableName + ", " + propertiesManager.getDeserializedModelName() + ")"; + methodBlock.ifBlock(ifBlockCondition, ifBlock -> generateUnknownFieldLogic(ifBlock, null)); + return; + } - /** - * Gets the additionalProperty model property from this model or its superclass. - * - * @param propertiesManager The properties for the model. - * @return the additionalProperty model property from this model or its superclass. - */ - private static ClientModelProperty getAdditionalPropertiesPropertyInModelOrFromSuper( - ClientModelPropertiesManager propertiesManager) { - return propertiesManager.getAdditionalProperties() != null - ? propertiesManager.getAdditionalProperties() - : propertiesManager.getSuperAdditionalPropertiesProperty(); - } + // Loop over all properties and generate their deserialization handling. + AtomicReference ifBlockReference = new AtomicReference<>(null); - /** - * Writes a terminal type's {@code fromJson(JsonReader)} method. - *

- * A terminal type is either a type without polymorphism or is the terminal type in a polymorphic hierarchy. - * - * @param classBlock The class having {@code fromJson(JsonReader)} written to it. - * @param propertiesManager The properties for the model. - * @param settings The Autorest generation settings. - * @param addGeneratedAnnotation Callback that adds {@code @Generated} annotation to a code block. - */ - private void writeTerminalTypeFromJson(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - JavaSettings settings, Consumer addGeneratedAnnotation) { - readJsonObject(classBlock, propertiesManager, false, - methodBlock -> writeFromJsonDeserialization(methodBlock, propertiesManager, settings), - addGeneratedAnnotation, settings); - } + BiConsumer consumer + = (property, fromSuper) -> handleJsonPropertyDeserialization(property, whileBlock, ifBlockReference, + fromSuper, false); - private void writeFromJsonDeserialization(JavaBlock methodBlock, - ClientModelPropertiesManager propertiesManager, JavaSettings settings) { - // Add the deserialization logic. - methodBlock.indent(() -> { - if (isManagementErrorSubclass(propertiesManager.getModel(), settings)) { - writeManagementErrorAdaption(methodBlock, propertiesManager); - } else { - writeFromJsonDeserialization0(methodBlock, propertiesManager, settings); - } - }); - } + Map modelPropertyMap = new HashMap<>(); + for (ClientModelProperty parentProperty : ClientModelUtil.getParentProperties(model)) { + modelPropertyMap.put(parentProperty.getName(), parentProperty); + } + for (ClientModelProperty property : model.getProperties()) { + modelPropertyMap.put(property.getName(), property); + } - private static void writeManagementErrorAdaption(JavaBlock methodBlock, ClientModelPropertiesManager propertiesManager) { - methodBlock.line("JsonReader bufferedReader = reader.bufferObject();"); - methodBlock.line("bufferedReader.nextToken();"); + if (useFromJsonShared) { + // If this model is a subtype, and 'fromJsonShared' can be used, instead of generating the + // deserialization of the parent model(s) in 'fromJson' call to the parent class's 'fromJsonShared'. + String ifBlockCondition = model.getParentModelName() + ".fromJsonShared(reader, " + + fieldNameVariableName + ", " + propertiesManager.getDeserializedModelName() + ")"; + ifBlockReference.set(methodBlock.ifBlock(ifBlockCondition, ifBlock -> ifBlock.line("continue;"))); + } else { + // Child classes may contain properties that shadow parents' ones. + // Thus, we only take the shadowing ones, not the ones shadowed. + Map superRequiredToDeserialized = new LinkedHashMap<>(); + propertiesManager.forEachSuperRequiredProperty(property -> { + if (!property.isConstant() && modelPropertyMap.get(property.getName()) == property) { + superRequiredToDeserialized.put(property.getName(), property); + } + }); + superRequiredToDeserialized.values().forEach(property -> consumer.accept(property, true)); + + // Child classes may contain properties that shadow parents' ones. + // Thus, we only take the shadowing ones, not the ones shadowed. + Map superSettersToDeserialized = new LinkedHashMap<>(); + propertiesManager.forEachSuperSetterProperty(property -> { + if (!property.isConstant() && modelPropertyMap.get(property.getName()) == property) { + superSettersToDeserialized.put(property.getName(), property); + } + }); + superSettersToDeserialized.values().forEach(property -> consumer.accept(property, true)); + } - String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); - addReaderWhileLoop("bufferedReader", methodBlock, true, fieldNameVariableName, false, whileBlock -> - methodBlock.ifBlock("\"error\".equals(" + fieldNameVariableName + ")", - ifAction -> ifAction.line("return " + READ_MANAGEMENT_ERROR_METHOD_NAME + "(bufferedReader);")) - .elseBlock(elseAction -> elseAction.line("bufferedReader.skipChildren();"))); + generateThisFromJson(ifBlockReference, consumer, methodBlock, false, useFromJsonShared); - methodBlock.methodReturn(READ_MANAGEMENT_ERROR_METHOD_NAME + "(bufferedReader.reset())"); - } + // All properties have been checked for, add an else block that will either ignore unknown properties + // or add them into an additional properties bag. + generateUnknownFieldLogic(whileBlock, ifBlockReference.get()); + }); - private static void writeFromJsonDeserialization0(JavaBlock methodBlock, - ClientModelPropertiesManager propertiesManager, JavaSettings settings) { - // Initialize local variables to track what has been deserialized. - initializeLocalVariables(methodBlock, propertiesManager, false, settings); + // Add the validation and return logic. + handleReadReturn(methodBlock); + } - boolean polymorphicJsonMergePatchScenario = propertiesManager.getModel().isPolymorphic() - && ClientModelUtil.isJsonMergePatchModel(propertiesManager.getModel(), settings); - boolean useFromJsonShared = canUseFromJsonShared(propertiesManager); + private void generateThisFromJson(AtomicReference ifBlockReference, + BiConsumer consumer, JavaBlock methodBlock, boolean isFromJsonShared, + boolean usingFromJsonShared) { + propertiesManager.forEachRequiredProperty(property -> { + if (property.isConstant()) { + return; + } - String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); + if (skipDeserializingParentDefinedDiscriminator(usingFromJsonShared, isFromJsonShared, property)) { + return; + } - // Add the outermost while loop to read the JSON object. - addReaderWhileLoop(methodBlock, true, fieldNameVariableName, false, whileBlock -> { - if (useFromJsonShared && propertiesManager.getModel().isPolymorphicParent()) { - // If we can use 'fromJsonShared' and this model is a super type, then we can use a customized - // 'fromJson' / 'fromJsonKnownDiscriminator' method to handle deserialization. - // This will generate the following logic: - // - // if (!fromJsonShared(reader, fieldName, deserializedModel)) { - // handleUnknownProperty - // } - String ifBlockCondition = "!" + propertiesManager.getModel().getName() + ".fromJsonShared(reader, " - + fieldNameVariableName + ", " + propertiesManager.getDeserializedModelName() + ")"; - methodBlock.ifBlock(ifBlockCondition, - ifBlock -> generateUnknownFieldLogic(ifBlock, null, propertiesManager)); - return; - } + consumer.accept(property, false); + }); + propertiesManager.forEachSetterProperty(property -> { + if (skipDeserializingParentDefinedDiscriminator(usingFromJsonShared, isFromJsonShared, property)) { + return; + } - // Loop over all properties and generate their deserialization handling. - AtomicReference ifBlockReference = new AtomicReference<>(null); + consumer.accept(property, false); + }); - BiConsumer consumer = (property, fromSuper) -> - handleJsonPropertyDeserialization(propertiesManager.getModel(), property, - propertiesManager.getDeserializedModelName(), whileBlock, ifBlockReference, - fieldNameVariableName, fromSuper, propertiesManager.hasConstructorArguments(), settings, - polymorphicJsonMergePatchScenario, false); + JavaIfBlock ifBlock = ifBlockReference.get(); - Map modelPropertyMap = new HashMap<>(); - for (ClientModelProperty parentProperty : ClientModelUtil.getParentProperties(propertiesManager.getModel())) { - modelPropertyMap.put(parentProperty.getName(), parentProperty); - } - for (ClientModelProperty property : propertiesManager.getModel().getProperties()) { - modelPropertyMap.put(property.getName(), property); + // Add flattened properties if we aren't using 'fromJsonShared' or some of the flattened properties are defined + // by this model. + if (!usingFromJsonShared || !propertiesManager.isAllFlattenedPropertiesFromParent()) { + handleFlattenedPropertiesDeserialization(methodBlock, ifBlock, isFromJsonShared); } + } - if (useFromJsonShared) { - // If this model is a subtype, and 'fromJsonShared' can be used, instead of generating the - // deserialization of the parent model(s) in 'fromJson' call to the parent class's 'fromJsonShared'. - String ifBlockCondition = propertiesManager.getModel().getParentModelName() + ".fromJsonShared(reader, " - + fieldNameVariableName + ", " + propertiesManager.getDeserializedModelName() + ")"; - ifBlockReference.set(methodBlock.ifBlock(ifBlockCondition, ifBlock -> ifBlock.line("continue;"))); - } else { - // Child classes may contain properties that shadow parents' ones. - // Thus, we only take the shadowing ones, not the ones shadowed. - Map superRequiredToDeserialized = new LinkedHashMap<>(); - propertiesManager.forEachSuperRequiredProperty(property -> { - if (!property.isConstant() && modelPropertyMap.get(property.getName()) == property) { - superRequiredToDeserialized.put(property.getName(), property); - } - }); - superRequiredToDeserialized.values().forEach(property -> consumer.accept(property, true)); - - // Child classes may contain properties that shadow parents' ones. - // Thus, we only take the shadowing ones, not the ones shadowed. - Map superSettersToDeserialized = new LinkedHashMap<>(); - propertiesManager.forEachSuperSetterProperty(property -> { - if (!property.isConstant() && modelPropertyMap.get(property.getName()) == property) { - superSettersToDeserialized.put(property.getName(), property); + private boolean skipDeserializingParentDefinedDiscriminator(boolean usingFromJsonShared, + boolean isFromJsonShared, ClientModelProperty property) { + // If this type is using 'fromJsonShared' from the parent model, skip deserializing polymorphic + // discriminators if it is defined by a parent model. + return (usingFromJsonShared || (isFromJsonShared && !CoreUtils.isNullOrEmpty(model.getParentModelName()))) + && property.isPolymorphicDiscriminator() && !model.isPolymorphicDiscriminatorDefinedByModel(); + } + + private void generateUnknownFieldLogic(JavaBlock whileBlock, JavaIfBlock ifBlock) { + ClientModelProperty additionalProperty = getAdditionalPropertiesPropertyInModelOrFromSuper(); + handleUnknownJsonFieldDeserialization(whileBlock, ifBlock, additionalProperty); + } + + /** + * Adds a static method to the class with the signature that handles reading the JSON string into the object + * type. + *

+ * If {@code superTypeReading} is true the method will be package-private and named + * {@code fromJsonWithKnownDiscriminator} instead of being public and named {@code fromJson}. This is done as + * super types use their {@code fromJson} method to determine the discriminator value and pass the reader to the + * specific type being deserialized. The specific type being deserialized may be the super type itself, so it + * cannot pass to {@code fromJson} as this will be a circular call and if the specific type being deserialized + * is an intermediate type (a type having both super and subclasses) it will attempt to perform discriminator + * validation which has already been done. + * + * @param classBlock The class where the {@code fromJson} method is being written. + * @param superTypeReading Whether the object reading is for a super type. + * @param deserializationBlock Logic for deserializing the object. + */ + private void readJsonObject(JavaClass classBlock, boolean superTypeReading, + Consumer deserializationBlock) { + JavaVisibility visibility = superTypeReading ? JavaVisibility.PackagePrivate : JavaVisibility.Public; + String methodName = superTypeReading ? "fromJsonKnownDiscriminator" : "fromJson"; + + String modelName = model.getName(); + boolean hasRequiredProperties = propertiesManager.hasRequiredProperties(); + + if (!superTypeReading) { + classBlock.javadocComment(javadocComment -> { + javadocComment.description("Reads an instance of " + modelName + " from the JsonReader."); + javadocComment.param("jsonReader", "The JsonReader being read."); + javadocComment.methodReturns( + "An instance of " + modelName + " if the JsonReader was pointing to an " + + "instance of it, or null if it was pointing to JSON null."); + + if (hasRequiredProperties) { + javadocComment.methodThrows("IllegalStateException", + "If the deserialized JSON object was missing any required properties."); } + + javadocComment.methodThrows("IOException", + "If an error occurs while reading the " + modelName + "."); }); - superSettersToDeserialized.values().forEach(property -> consumer.accept(property, true)); } - generateThisFromJson(propertiesManager, ifBlockReference, consumer, methodBlock, settings, - polymorphicJsonMergePatchScenario, false, useFromJsonShared); - - // All properties have been checked for, add an else block that will either ignore unknown properties - // or add them into an additional properties bag. - generateUnknownFieldLogic(whileBlock, ifBlockReference.get(), propertiesManager); - }); - - // Add the validation and return logic. - handleReadReturn(methodBlock, propertiesManager.getModel().getName(), propertiesManager, settings); - } - - private static void generateThisFromJson(ClientModelPropertiesManager propertiesManager, - AtomicReference ifBlockReference, BiConsumer consumer, - JavaBlock methodBlock, JavaSettings settings, boolean polymorphicJsonMergePatchScenario, - boolean isFromJsonShared, boolean usingFromJsonShared) { - propertiesManager.forEachRequiredProperty(property -> { - if (property.isConstant()) { - return; - } + addGeneratedAnnotation.accept(classBlock); + classBlock.staticMethod(visibility, + modelName + " " + methodName + "(JsonReader jsonReader) throws IOException", + methodBlock -> readJsonObjectMethodBody(methodBlock, deserializationBlock)); + + if (superTypeReading && useFromJsonShared && model.isPolymorphicParent()) { + // Add a package-private 'fromJsonShared' method that can handle deserializing properties defined in the parent + // class. + String fieldName = propertiesManager.getJsonReaderFieldNameVariableName(); + String modelDeserializedName = propertiesManager.getDeserializedModelName(); + String methodDefinition = "boolean fromJsonShared(JsonReader reader, String " + fieldName + ", " + + modelName + " " + modelDeserializedName + ") throws IOException"; + addGeneratedAnnotation.accept(classBlock); + classBlock.staticMethod(JavaVisibility.PackagePrivate, methodDefinition, methodBlock -> { + AtomicReference ifBlockReference = new AtomicReference<>(); + if (!CoreUtils.isNullOrEmpty(model.getParentModelName())) { + String callToSuperFromJsonShared = model.getParentModelName() + ".fromJsonShared(reader, " + + propertiesManager.getJsonReaderFieldNameVariableName() + ", " + + propertiesManager.getDeserializedModelName() + ")"; + ifBlockReference.set( + methodBlock.ifBlock(callToSuperFromJsonShared, ifBlock -> ifBlock.methodReturn("true"))); + } - if (skipDeserializingParentDefinedDiscriminator(usingFromJsonShared, isFromJsonShared, propertiesManager, - property)) { - return; - } + BiConsumer consumer + = (property, fromSuper) -> handleJsonPropertyDeserialization(property, methodBlock, + ifBlockReference, fromSuper, true); + generateThisFromJson(ifBlockReference, consumer, methodBlock, true, false); - consumer.accept(property, false); - }); - propertiesManager.forEachSetterProperty(property -> { - if (skipDeserializingParentDefinedDiscriminator(usingFromJsonShared, isFromJsonShared, propertiesManager, - property)) { - return; + methodBlock.methodReturn("false"); + }); } - - consumer.accept(property, false); - }); - - JavaIfBlock ifBlock = ifBlockReference.get(); - - // Add flattened properties if we aren't using 'fromJsonShared' or some of the flattened properties are defined - // by this model. - if (!usingFromJsonShared || !propertiesManager.isAllFlattenedPropertiesFromParent()) { - handleFlattenedPropertiesDeserialization(propertiesManager.getJsonFlattenedPropertiesTree(), methodBlock, - ifBlock, propertiesManager.getAdditionalProperties(), - propertiesManager.getJsonReaderFieldNameVariableName(), propertiesManager.hasConstructorArguments(), - settings, polymorphicJsonMergePatchScenario, isFromJsonShared); } - } - private static boolean skipDeserializingParentDefinedDiscriminator(boolean usingFromJsonShared, - boolean isFromJsonShared, ClientModelPropertiesManager propertiesManager, ClientModelProperty property) { - // If this type is using 'fromJsonShared' from the parent model, skip deserializing polymorphic - // discriminators if it is defined by a parent model. - return (usingFromJsonShared - || (isFromJsonShared && !CoreUtils.isNullOrEmpty(propertiesManager.getModel().getParentModelName()))) - && property.isPolymorphicDiscriminator() - && !propertiesManager.getModel().isPolymorphicDiscriminatorDefinedByModel(); - } - - private static void generateUnknownFieldLogic(JavaBlock whileBlock, JavaIfBlock ifBlock, - ClientModelPropertiesManager propertiesManager) { - ClientModelProperty additionalProperty = getAdditionalPropertiesPropertyInModelOrFromSuper(propertiesManager); - handleUnknownJsonFieldDeserialization(whileBlock, ifBlock, additionalProperty, - propertiesManager.getJsonReaderFieldNameVariableName()); - } - - /** - * Whether the given model is subclass of ManagementError, which needs special deserialization adaption. - * @param model the model to check - * @param settings JavaSettings instance - * @return whether the given model is subclass of ManagementError - */ - protected boolean isManagementErrorSubclass(ClientModel model, JavaSettings settings) { - return false; - } - - /** - * Adds a static method to the class with the signature that handles reading the JSON string into the object type. - *

- * If {@code superTypeReading} is true the method will be package-private and named - * {@code fromJsonWithKnownDiscriminator} instead of being public and named {@code fromJson}. This is done as super - * types use their {@code fromJson} method to determine the discriminator value and pass the reader to the specific - * type being deserialized. The specific type being deserialized may be the super type itself, so it cannot pass to - * {@code fromJson} as this will be a circular call and if the specific type being deserialized is an intermediate - * type (a type having both super and subclasses) it will attempt to perform discriminator validation which has - * already been done. - * - * @param classBlock The class where the {@code fromJson} method is being written. - * @param propertiesManager Properties information about the object being deserialized. - * @param superTypeReading Whether the object reading is for a super type. - * @param deserializationBlock Logic for deserializing the object. - * @param addGeneratedAnnotation Callback that adds {@code @Generated} annotation to a code block. - */ - private static void readJsonObject(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - boolean superTypeReading, Consumer deserializationBlock, - Consumer addGeneratedAnnotation, JavaSettings settings) { - JavaVisibility visibility = superTypeReading ? JavaVisibility.PackagePrivate : JavaVisibility.Public; - String methodName = superTypeReading ? "fromJsonKnownDiscriminator" : "fromJson"; - - String modelName = propertiesManager.getModel().getName(); - boolean hasRequiredProperties = propertiesManager.hasRequiredProperties(); - - if (!superTypeReading) { - classBlock.javadocComment(javadocComment -> { - javadocComment.description("Reads an instance of " + modelName + " from the JsonReader."); - javadocComment.param("jsonReader", "The JsonReader being read."); - javadocComment.methodReturns("An instance of " + modelName + " if the JsonReader was pointing to an " - + "instance of it, or null if it was pointing to JSON null."); - - if (hasRequiredProperties) { - javadocComment.methodThrows("IllegalStateException", - "If the deserialized JSON object was missing any required properties."); - } - - javadocComment.methodThrows("IOException", "If an error occurs while reading the " + modelName + "."); - }); + private static void readJsonObjectMethodBody(JavaBlock methodBlock, Consumer deserializationBlock) { + // For now, use the basic readObject which will return null if the JsonReader is pointing to JsonToken.NULL. + // + // Support for a default value if null will need to be supported and for objects that get their value + // from a JSON value instead of JSON object or are an array type. + methodBlock.line("return jsonReader.readObject(reader -> {"); + deserializationBlock.accept(methodBlock); + methodBlock.line("});"); } - addGeneratedAnnotation.accept(classBlock); - classBlock.staticMethod(visibility, modelName + " " + methodName + "(JsonReader jsonReader) throws IOException", - methodBlock -> readJsonObjectMethodBody(methodBlock, deserializationBlock)); - - if (superTypeReading - && canUseFromJsonShared(propertiesManager) - && propertiesManager.getModel().isPolymorphicParent()) { - // Add a package-private 'fromJsonShared' method that can handle deserializing properties defined in the parent - // class. - String fieldName = propertiesManager.getJsonReaderFieldNameVariableName(); - String modelDeserializedName = propertiesManager.getDeserializedModelName(); - String methodDefinition = "boolean fromJsonShared(JsonReader reader, String " + fieldName + ", " - + modelName + " " + modelDeserializedName + ") throws IOException"; - addGeneratedAnnotation.accept(classBlock); - classBlock.staticMethod(JavaVisibility.PackagePrivate, methodDefinition, methodBlock -> { - boolean polymorphicJsonMergePatchScenario = propertiesManager.getModel().isPolymorphic() - && ClientModelUtil.isJsonMergePatchModel(propertiesManager.getModel(), settings); - - AtomicReference ifBlockReference = new AtomicReference<>(); - if (!CoreUtils.isNullOrEmpty(propertiesManager.getModel().getParentModelName())) { - String callToSuperFromJsonShared = propertiesManager.getModel().getParentModelName() - + ".fromJsonShared(reader, " + propertiesManager.getJsonReaderFieldNameVariableName() + ", " - + propertiesManager.getDeserializedModelName() + ")"; - ifBlockReference.set(methodBlock.ifBlock(callToSuperFromJsonShared, - ifBlock -> ifBlock.methodReturn("true"))); + /** + * Initializes the local variables needed to maintain what has been deserialized. + * + * @param methodBlock The method handling deserialization. + */ + private void initializeLocalVariables(JavaBlock methodBlock, boolean isXml) { + if (propertiesManager.hasConstructorArguments()) { + if (isXml) { + // XML only needs to initialize the XML element properties. XML attribute properties are initialized with + // their XML value. + propertiesManager.forEachSuperXmlElement( + element -> initializeLocalVariable(methodBlock, element, true)); + propertiesManager.forEachXmlElement( + element -> initializeLocalVariable(methodBlock, element, false)); + } else { + propertiesManager.forEachSuperRequiredProperty(property -> { + if (property.isConstant()) { + // Constants are never deserialized. + return; + } + initializeLocalVariable(methodBlock, property, true); + }); + propertiesManager.forEachSuperSetterProperty(property -> { + if (ClientModelUtil.readOnlyNotInCtor(model, property, settings)) { + initializeShadowPropertyLocalVariable(methodBlock, property); + } else { + initializeLocalVariable(methodBlock, property, true); + } + }); + propertiesManager.forEachRequiredProperty(property -> { + if (property.isConstant()) { + // Constants are never deserialized. + return; + } + initializeLocalVariable(methodBlock, property, false); + }); + propertiesManager.forEachSetterProperty( + property -> initializeLocalVariable(methodBlock, property, false)); } - - BiConsumer consumer - = (property, fromSuper) -> handleJsonPropertyDeserialization(propertiesManager.getModel(), property, - modelDeserializedName, methodBlock, ifBlockReference, fieldName, fromSuper, - propertiesManager.hasConstructorArguments(), settings, polymorphicJsonMergePatchScenario, true); - generateThisFromJson(propertiesManager, ifBlockReference, consumer, methodBlock, settings, - polymorphicJsonMergePatchScenario, true, false); - - methodBlock.methodReturn("false"); - }); - } - } - - private static void readJsonObjectMethodBody(JavaBlock methodBlock, Consumer deserializationBlock) { - // For now, use the basic readObject which will return null if the JsonReader is pointing to JsonToken.NULL. - // - // Support for a default value if null will need to be supported and for objects that get their value - // from a JSON value instead of JSON object or are an array type. - methodBlock.line("return jsonReader.readObject(reader -> {"); - deserializationBlock.accept(methodBlock); - methodBlock.line("});"); - } - - private static boolean canUseFromJsonShared(ClientModelPropertiesManager propertiesManager) { - // If the model is part of a polymorphic hierarchy and all models in the polymorphic hierarchy are in the same - // package we can generate a package-private 'toJsonShared' method that can handle deserializing properties - // defined in the parent class(es). - // This will prevent duplicating the deserialization logic for parent properties in each subclass. - return !propertiesManager.hasConstructorArguments() - && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage(); - } - - /** - * Initializes the local variables needed to maintain what has been deserialized. - * - * @param methodBlock The method handling deserialization. - * @param propertiesManager The property manager for the model. - */ - private static void initializeLocalVariables(JavaBlock methodBlock, ClientModelPropertiesManager propertiesManager, - boolean isXml, JavaSettings settings) { - if (propertiesManager.hasConstructorArguments()) { - if (isXml) { - // XML only needs to initialize the XML element properties. XML attribute properties are initialized with - // their XML value. - propertiesManager.forEachSuperXmlElement(element -> initializeLocalVariable(methodBlock, element, true, - settings)); - propertiesManager.forEachXmlElement(element -> initializeLocalVariable(methodBlock, element, false, - settings)); } else { - propertiesManager.forEachSuperRequiredProperty(property -> { - if (property.isConstant()) { - // Constants are never deserialized. - return; - } - initializeLocalVariable(methodBlock, property, true, settings); - }); - propertiesManager.forEachSuperSetterProperty(property -> { - if (ClientModelUtil.readOnlyNotInCtor(propertiesManager.getModel(), property, settings)) { - initializeShadowPropertyLocalVariable(methodBlock, property); - } else { - initializeLocalVariable(methodBlock, property, true, settings); - } - }); - propertiesManager.forEachRequiredProperty(property -> { - if (property.isConstant()) { - // Constants are never deserialized. - return; - } - initializeLocalVariable(methodBlock, property, false, settings); - }); - propertiesManager.forEachSetterProperty(property -> initializeLocalVariable(methodBlock, property, - false, settings)); + methodBlock.line(model.getName() + " " + propertiesManager.getDeserializedModelName() + " = new " + + model.getName() + "();"); } - } else { - String modelName = propertiesManager.getModel().getName(); - methodBlock.line(modelName + " " + propertiesManager.getDeserializedModelName() + " = new " - + modelName + "();"); - } - ClientModelProperty additionalProperty = getAdditionalPropertiesPropertyInModelOrFromSuper(propertiesManager); - if (additionalProperty != null) { - initializeLocalVariable(methodBlock, additionalProperty, false, settings); + ClientModelProperty additionalProperty = getAdditionalPropertiesPropertyInModelOrFromSuper(); + if (additionalProperty != null) { + initializeLocalVariable(methodBlock, additionalProperty, false); + } } - } - /* - * Shadow properties from parent should be initialized as wired type. - */ - private static void initializeShadowPropertyLocalVariable(JavaBlock methodBlock, ClientModelProperty property) { - IType type = property.getWireType(); - String defaultValue = property.isPolymorphicDiscriminator() - ? property.getDefaultValue() : type.defaultValueExpression(); - methodBlock.line(type + " " + property.getName() + " = " + defaultValue + ";"); - } - - private static void initializeLocalVariable(JavaBlock methodBlock, ClientModelProperty property, boolean fromSuper, - JavaSettings settings) { - if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { - // Required properties need an additional boolean variable to indicate they've been found. - methodBlock.line("boolean " + property.getName() + "Found = false;"); - } - - // Always instantiate the local variable. - // If the property is part of the constructor or set by a setter method from the super class, initialize the - // local variable with the client type. Otherwise, initialize as the wire type to prevent multiple conversions - // between wire and client types. - IType type = (includePropertyInConstructor(property, settings) || fromSuper) - ? property.getClientType() : property.getWireType(); - String defaultValue = property.isPolymorphicDiscriminator() - ? property.getDefaultValue() : type.defaultValueExpression(); - methodBlock.line(type + " " + property.getName() + " = " + defaultValue + ";"); - } - - /** - * Adds the while loop that handles reading the JSON object until it is fully consumed. - * - * @param methodBlock The method handling deserialization. - * @param initializeFieldNameVariable Whether the {@code fieldNameVariableName} variable needs to be initialized. If - * this is a nested while loop the variable doesn't need to be initialized. - * @param fieldNameVariableName The name for the variable that tracks the JSON field name. - * @param isXml Whether the reader while loop is for XML reading. - * @param whileBlock The consumer that adds deserialization logic into the while loop. - */ - private static void addReaderWhileLoop(JavaBlock methodBlock, boolean initializeFieldNameVariable, - String fieldNameVariableName, boolean isXml, Consumer whileBlock) { - addReaderWhileLoop("reader", methodBlock, initializeFieldNameVariable, fieldNameVariableName, - isXml, whileBlock); - } + /* + * Shadow properties from parent should be initialized as wired type. + */ + private static void initializeShadowPropertyLocalVariable(JavaBlock methodBlock, ClientModelProperty property) { + IType type = property.getWireType(); + String defaultValue = property.isPolymorphicDiscriminator() + ? property.getDefaultValue() + : type.defaultValueExpression(); + methodBlock.line(type + " " + property.getName() + " = " + defaultValue + ";"); + } - /** - * Adds the while loop that handles reading the JSON object until it is fully consumed. - * - * @param readerVariableName The name of the local reader variable. - * @param methodBlock The method handling deserialization. - * @param initializeFieldNameVariable Whether the {@code fieldNameVariableName} variable needs to be initialized. If - * this is a nested while loop the variable doesn't need to be initialized. - * @param fieldNameVariableName The name for the variable that tracks the JSON field name. - * @param isXml Whether the reader while loop is for XML reading. - * @param whileBlock The consumer that adds deserialization logic into the while loop. - */ - private static void addReaderWhileLoop(String readerVariableName, JavaBlock methodBlock, boolean initializeFieldNameVariable, - String fieldNameVariableName, boolean isXml, Consumer whileBlock) { - String whileCheck = isXml - ? readerVariableName + ".nextElement() != XmlToken.END_ELEMENT" - : readerVariableName + ".nextToken() != JsonToken.END_OBJECT"; - - methodBlock.block("while (" + whileCheck + ")", whileAction -> { - String fieldNameInitialization = ""; - if (initializeFieldNameVariable) { - fieldNameInitialization = isXml ? "QName" : "String"; + private void initializeLocalVariable(JavaBlock methodBlock, ClientModelProperty property, boolean fromSuper) { + if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { + // Required properties need an additional boolean variable to indicate they've been found. + methodBlock.line("boolean " + property.getName() + "Found = false;"); } - methodBlock.line("%s %s = %s.get%sName();", fieldNameInitialization, fieldNameVariableName, - readerVariableName, isXml ? "Element" : "Field"); + // Always instantiate the local variable. + // If the property is part of the constructor or set by a setter method from the super class, initialize the + // local variable with the client type. Otherwise, initialize as the wire type to prevent multiple conversions + // between wire and client types. + IType type = (includePropertyInConstructor(property, settings) || fromSuper) + ? property.getClientType() + : property.getWireType(); + String defaultValue = property.isPolymorphicDiscriminator() + ? property.getDefaultValue() + : type.defaultValueExpression(); + methodBlock.line(type + " " + property.getName() + " = " + defaultValue + ";"); + } + + /** + * Adds the while loop that handles reading the JSON object until it is fully consumed. + * + * @param methodBlock The method handling deserialization. + * @param initializeFieldNameVariable Whether the {@code fieldNameVariableName} variable needs to be + * initialized. If this is a nested while loop the variable doesn't need to be initialized. + * @param isXml Whether the reader while loop is for XML reading. + * @param whileBlock The consumer that adds deserialization logic into the while loop. + */ + private void addReaderWhileLoop(JavaBlock methodBlock, boolean initializeFieldNameVariable, boolean isXml, + Consumer whileBlock) { + addReaderWhileLoop("reader", methodBlock, initializeFieldNameVariable, isXml, whileBlock); + } + + /** + * Adds the while loop that handles reading the JSON object until it is fully consumed. + * + * @param readerVariableName The name of the local reader variable. + * @param methodBlock The method handling deserialization. + * @param initializeFieldNameVariable Whether the {@code fieldNameVariableName} variable needs to be + * initialized. If this is a nested while loop the variable doesn't need to be initialized. + * @param isXml Whether the reader while loop is for XML reading. + * @param whileBlock The consumer that adds deserialization logic into the while loop. + */ + private void addReaderWhileLoop(String readerVariableName, JavaBlock methodBlock, + boolean initializeFieldNameVariable, boolean isXml, Consumer whileBlock) { + String whileCheck = isXml + ? readerVariableName + ".nextElement() != XmlToken.END_ELEMENT" + : readerVariableName + ".nextToken() != JsonToken.END_OBJECT"; + String fieldNameVariableName = isXml + ? propertiesManager.getXmlReaderNameVariableName() + : propertiesManager.getJsonReaderFieldNameVariableName(); + + methodBlock.block("while (" + whileCheck + ")", whileAction -> { + String fieldNameInitialization = ""; + if (initializeFieldNameVariable) { + fieldNameInitialization = isXml ? "QName" : "String"; + } - if (!isXml) { - methodBlock.line(readerVariableName + ".nextToken();"); - } - methodBlock.line(""); + methodBlock.line("%s %s = %s.get%sName();", fieldNameInitialization, fieldNameVariableName, + readerVariableName, isXml ? "Element" : "Field"); - whileBlock.accept(methodBlock); - }); - } + if (!isXml) { + methodBlock.line(readerVariableName + ".nextToken();"); + } + methodBlock.line(""); - private static void handleJsonPropertyDeserialization(ClientModel model, ClientModelProperty property, - String modelVariableName, JavaBlock methodBlock, AtomicReference ifBlockReference, - String fieldNameVariableName, boolean fromSuper, boolean hasConstructorArguments, JavaSettings settings, - boolean polymorphicJsonMergePatchScenario, boolean isFromJsonShared) { - // Property will be handled later by flattened deserialization. - if (property.getNeedsFlatten()) { - return; + whileBlock.accept(methodBlock); + }); } - JavaIfBlock ifBlock = ifBlockReference.get(); - ifBlock = handleJsonPropertyDeserialization(model, property, modelVariableName, methodBlock, ifBlock, - fieldNameVariableName, fromSuper, hasConstructorArguments, settings, polymorphicJsonMergePatchScenario, - isFromJsonShared); - - ifBlockReference.set(ifBlock); - } + private void handleJsonPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, + AtomicReference ifBlockReference, boolean fromSuper, boolean isFromJsonShared) { + // Property will be handled later by flattened deserialization. + if (property.getNeedsFlatten()) { + return; + } - private static JavaIfBlock handleJsonPropertyDeserialization(ClientModel model, ClientModelProperty property, - String modelVariableName, JavaBlock methodBlock, JavaIfBlock ifBlock, String fieldNameVariableName, - boolean fromSuper, boolean hasConstructorArguments, JavaSettings settings, - boolean polymorphicJsonMergePatchScenario, boolean isFromJsonShared) { - String jsonPropertyName = property.getSerializedName(); - if (CoreUtils.isNullOrEmpty(jsonPropertyName)) { - return ifBlock; - } - - return ifOrElseIf(methodBlock, ifBlock, "\"" + jsonPropertyName + "\".equals(" + fieldNameVariableName + ")", - deserializationBlock -> { - generateJsonDeserializationLogic(deserializationBlock, modelVariableName, model, property, fromSuper, - hasConstructorArguments, settings, polymorphicJsonMergePatchScenario); - if (isFromJsonShared) { - deserializationBlock.methodReturn("true"); - } - }); - } + JavaIfBlock ifBlock = ifBlockReference.get(); + ifBlock = handleJsonPropertyDeserialization(property, methodBlock, ifBlock, fromSuper, isFromJsonShared); - private static void handleFlattenedPropertiesDeserialization( - JsonFlattenedPropertiesTree flattenedProperties, JavaBlock methodBlock, JavaIfBlock ifBlock, - ClientModelProperty additionalProperties, String fieldNameVariableName, boolean hasConstructorArguments, - JavaSettings settings, boolean polymorphicJsonMergePatchScenario, boolean isFromJsonShared) { - // The initial call to handle flattened properties is using the base node which is just a holder. - for (JsonFlattenedPropertiesTree structure : flattenedProperties.getChildrenNodes().values()) { - handleFlattenedPropertiesDeserializationHelper(structure, methodBlock, ifBlock, additionalProperties, - fieldNameVariableName, hasConstructorArguments, settings, polymorphicJsonMergePatchScenario, - isFromJsonShared, 0); + ifBlockReference.set(ifBlock); } - } - private static JavaIfBlock handleFlattenedPropertiesDeserializationHelper( - JsonFlattenedPropertiesTree flattenedProperties, JavaBlock methodBlock, JavaIfBlock ifBlock, - ClientModelProperty additionalProperties, String fieldNameVariableName, boolean hasConstructorArguments, - JavaSettings settings, boolean polymorphicJsonMergePatchScenario, boolean isFromJsonShared, int depth) { - ClientModelPropertyWithMetadata propertyWithMetadata = flattenedProperties.getProperty(); - if (propertyWithMetadata != null) { - String modelVariableName = "deserialized" + propertyWithMetadata.getModel().getName(); + private JavaIfBlock handleJsonPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, + JavaIfBlock ifBlock, boolean fromSuper, boolean isFromJsonShared) { + String jsonPropertyName = property.getSerializedName(); + if (CoreUtils.isNullOrEmpty(jsonPropertyName)) { + return ifBlock; + } - // This is a terminal location, so only need to handle checking for the property name. return ifOrElseIf(methodBlock, ifBlock, - "\"" + flattenedProperties.getNodeName() + "\".equals(" + fieldNameVariableName + ")", - deserializationBlock -> generateJsonDeserializationLogic(deserializationBlock, modelVariableName, - propertyWithMetadata.getModel(), propertyWithMetadata.getProperty(), - propertyWithMetadata.isFromSuperClass(), hasConstructorArguments, settings, - polymorphicJsonMergePatchScenario)); - } else { - // Otherwise this is an intermediate location and a while loop reader needs to be added. - return ifOrElseIf(methodBlock, ifBlock, - "\"" + flattenedProperties.getNodeName() + "\".equals(" + fieldNameVariableName + ") && reader.currentToken() == JsonToken.START_OBJECT", - ifAction -> { - addReaderWhileLoop(ifAction, false, fieldNameVariableName, false, whileBlock -> { - JavaIfBlock innerIfBlock = null; - for (JsonFlattenedPropertiesTree structure : flattenedProperties.getChildrenNodes().values()) { - innerIfBlock = handleFlattenedPropertiesDeserializationHelper(structure, methodBlock, - innerIfBlock, additionalProperties, fieldNameVariableName, hasConstructorArguments, - settings, polymorphicJsonMergePatchScenario, isFromJsonShared, depth + 1); - } - - handleUnknownJsonFieldDeserialization(whileBlock, innerIfBlock, additionalProperties, - fieldNameVariableName); - }); - - if (isFromJsonShared && depth == 0) { - // Flattening will handle skipping and additional properties itself. - ifAction.methodReturn("true"); + "\"" + jsonPropertyName + "\".equals(" + propertiesManager.getJsonReaderFieldNameVariableName() + ")", + deserializationBlock -> { + generateJsonDeserializationLogic(deserializationBlock, property, fromSuper); + if (isFromJsonShared) { + deserializationBlock.methodReturn("true"); } }); } - } - private static void generateJsonDeserializationLogic(JavaBlock deserializationBlock, String modelVariableName, - ClientModel model, ClientModelProperty property, boolean fromSuper, boolean hasConstructorArguments, JavaSettings settings, - boolean polymorphicJsonMergePatchScenario) { - IType wireType = property.getWireType(); - IType clientType = property.getClientType(); - - // Attempt to determine whether the wire type is simple deserialization. - // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. - String simpleDeserialization = getSimpleJsonDeserialization(wireType, "reader"); - if (simpleDeserialization != null) { - // Need to convert the wire type to the client type for constructors. - // Need to convert the wire type to the client type for public setters. - boolean convertToClientType = (clientType != wireType) - && (includePropertyInConstructor(property, settings) || (fromSuper && !ClientModelUtil.readOnlyNotInCtor(model, property, settings))); - BiConsumer simpleDeserializationConsumer = (logic, block) -> { - if (!hasConstructorArguments) { - handleSettingDeserializedValue(block, modelVariableName, model, property, logic, fromSuper, - polymorphicJsonMergePatchScenario); - } else { - block.line(property.getName() + " = " + logic + ";"); - } - }; - - if (convertToClientType) { - // If the wire type is nullable don't attempt to call the convert to client type until it's known that - // a value was deserialized. This protects against cases such as UnixTimeLong where the wire type is - // Long and the client type of OffsetDateTime. This is converted using Instant.ofEpochMilli(long) which - // would result in a null if the Long is null, which is already guarded using - // reader.readNullable(nonNullReader -> Instant.ofEpochMillis(nonNullReader.readLong())) but this itself - // returns null which would have been passed to OffsetDateTime.ofInstant(Instant, ZoneId) which would - // have thrown a NullPointerException. - if (wireType.isNullable()) { - // Check if the property is required, if so use a holder name as there will be an existing holder - // variable for the value that will be used in the constructor. - String holderName = property.getName() + "Holder"; - deserializationBlock.line(wireType + " " + holderName + " = " + simpleDeserialization + ";"); - deserializationBlock.ifBlock(holderName + " != null", ifBlock -> - simpleDeserializationConsumer.accept(wireType.convertToClientType(holderName), ifBlock)); - } else { - simpleDeserializationConsumer.accept(wireType.convertToClientType(simpleDeserialization), - deserializationBlock); - } - } else { - simpleDeserializationConsumer.accept(simpleDeserialization, deserializationBlock); - } - } else if (wireType == ClassType.OBJECT) { - if (!hasConstructorArguments) { - handleSettingDeserializedValue(deserializationBlock, modelVariableName, model, property, - "reader.readUntyped()", fromSuper, polymorphicJsonMergePatchScenario); - } else { - deserializationBlock.line(property.getName() + " = reader.readUntyped();"); - } - } else if (wireType instanceof IterableType) { - if (!hasConstructorArguments) { - deserializationBlock.text(property.getClientType() + " "); - } - - deserializationBlock.text(property.getName() + " = "); - deserializeJsonContainerProperty(deserializationBlock, "readArray", wireType, - ((IterableType) wireType).getElementType(), ((IterableType) clientType).getElementType(), 0); - - if (!hasConstructorArguments) { - handleSettingDeserializedValue(deserializationBlock, modelVariableName, model, property, - property.getName(), fromSuper, polymorphicJsonMergePatchScenario); - } - } else if (wireType instanceof MapType) { - if (!hasConstructorArguments) { - deserializationBlock.text(property.getClientType() + " "); + private void handleFlattenedPropertiesDeserialization(JavaBlock methodBlock, JavaIfBlock ifBlock, boolean isFromJsonShared) { + // The initial call to handle flattened properties is using the base node which is just a holder. + for (JsonFlattenedPropertiesTree structure : propertiesManager.getJsonFlattenedPropertiesTree().getChildrenNodes().values()) { + handleFlattenedPropertiesDeserializationHelper(structure, methodBlock, ifBlock, isFromJsonShared, 0); } + } - // Assumption is that the key type for the Map is a String. This may not always hold true and when that - // becomes reality this will need to be reworked to handle that case. - deserializationBlock.text(property.getName() + " = "); - deserializeJsonContainerProperty(deserializationBlock, "readMap", wireType, - ((MapType) wireType).getValueType(), ((MapType) clientType).getValueType(), 0); - - if (!hasConstructorArguments) { - handleSettingDeserializedValue(deserializationBlock, modelVariableName, model, property, - property.getName(), fromSuper, polymorphicJsonMergePatchScenario); + private JavaIfBlock handleFlattenedPropertiesDeserializationHelper( + JsonFlattenedPropertiesTree flattenedProperties, JavaBlock methodBlock, JavaIfBlock ifBlock, + boolean isFromJsonShared, int depth) { + String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); + ClientModelPropertyWithMetadata propertyWithMetadata = flattenedProperties.getProperty(); + if (propertyWithMetadata != null) { + // This is a terminal location, so only need to handle checking for the property name. + return ifOrElseIf(methodBlock, ifBlock, + "\"" + flattenedProperties.getNodeName() + "\".equals(" + fieldNameVariableName + ")", + deserializationBlock -> generateJsonDeserializationLogic(deserializationBlock, + propertyWithMetadata.getProperty(), propertyWithMetadata.isFromSuperClass())); + } else { + // Otherwise this is an intermediate location and a while loop reader needs to be added. + return ifOrElseIf(methodBlock, ifBlock, + "\"" + flattenedProperties.getNodeName() + "\".equals(" + fieldNameVariableName + + ") && reader.currentToken() == JsonToken.START_OBJECT", ifAction -> { + addReaderWhileLoop(ifAction, false, false, whileBlock -> { + JavaIfBlock innerIfBlock = null; + for (JsonFlattenedPropertiesTree structure : flattenedProperties.getChildrenNodes().values()) { + innerIfBlock = handleFlattenedPropertiesDeserializationHelper(structure, methodBlock, + innerIfBlock, isFromJsonShared, depth + 1); + } + + handleUnknownJsonFieldDeserialization(whileBlock, innerIfBlock, + propertiesManager.getAdditionalProperties()); + }); + + if (isFromJsonShared && depth == 0) { + // Flattening will handle skipping and additional properties itself. + ifAction.methodReturn("true"); + } + }); } - } else { - // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. - throw new RuntimeException("Unknown wire type " + wireType + ". Need to add support for it."); } - // If the property was required, mark it as found. - if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { - deserializationBlock.line(property.getName() + "Found = true;"); - } - } + private void generateJsonDeserializationLogic(JavaBlock deserializationBlock, ClientModelProperty property, + boolean fromSuper) { + IType wireType = property.getWireType(); + IType clientType = property.getClientType(); + + // Attempt to determine whether the wire type is simple deserialization. + // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. + String simpleDeserialization = getSimpleJsonDeserialization(wireType, "reader"); + if (simpleDeserialization != null) { + // Need to convert the wire type to the client type for constructors. + // Need to convert the wire type to the client type for public setters. + boolean convertToClientType = (clientType != wireType) && ( + includePropertyInConstructor(property, settings) || (fromSuper + && !ClientModelUtil.readOnlyNotInCtor(model, property, settings))); + BiConsumer simpleDeserializationConsumer = (logic, block) -> { + if (!propertiesManager.hasConstructorArguments()) { + handleSettingDeserializedValue(block, property, logic, fromSuper); + } else { + block.line(property.getName() + " = " + logic + ";"); + } + }; - /** - * Helper method to deserialize a container property (such as {@link List} and {@link Map}). - * - * @param methodBlock The method handling deserialization. - * @param utilityMethod The method aiding in the deserialization of the container. - * @param containerType The container type. - * @param elementWireType The element type for the container, for a {@link List} this is the element type and for a - * {@link Map} this is the value type. - * @param depth Depth of recursion for container types, such as {@code Map>} would be 0 when - * {@code Map} is being handled and then 1 when {@code List} is being handled. - */ - private static void deserializeJsonContainerProperty(JavaBlock methodBlock, String utilityMethod, IType containerType, - IType elementWireType, IType elementClientType, int depth) { - String callingReaderName = depth == 0 ? "reader" : "reader" + depth; - String lambdaReaderName = "reader" + (depth + 1); - String valueDeserializationMethod = getSimpleJsonDeserialization(elementWireType, lambdaReaderName); - boolean convertToClientType = (elementClientType != elementWireType); - boolean useCodeBlockLambda = valueDeserializationMethod != null && elementWireType.isNullable() - && convertToClientType; - - if (useCodeBlockLambda) { - methodBlock.line(callingReaderName + "." + utilityMethod + "(" + lambdaReaderName + " -> {"); - } else { - methodBlock.line(callingReaderName + "." + utilityMethod + "(" + lambdaReaderName + " ->"); - } - methodBlock.indent(() -> { - if (valueDeserializationMethod != null) { if (convertToClientType) { // If the wire type is nullable don't attempt to call the convert to client type until it's known that // a value was deserialized. This protects against cases such as UnixTimeLong where the wire type is @@ -1611,926 +1488,964 @@ private static void deserializeJsonContainerProperty(JavaBlock methodBlock, Stri // reader.readNullable(nonNullReader -> Instant.ofEpochMillis(nonNullReader.readLong())) but this itself // returns null which would have been passed to OffsetDateTime.ofInstant(Instant, ZoneId) which would // have thrown a NullPointerException. - if (elementWireType.isNullable()) { + if (wireType.isNullable()) { // Check if the property is required, if so use a holder name as there will be an existing holder // variable for the value that will be used in the constructor. - String holderName = lambdaReaderName + "ValueHolder"; - methodBlock.line(elementWireType + " " + holderName + " = " + valueDeserializationMethod + ";"); - methodBlock.ifBlock(holderName + " != null", - ifBlock -> ifBlock.methodReturn(elementWireType.convertToClientType(holderName))) - .elseBlock(elseBlock -> elseBlock.methodReturn("null")); + String holderName = property.getName() + "Holder"; + deserializationBlock.line(wireType + " " + holderName + " = " + simpleDeserialization + ";"); + deserializationBlock.ifBlock(holderName + " != null", + ifBlock -> simpleDeserializationConsumer.accept(wireType.convertToClientType(holderName), + ifBlock)); } else { - methodBlock.line(elementWireType.convertToClientType(valueDeserializationMethod)); + simpleDeserializationConsumer.accept(wireType.convertToClientType(simpleDeserialization), + deserializationBlock); } } else { - methodBlock.line(valueDeserializationMethod); + simpleDeserializationConsumer.accept(simpleDeserialization, deserializationBlock); + } + } else if (wireType == ClassType.OBJECT) { + if (!propertiesManager.hasConstructorArguments()) { + handleSettingDeserializedValue(deserializationBlock, property, "reader.readUntyped()", fromSuper); + } else { + deserializationBlock.line(property.getName() + " = reader.readUntyped();"); } - } else if (elementWireType == ClassType.OBJECT) { - methodBlock.line(lambdaReaderName + ".readUntyped()"); - } else if (elementWireType instanceof IterableType) { - deserializeJsonContainerProperty(methodBlock, "readArray", elementWireType, - ((IterableType) elementWireType).getElementType(), - ((IterableType) elementClientType).getElementType(), depth + 1); - } else if (elementWireType instanceof MapType) { + } else if (wireType instanceof IterableType) { + if (!propertiesManager.hasConstructorArguments()) { + deserializationBlock.text(property.getClientType() + " "); + } + + deserializationBlock.text(property.getName() + " = "); + deserializeJsonContainerProperty(deserializationBlock, "readArray", wireType, + ((IterableType) wireType).getElementType(), ((IterableType) clientType).getElementType(), 0); + + if (!propertiesManager.hasConstructorArguments()) { + handleSettingDeserializedValue(deserializationBlock, property, property.getName(), fromSuper); + } + } else if (wireType instanceof MapType) { + if (!propertiesManager.hasConstructorArguments()) { + deserializationBlock.text(property.getClientType() + " "); + } + // Assumption is that the key type for the Map is a String. This may not always hold true and when that // becomes reality this will need to be reworked to handle that case. - deserializeJsonContainerProperty(methodBlock, "readMap", elementWireType, - ((MapType) elementWireType).getValueType(), ((MapType) elementClientType).getValueType(), - depth + 1); - } else if (elementWireType == ClassType.BINARY_DATA) { - methodBlock.line(lambdaReaderName + ".readUntyped()"); - } else { - throw new RuntimeException("Unknown value type " + elementWireType + " in " + containerType - + " serialization. Need to add support for it."); - } - }); + deserializationBlock.text(property.getName() + " = "); + deserializeJsonContainerProperty(deserializationBlock, "readMap", wireType, + ((MapType) wireType).getValueType(), ((MapType) clientType).getValueType(), 0); - if (useCodeBlockLambda) { - if (depth > 0) { - methodBlock.line("})"); + if (!propertiesManager.hasConstructorArguments()) { + handleSettingDeserializedValue(deserializationBlock, property, property.getName(), fromSuper); + } } else { - methodBlock.line("});"); + // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. + throw new RuntimeException("Unknown wire type " + wireType + ". Need to add support for it."); } - } else { - if (depth > 0) { - methodBlock.line(")"); - } else { - methodBlock.line(");"); + + // If the property was required, mark it as found. + if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { + deserializationBlock.line(property.getName() + "Found = true;"); } } - } - - private static String getSimpleJsonDeserialization(IType wireType, String readerName) { - return (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) - ? wireType + ".fromJson(" + readerName + ")" - : wireType.jsonDeserializationMethod(readerName); - } - private static void handleUnknownJsonFieldDeserialization(JavaBlock methodBlock, JavaIfBlock ifBlock, - ClientModelProperty additionalProperties, String fieldNameVariableName) { - Consumer unknownFieldConsumer = javaBlock -> { - if (additionalProperties != null) { - javaBlock.ifBlock(additionalProperties.getName() + " == null", - ifAction -> ifAction.line(additionalProperties.getName() + " = new LinkedHashMap<>();")); - javaBlock.line(); - - // Assumption, additional properties is a Map of String-Object - IType valueType = ((MapType) additionalProperties.getWireType()).getValueType(); - if (valueType == ClassType.OBJECT) { - // String fieldName should be a local variable accessible in this spot of code. - javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", reader.readUntyped());"); - } else if (valueType instanceof IterableType) { - // The case that element is a List - String varName = additionalProperties.getName() + "ArrayItem"; - javaBlock.text(valueType + " " + varName + " = "); - deserializeJsonContainerProperty(javaBlock, "readArray", valueType, - ((IterableType) valueType).getElementType(), ((IterableType) valueType).getElementType(), 0); - javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " + varName + ");"); - } else { - // Another assumption, the additional properties value type is simple. - javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " - + getSimpleJsonDeserialization(valueType, "reader") + ");"); - } + /** + * Helper method to deserialize a container property (such as {@link List} and {@link Map}). + * + * @param methodBlock The method handling deserialization. + * @param utilityMethod The method aiding in the deserialization of the container. + * @param containerType The container type. + * @param elementWireType The element type for the container, for a {@link List} this is the element type and + * for a {@link Map} this is the value type. + * @param depth Depth of recursion for container types, such as {@code Map>} would be 0 + * when {@code Map} is being handled and then 1 when {@code List} is being handled. + */ + private static void deserializeJsonContainerProperty(JavaBlock methodBlock, String utilityMethod, + IType containerType, IType elementWireType, IType elementClientType, int depth) { + String callingReaderName = depth == 0 ? "reader" : "reader" + depth; + String lambdaReaderName = "reader" + (depth + 1); + String valueDeserializationMethod = getSimpleJsonDeserialization(elementWireType, lambdaReaderName); + boolean convertToClientType = (elementClientType != elementWireType); + boolean useCodeBlockLambda = valueDeserializationMethod != null && elementWireType.isNullable() + && convertToClientType; + + if (useCodeBlockLambda) { + methodBlock.line(callingReaderName + "." + utilityMethod + "(" + lambdaReaderName + " -> {"); } else { - javaBlock.line("reader.skipChildren();"); + methodBlock.line(callingReaderName + "." + utilityMethod + "(" + lambdaReaderName + " ->"); } - }; - - if (ifBlock == null) { - unknownFieldConsumer.accept(methodBlock); - } else { - ifBlock.elseBlock(unknownFieldConsumer); - } - } - - /** - * Handles validating that all required properties have been found and creating the return type. - *

- * Properties are split into two concepts, required and optional properties, and those concepts are split into an - * additional two groups, properties declared by super types and by the model type. - * - * @param methodBlock The method handling deserialization. - * @param modelName The name of the model. - * @param propertiesManager The property manager for the model. - */ - private static void handleReadReturn(JavaBlock methodBlock, String modelName, - ClientModelPropertiesManager propertiesManager, JavaSettings settings) { - StringBuilder constructorArgs = new StringBuilder(); - - propertiesManager.forEachSuperConstructorProperty(arg -> addConstructorParameter(constructorArgs, arg.getName())); - propertiesManager.forEachConstructorProperty(arg -> addConstructorParameter(constructorArgs, arg.getName())); - - // If there are required properties of any type we must check that all required fields were found. - if (propertiesManager.hasRequiredProperties()) { - StringBuilder ifStatementBuilder = new StringBuilder(); - propertiesManager.forEachSuperRequiredProperty(property -> addRequiredCheck(ifStatementBuilder, property, settings)); - propertiesManager.forEachRequiredProperty(property -> addRequiredCheck(ifStatementBuilder, property, settings)); - - if (ifStatementBuilder.length() > 0) { - methodBlock.ifBlock(ifStatementBuilder.toString(), ifAction -> - createObjectAndReturn(methodBlock, modelName, constructorArgs.toString(), propertiesManager, settings)); - - if (propertiesManager.getRequiredPropertiesCount() == 1) { - StringBuilder stringBuilder = new StringBuilder(); - propertiesManager.forEachSuperRequiredProperty(property -> stringBuilder.append(property.getSerializedName())); - propertiesManager.forEachRequiredProperty(property -> stringBuilder.append(property.getSerializedName())); - methodBlock.line("throw new IllegalStateException(\"Missing required property: " + stringBuilder + "\");"); + methodBlock.indent(() -> { + if (valueDeserializationMethod != null) { + if (convertToClientType) { + // If the wire type is nullable don't attempt to call the convert to client type until it's known that + // a value was deserialized. This protects against cases such as UnixTimeLong where the wire type is + // Long and the client type of OffsetDateTime. This is converted using Instant.ofEpochMilli(long) which + // would result in a null if the Long is null, which is already guarded using + // reader.readNullable(nonNullReader -> Instant.ofEpochMillis(nonNullReader.readLong())) but this itself + // returns null which would have been passed to OffsetDateTime.ofInstant(Instant, ZoneId) which would + // have thrown a NullPointerException. + if (elementWireType.isNullable()) { + // Check if the property is required, if so use a holder name as there will be an existing holder + // variable for the value that will be used in the constructor. + String holderName = lambdaReaderName + "ValueHolder"; + methodBlock.line( + elementWireType + " " + holderName + " = " + valueDeserializationMethod + ";"); + methodBlock.ifBlock(holderName + " != null", + ifBlock -> ifBlock.methodReturn(elementWireType.convertToClientType(holderName))) + .elseBlock(elseBlock -> elseBlock.methodReturn("null")); + } else { + methodBlock.line(elementWireType.convertToClientType(valueDeserializationMethod)); + } + } else { + methodBlock.line(valueDeserializationMethod); + } + } else if (elementWireType == ClassType.OBJECT) { + methodBlock.line(lambdaReaderName + ".readUntyped()"); + } else if (elementWireType instanceof IterableType) { + deserializeJsonContainerProperty(methodBlock, "readArray", elementWireType, + ((IterableType) elementWireType).getElementType(), + ((IterableType) elementClientType).getElementType(), depth + 1); + } else if (elementWireType instanceof MapType) { + // Assumption is that the key type for the Map is a String. This may not always hold true and when that + // becomes reality this will need to be reworked to handle that case. + deserializeJsonContainerProperty(methodBlock, "readMap", elementWireType, + ((MapType) elementWireType).getValueType(), ((MapType) elementClientType).getValueType(), + depth + 1); + } else if (elementWireType == ClassType.BINARY_DATA) { + methodBlock.line(lambdaReaderName + ".readUntyped()"); } else { - methodBlock.line("List missingProperties = new ArrayList<>();"); - propertiesManager.forEachSuperRequiredProperty(property -> addFoundValidationIfCheck(methodBlock, property, settings)); - propertiesManager.forEachRequiredProperty(property -> addFoundValidationIfCheck(methodBlock, property, settings)); + throw new RuntimeException("Unknown value type " + elementWireType + " in " + containerType + + " serialization. Need to add support for it."); + } + }); - methodBlock.line(); - methodBlock.line("throw new IllegalStateException(\"Missing required property/properties: \" + String.join(\", \", missingProperties));"); + if (useCodeBlockLambda) { + if (depth > 0) { + methodBlock.line("})"); + } else { + methodBlock.line("});"); } } else { - createObjectAndReturn(methodBlock, modelName, constructorArgs.toString(), propertiesManager, settings); + if (depth > 0) { + methodBlock.line(")"); + } else { + methodBlock.line(");"); + } } - } else { - createObjectAndReturn(methodBlock, modelName, constructorArgs.toString(), propertiesManager, settings); } - } - - private static void createObjectAndReturn(JavaBlock methodBlock, String modelName, String constructorArgs, - ClientModelPropertiesManager propertiesManager, JavaSettings settings) { - boolean polymorphicJsonMergePatchScenario = propertiesManager.getModel().isPolymorphic() - && ClientModelUtil.isJsonMergePatchModel(propertiesManager.getModel(), settings); - if (propertiesManager.hasConstructorArguments()) { - if (propertiesManager.getSetterPropertiesCount() == 0 - && propertiesManager.getReadOnlyPropertiesCount() == 0 - && propertiesManager.getAdditionalProperties() == null - && propertiesManager.getSuperAdditionalPropertiesProperty() == null) { - methodBlock.methodReturn("new " + modelName + "(" + constructorArgs + ")"); - return; - } - - methodBlock.line(modelName + " " + propertiesManager.getDeserializedModelName() + " = new " + modelName - + "(" + constructorArgs + ");"); - BiConsumer handleSettingDeserializedValue = (property, fromSuper) -> - handleSettingDeserializedValue(methodBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), property, property.getName(), fromSuper, - polymorphicJsonMergePatchScenario); - - propertiesManager.forEachSuperReadOnlyProperty(property -> handleSettingDeserializedValue.accept(property, true)); - propertiesManager.forEachSuperSetterProperty(property -> handleSettingDeserializedValue.accept(property, true)); - propertiesManager.forEachReadOnlyProperty(property -> handleSettingDeserializedValue.accept(property, false)); - propertiesManager.forEachSetterProperty(property -> handleSettingDeserializedValue.accept(property, false)); - } - - if (propertiesManager.getAdditionalProperties() != null) { - handleSettingDeserializedValue(methodBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), propertiesManager.getAdditionalProperties(), - propertiesManager.getAdditionalProperties().getName(), false, polymorphicJsonMergePatchScenario); - } else if (propertiesManager.getSuperAdditionalPropertiesProperty() != null) { - handleSettingDeserializedValue(methodBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), propertiesManager.getSuperAdditionalPropertiesProperty(), - propertiesManager.getSuperAdditionalPropertiesProperty().getName(), true, - polymorphicJsonMergePatchScenario); - } - - methodBlock.line(); - methodBlock.methodReturn(propertiesManager.getDeserializedModelName()); - } - - private static void addConstructorParameter(StringBuilder constructor, String parameterName) { - if (constructor.length() > 0) { - constructor.append(", "); - } - - constructor.append(parameterName); - } - - private static void addRequiredCheck(StringBuilder ifCheck, ClientModelProperty property, JavaSettings settings) { - // XML attributes and text don't need checks. - if (property.isXmlAttribute() || property.isXmlText() || !includePropertyInConstructor(property, settings)) { - return; - } - - // Constants are ignored during deserialization. - if (property.isConstant()) { - return; - } - - // Required properties aren't being validated for being found. - if (settings.isDisableRequiredJsonAnnotation()) { - return; - } - - if (ifCheck.length() > 0) { - ifCheck.append(" && "); - } - - ifCheck.append(property.getName()).append("Found"); - } - - private static void addFoundValidationIfCheck(JavaBlock methodBlock, ClientModelProperty property, - JavaSettings settings) { - // XML attributes and text don't need checks. - if (property.isXmlAttribute() || property.isXmlText() || !includePropertyInConstructor(property, settings)) { - return; - } - - // Constants are ignored during deserialization. - if (property.isConstant()) { - return; - } + private static String getSimpleJsonDeserialization(IType wireType, String readerName) { + return (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) ? wireType + ".fromJson(" + + readerName + ")" : wireType.jsonDeserializationMethod(readerName); + } + + private void handleUnknownJsonFieldDeserialization(JavaBlock methodBlock, JavaIfBlock ifBlock, + ClientModelProperty additionalProperties) { + String fieldNameVariableName = propertiesManager.getJsonReaderFieldNameVariableName(); + Consumer unknownFieldConsumer = javaBlock -> { + if (additionalProperties != null) { + javaBlock.ifBlock(additionalProperties.getName() + " == null", + ifAction -> ifAction.line(additionalProperties.getName() + " = new LinkedHashMap<>();")); + javaBlock.line(); + + // Assumption, additional properties is a Map of String-Object + IType valueType = ((MapType) additionalProperties.getWireType()).getValueType(); + if (valueType == ClassType.OBJECT) { + // String fieldName should be a local variable accessible in this spot of code. + javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + + ", reader.readUntyped());"); + } else if (valueType instanceof IterableType) { + // The case that element is a List + String varName = additionalProperties.getName() + "ArrayItem"; + javaBlock.text(valueType + " " + varName + " = "); + deserializeJsonContainerProperty(javaBlock, "readArray", valueType, + ((IterableType) valueType).getElementType(), ((IterableType) valueType).getElementType(), + 0); + javaBlock.line( + additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " + varName + ");"); + } else { + // Another assumption, the additional properties value type is simple. + javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " + + getSimpleJsonDeserialization(valueType, "reader") + ");"); + } + } else { + javaBlock.line("reader.skipChildren();"); + } + }; - // Required properties aren't being validated for being found. - if (settings.isDisableRequiredJsonAnnotation()) { - return; + if (ifBlock == null) { + unknownFieldConsumer.accept(methodBlock); + } else { + ifBlock.elseBlock(unknownFieldConsumer); + } } - methodBlock.ifBlock("!" + property.getName() + "Found", - ifAction -> ifAction.line("missingProperties.add(\"" + property.getSerializedName() + "\");")); - } - - private static void handleSettingDeserializedValue(JavaBlock methodBlock, String modelVariableName, - ClientModel model, ClientModelProperty property, String value, boolean fromSuper, - boolean polymorphicJsonMergePatchScenario) { - // If the property is defined in a super class use the setter as this will be able to set the value in the - // super class. - if (fromSuper - // If the property is flattened or read-only from parent, it will be shadowed in child class. - && (!ClientModelUtil.readOnlyNotInCtor(model, property, JavaSettings.getInstance()) && !property.getClientFlatten())) { - if (polymorphicJsonMergePatchScenario) { - // Polymorphic JSON merge patch needs special handling as the setter methods are used to track whether - // the property is included in patch serialization. To prevent deserialization from requiring parent - // defined properties to always be included in serialization, access helpers are used to set the value - // without marking the property as included in the patch. - ClientModel definingModel = definingModel(model, property); - methodBlock.line("JsonMergePatchHelper.get" + definingModel.getName() + "Accessor()." - + property.getSetterName() + "(" + modelVariableName + ", " + value + ");"); + /** + * Handles validating that all required properties have been found and creating the return type. + *

+ * Properties are split into two concepts, required and optional properties, and those concepts are split into + * an additional two groups, properties declared by super types and by the model type. + * + * @param methodBlock The method handling deserialization. + */ + private void handleReadReturn(JavaBlock methodBlock) { + StringBuilder constructorArgs = new StringBuilder(); + + propertiesManager.forEachSuperConstructorProperty( + arg -> addConstructorParameter(constructorArgs, arg.getName())); + propertiesManager.forEachConstructorProperty( + arg -> addConstructorParameter(constructorArgs, arg.getName())); + + // If there are required properties of any type we must check that all required fields were found. + if (propertiesManager.hasRequiredProperties()) { + StringBuilder ifStatementBuilder = new StringBuilder(); + propertiesManager.forEachSuperRequiredProperty( + property -> addRequiredCheck(ifStatementBuilder, property)); + propertiesManager.forEachRequiredProperty(property -> addRequiredCheck(ifStatementBuilder, property)); + + if (ifStatementBuilder.length() > 0) { + methodBlock.ifBlock(ifStatementBuilder.toString(), + ifAction -> createObjectAndReturn(methodBlock, constructorArgs.toString())); + + if (propertiesManager.getRequiredPropertiesCount() == 1) { + StringBuilder stringBuilder = new StringBuilder(); + propertiesManager.forEachSuperRequiredProperty( + property -> stringBuilder.append(property.getSerializedName())); + propertiesManager.forEachRequiredProperty( + property -> stringBuilder.append(property.getSerializedName())); + methodBlock.line( + "throw new IllegalStateException(\"Missing required property: " + stringBuilder + "\");"); + } else { + methodBlock.line("List missingProperties = new ArrayList<>();"); + propertiesManager.forEachSuperRequiredProperty( + property -> addFoundValidationIfCheck(methodBlock, property)); + propertiesManager.forEachRequiredProperty( + property -> addFoundValidationIfCheck(methodBlock, property)); + + methodBlock.line(); + methodBlock.line( + "throw new IllegalStateException(\"Missing required property/properties: \" + String.join(\", \", missingProperties));"); + } + } else { + createObjectAndReturn(methodBlock, constructorArgs.toString()); + } } else { - methodBlock.line(modelVariableName + "." + property.getSetterName() + "(" + value + ");"); + createObjectAndReturn(methodBlock, constructorArgs.toString()); } - } else { - methodBlock.line(modelVariableName + "." + property.getName() + " = " + value + ";"); } - } - private static boolean isSuperTypeWithDiscriminator(ClientModel child) { - return !CoreUtils.isNullOrEmpty(child.getPolymorphicDiscriminatorName()) - && !CoreUtils.isNullOrEmpty(child.getDerivedModels()); - } + private void createObjectAndReturn(JavaBlock methodBlock, String constructorArgs) { + if (propertiesManager.hasConstructorArguments()) { + if (propertiesManager.getSetterPropertiesCount() == 0 + && propertiesManager.getReadOnlyPropertiesCount() == 0 + && propertiesManager.getAdditionalProperties() == null + && propertiesManager.getSuperAdditionalPropertiesProperty() == null) { + methodBlock.methodReturn("new " + model.getName() + "(" + constructorArgs + ")"); + return; + } + + methodBlock.line(model.getName() + " " + propertiesManager.getDeserializedModelName() + " = new " + + model.getName() + "(" + constructorArgs + ");"); + + BiConsumer handleSettingDeserializedValue + = (property, fromSuper) -> handleSettingDeserializedValue(methodBlock, property, property.getName(), + fromSuper); + + propertiesManager.forEachSuperReadOnlyProperty( + property -> handleSettingDeserializedValue.accept(property, true)); + propertiesManager.forEachSuperSetterProperty( + property -> handleSettingDeserializedValue.accept(property, true)); + propertiesManager.forEachReadOnlyProperty( + property -> handleSettingDeserializedValue.accept(property, false)); + propertiesManager.forEachSetterProperty( + property -> handleSettingDeserializedValue.accept(property, false)); + } - // TODO (alzimmer): This is a very inefficient design where we're using the ClientModelProperty to find which model - // in the polymorphic hierarchy defines it, but this is a simple bootstrapping method rather than a larger - // re-architecting. - private static ClientModel definingModel(ClientModel model, ClientModelProperty property) { - while (model != null) { - if (model.getProperties().stream().anyMatch(prop -> Objects.equals(prop.getName(), property.getName()))) { - return model; + if (propertiesManager.getAdditionalProperties() != null) { + handleSettingDeserializedValue(methodBlock, propertiesManager.getAdditionalProperties(), + propertiesManager.getAdditionalProperties().getName(), false); + } else if (propertiesManager.getSuperAdditionalPropertiesProperty() != null) { + handleSettingDeserializedValue(methodBlock, propertiesManager.getSuperAdditionalPropertiesProperty(), + propertiesManager.getSuperAdditionalPropertiesProperty().getName(), true); } - model = ClientModelUtil.getClientModel(model.getParentModelName()); + + methodBlock.line(); + methodBlock.methodReturn(propertiesManager.getDeserializedModelName()); } - throw new IllegalStateException("No ClientModel in the polymorphic hierarchy define this property, this should never happen."); - } + private static void addConstructorParameter(StringBuilder constructor, String parameterName) { + if (constructor.length() > 0) { + constructor.append(", "); + } - /** - * Helper method for adding a base if condition or an else if condition. - * - * @param baseBlock Base code block where an if condition would be added. - * @param ifBlock If block where an else if condition would be added. - * @param condition The conditional statement. - * @param action The conditional action. - * @return An if block for further chaining. - */ - private static JavaIfBlock ifOrElseIf(JavaBlock baseBlock, JavaIfBlock ifBlock, String condition, - Consumer action) { - return (ifBlock == null) ? baseBlock.ifBlock(condition, action) : ifBlock.elseIfBlock(condition, action); - } + constructor.append(parameterName); + } - private static void writeToXml(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - Consumer addGeneratedAnnotation) { - addGeneratedAnnotation.accept(classBlock); - classBlock.annotation("Override"); - classBlock.publicMethod("XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException", - methodBlock -> methodBlock.methodReturn("toXml(xmlWriter, null)")); + private void addRequiredCheck(StringBuilder ifCheck, ClientModelProperty property) { + // XML attributes and text don't need checks. + if (property.isXmlAttribute() || property.isXmlText() || !includePropertyInConstructor(property, + settings)) { + return; + } - addGeneratedAnnotation.accept(classBlock); - classBlock.annotation("Override"); - classBlock.publicMethod("XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException", methodBlock -> { - String modelXmlName = propertiesManager.getXmlRootElementName(); - methodBlock.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + modelXmlName + "\" : rootElementName;"); - methodBlock.line("xmlWriter.writeStartElement(rootElementName);"); - - String modelXmlNamespace = propertiesManager.getXmlRootElementNamespace(); - if (modelXmlNamespace != null) { - methodBlock.line("xmlWriter.writeNamespace(" + propertiesManager.getXmlNamespaceConstant(modelXmlNamespace) + ");"); + // Constants are ignored during deserialization. + if (property.isConstant()) { + return; } - propertiesManager.forEachXmlNamespaceWithPrefix((prefix, namespace) -> - methodBlock.line("xmlWriter.writeNamespace(\"" + prefix + "\", " + propertiesManager.getXmlNamespaceConstant(namespace) + ");")); + // Required properties aren't being validated for being found. + if (settings.isDisableRequiredJsonAnnotation()) { + return; + } - // Assumption for XML is polymorphic discriminators are attributes. - if (propertiesManager.getDiscriminatorProperty() != null) { - serializeXml(methodBlock, propertiesManager.getDiscriminatorProperty().getProperty(), false, - propertiesManager); + if (ifCheck.length() > 0) { + ifCheck.append(" && "); } - propertiesManager.forEachSuperXmlAttribute(property -> serializeXml(methodBlock, property, true, propertiesManager)); - propertiesManager.forEachXmlAttribute(property -> serializeXml(methodBlock, property, false, propertiesManager)); + ifCheck.append(property.getName()).append("Found"); + } - // Valid XML should only either have elements or text. - if (propertiesManager.hasXmlElements()) { - propertiesManager.forEachSuperXmlElement(property -> serializeXml(methodBlock, property, true, propertiesManager)); - propertiesManager.forEachXmlElement(property -> serializeXml(methodBlock, property, false, propertiesManager)); - } else { - propertiesManager.forEachSuperXmlText(property -> serializeXml(methodBlock, property, true, propertiesManager)); - propertiesManager.forEachXmlText(property -> serializeXml(methodBlock, property, false, propertiesManager)); + private void addFoundValidationIfCheck(JavaBlock methodBlock, ClientModelProperty property) { + // XML attributes and text don't need checks. + if (property.isXmlAttribute() || property.isXmlText() || !includePropertyInConstructor(property, + settings)) { + return; } - methodBlock.methodReturn("xmlWriter.writeEndElement()"); - }); - } + // Constants are ignored during deserialization. + if (property.isConstant()) { + return; + } - /** - * Serializes an XML element. - * - * @param methodBlock The method handling serialization. - * @param element The XML element being serialized. - * @param fromSuperType Whether the property is defined in the super type. - */ - private static void serializeXml(JavaBlock methodBlock, ClientModelProperty element, boolean fromSuperType, - ClientModelPropertiesManager propertiesManager) { - IType clientType = element.getClientType(); - IType wireType = element.getWireType(); - String propertyValueGetter; - if (fromSuperType) { - propertyValueGetter = (clientType != wireType) - ? wireType.convertFromClientType(element.getGetterName() + "()") - : element.getGetterName() + "()"; - } else { - propertyValueGetter = "this." + element.getName(); - } - - // Attempt to determine whether the wire type is simple serialization. - // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. - String xmlSerializationMethodCall = wireType.xmlSerializationMethodCall("xmlWriter", element.getXmlName(), - propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()), propertyValueGetter, - element.isXmlAttribute(), false, true); - if (xmlSerializationMethodCall != null) { - Consumer serializationLogic = javaBlock -> { - // XML text has special handling. - if (element.isXmlText()) { - javaBlock.line("xmlWriter.writeString(" + propertyValueGetter + ");"); + // Required properties aren't being validated for being found. + if (settings.isDisableRequiredJsonAnnotation()) { + return; + } + + methodBlock.ifBlock("!" + property.getName() + "Found", + ifAction -> ifAction.line("missingProperties.add(\"" + property.getSerializedName() + "\");")); + } + + private void handleSettingDeserializedValue(JavaBlock methodBlock, ClientModelProperty property, String value, + boolean fromSuper) { + String modelVariableName = propertiesManager.getDeserializedModelName(); + // If the property is defined in a super class use the setter as this will be able to set the value in the + // super class. + if (fromSuper + // If the property is flattened or read-only from parent, it will be shadowed in child class. + && (!ClientModelUtil.readOnlyNotInCtor(model, property, settings) && !property.getClientFlatten())) { + if (model.isPolymorphic() && isJsonMergePatchModel) { + // Polymorphic JSON merge patch needs special handling as the setter methods are used to track whether + // the property is included in patch serialization. To prevent deserialization from requiring parent + // defined properties to always be included in serialization, access helpers are used to set the value + // without marking the property as included in the patch. + ClientModel definingModel = ClientModelUtil.getDefiningModel(model, property); + methodBlock.line( + "JsonMergePatchHelper.get" + definingModel.getName() + "Accessor()." + property.getSetterName() + + "(" + modelVariableName + ", " + value + ");"); } else { - javaBlock.line(xmlSerializationMethodCall + ";"); + methodBlock.line(modelVariableName + "." + property.getSetterName() + "(" + value + ");"); } - }; - - // If the property is from a super type and the client type is different from the wire type then a null - // check is required to prevent a NullPointerException when converting the value. - if (fromSuperType && clientType != wireType && clientType.isNullable()) { - methodBlock.ifBlock(propertyValueGetter + " != null", serializationLogic); } else { - serializationLogic.accept(methodBlock); + methodBlock.line(modelVariableName + "." + property.getName() + " = " + value + ";"); } - } else if (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { - methodBlock.line("xmlWriter.writeXml(" + propertyValueGetter + ");"); - } else if (wireType instanceof IterableType) { - IType elementType = ((IterableType) wireType).getElementType(); - - methodBlock.ifBlock(propertyValueGetter + " != null", ifAction -> { - if (element.isXmlWrapper()) { - String writeStartElement = element.getXmlNamespace() == null - ? "xmlWriter.writeStartElement(\"" + element.getXmlName() + "\");" - : "xmlWriter.writeStartElement(" + propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()) + ", \"" + element.getXmlName() + "\");"; - ifAction.line(writeStartElement); - } + } - String xmlWrite = elementType.xmlSerializationMethodCall("xmlWriter", element.getXmlListElementName(), - propertiesManager.getXmlNamespaceConstant(element.getXmlListElementNamespace()), "element", false, - false, true); - ifAction.line("for (%s element : %s) {", elementType, propertyValueGetter); - ifAction.indent(() -> ifAction.line(xmlWrite + ";")); - ifAction.line("}"); + private static boolean isSuperTypeWithDiscriminator(ClientModel child) { + return !CoreUtils.isNullOrEmpty(child.getPolymorphicDiscriminatorName()) && !CoreUtils.isNullOrEmpty( + child.getDerivedModels()); + } - if (element.isXmlWrapper()) { - ifAction.line("xmlWriter.writeEndElement();"); - } - }); - } else if (wireType instanceof MapType) { - // Assumption is that the key type for the Map is a String. This may not always hold true and when that - // becomes reality this will need to be reworked to handle that case. - IType valueType = ((MapType) wireType).getValueType(); + /** + * Helper method for adding a base if condition or an else if condition. + * + * @param baseBlock Base code block where an if condition would be added. + * @param ifBlock If block where an else if condition would be added. + * @param condition The conditional statement. + * @param action The conditional action. + * @return An if block for further chaining. + */ + private static JavaIfBlock ifOrElseIf(JavaBlock baseBlock, JavaIfBlock ifBlock, String condition, + Consumer action) { + return (ifBlock == null) ? baseBlock.ifBlock(condition, action) : ifBlock.elseIfBlock(condition, action); + } - methodBlock.ifBlock(propertyValueGetter + " != null", ifAction -> { - ifAction.line("xmlWriter.writeStartElement(\"" + element.getXmlName() + "\");"); + private void writeToXml(JavaClass classBlock) { + addGeneratedAnnotation.accept(classBlock); + classBlock.annotation("Override"); + classBlock.publicMethod("XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException", + methodBlock -> methodBlock.methodReturn("toXml(xmlWriter, null)")); - if (valueType instanceof ClassType && ((ClassType) valueType).isSwaggerType()) { - String writeStartElement = (element.getXmlNamespace() != null) - ? "xmlWriter.writeStartElement(" + propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()) + ", key);" - : "xmlWriter.writeStartElement(key);"; + addGeneratedAnnotation.accept(classBlock); + classBlock.annotation("Override"); + classBlock.publicMethod( + "XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException", + methodBlock -> { + String modelXmlName = propertiesManager.getXmlRootElementName(); + methodBlock.line("rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? \"" + modelXmlName + + "\" : rootElementName;"); + methodBlock.line("xmlWriter.writeStartElement(rootElementName);"); + + String modelXmlNamespace = propertiesManager.getXmlRootElementNamespace(); + if (modelXmlNamespace != null) { + methodBlock.line( + "xmlWriter.writeNamespace(" + propertiesManager.getXmlNamespaceConstant(modelXmlNamespace) + + ");"); + } - ifAction.line("for (Map.Entry entry : %s.entrySet()) {", valueType, propertyValueGetter); - ifAction.indent(() -> { - ifAction.line(writeStartElement); - ifAction.line("xmlWriter.writeXml(entry.getValue());"); - ifAction.line("xmlWriter.writeEndElement();"); - }); - ifAction.line("}"); - } else { - String xmlWrite = valueType.xmlSerializationMethodCall("xmlWriter", "entry.getKey()", - propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()), "entry.getValue()", false, - true, true); + propertiesManager.forEachXmlNamespaceWithPrefix((prefix, namespace) -> methodBlock.line( + "xmlWriter.writeNamespace(\"" + prefix + "\", " + propertiesManager.getXmlNamespaceConstant( + namespace) + ");")); - ifAction.line("for (Map.Entry entry : %s.entrySet()) {", valueType, propertyValueGetter); - ifAction.indent(() -> ifAction.line(xmlWrite + ";")); - ifAction.line("}"); - } + // Assumption for XML is polymorphic discriminators are attributes. + if (propertiesManager.getDiscriminatorProperty() != null) { + serializeXml(methodBlock, propertiesManager.getDiscriminatorProperty().getProperty(), false); + } - ifAction.line("xmlWriter.writeEndElement();"); - }); - } else { - // TODO (alzimmer): Resolve this as serialization logic generation needs to handle all cases. - throw new RuntimeException("Unknown wire type " + wireType + " in XML element serialization. " - + "Need to add support for it."); - } - } + propertiesManager.forEachSuperXmlAttribute(property -> serializeXml(methodBlock, property, true)); + propertiesManager.forEachXmlAttribute(property -> serializeXml(methodBlock, property, false)); - private static void writeFromXml(JavaClass classBlock, ClientModel model, - ClientModelPropertiesManager propertiesManager, JavaSettings settings, - Consumer addGeneratedAnnotation) { - if (isSuperTypeWithDiscriminator(model)) { - writeSuperTypeFromXml(classBlock, model, propertiesManager, settings, addGeneratedAnnotation); - } else { - writeTerminalTypeFromXml(classBlock, propertiesManager, settings, addGeneratedAnnotation); + // Valid XML should only either have elements or text. + if (propertiesManager.hasXmlElements()) { + propertiesManager.forEachSuperXmlElement(property -> serializeXml(methodBlock, property, true)); + propertiesManager.forEachXmlElement(property -> serializeXml(methodBlock, property, false)); + } else { + propertiesManager.forEachSuperXmlText(property -> serializeXml(methodBlock, property, true)); + propertiesManager.forEachXmlText(property -> serializeXml(methodBlock, property, false)); + } + + methodBlock.methodReturn("xmlWriter.writeEndElement()"); + }); } - } - /** - * Writes a super type's {@code fromXml(XmlReader)} method. - * - * @param classBlock The class having {@code fromXml(XmlReader)} written to it. - * @param model The Autorest representation of the model. - * @param propertiesManager The properties for the model. - * @param settings The Autorest generation settings. - * @param addGeneratedAnnotation Consumer for adding the generated annotation to the class. - */ - private static void writeSuperTypeFromXml(JavaClass classBlock, ClientModel model, - ClientModelPropertiesManager propertiesManager, JavaSettings settings, - Consumer addGeneratedAnnotation) { - // Handling polymorphic fields while determining which subclass, or the class itself, to deserialize handles the - // discriminator type always as a String. This is permissible as the found discriminator is never being used in - // a setter or for setting a field, unlike in the actual deserialization method where it needs to be the same - // type as the field. - ClientModelProperty discriminatorProperty = propertiesManager.getDiscriminatorProperty().getProperty(); - readXmlObject(classBlock, propertiesManager, false, methodBlock -> { - // Assumption for now for XML, only XML properties are used for handling inheritance. - // If this found to be wrong in the future copy the concept of bufferObject and resettable from azure-json - // into azure-xml as bufferElement and resettable. - methodBlock.line("// Get the XML discriminator attribute."); - if (discriminatorProperty.getXmlNamespace() != null) { - methodBlock.line("String discriminatorValue = reader.getStringAttribute(" - + propertiesManager.getXmlNamespaceConstant(discriminatorProperty.getXmlNamespace()) + ", " - + "\"" + discriminatorProperty.getSerializedName() + "\");"); + /** + * Serializes an XML element. + * + * @param methodBlock The method handling serialization. + * @param element The XML element being serialized. + * @param fromSuperType Whether the property is defined in the super type. + */ + private void serializeXml(JavaBlock methodBlock, ClientModelProperty element, boolean fromSuperType) { + IType clientType = element.getClientType(); + IType wireType = element.getWireType(); + String propertyValueGetter; + if (fromSuperType) { + propertyValueGetter = (clientType != wireType) ? wireType.convertFromClientType( + element.getGetterName() + "()") : element.getGetterName() + "()"; } else { - methodBlock.line("String discriminatorValue = reader.getStringAttribute(" - + "\"" + discriminatorProperty.getSerializedName() + "\");"); + propertyValueGetter = "this." + element.getName(); } - methodBlock.line("// Use the discriminator value to determine which subtype should be deserialized."); + // Attempt to determine whether the wire type is simple serialization. + // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. + String xmlSerializationMethodCall = wireType.xmlSerializationMethodCall("xmlWriter", element.getXmlName(), + propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()), propertyValueGetter, + element.isXmlAttribute(), false, true); + if (xmlSerializationMethodCall != null) { + Consumer serializationLogic = javaBlock -> { + // XML text has special handling. + if (element.isXmlText()) { + javaBlock.line("xmlWriter.writeString(" + propertyValueGetter + ");"); + } else { + javaBlock.line(xmlSerializationMethodCall + ";"); + } + }; - // Add deserialization for the super type itself. - JavaIfBlock ifBlock = null; + // If the property is from a super type and the client type is different from the wire type then a null + // check is required to prevent a NullPointerException when converting the value. + if (fromSuperType && clientType != wireType && clientType.isNullable()) { + methodBlock.ifBlock(propertyValueGetter + " != null", serializationLogic); + } else { + serializationLogic.accept(methodBlock); + } + } else if (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { + methodBlock.line("xmlWriter.writeXml(" + propertyValueGetter + ");"); + } else if (wireType instanceof IterableType) { + IType elementType = ((IterableType) wireType).getElementType(); + + methodBlock.ifBlock(propertyValueGetter + " != null", ifAction -> { + if (element.isXmlWrapper()) { + String writeStartElement = element.getXmlNamespace() == null + ? "xmlWriter.writeStartElement(\"" + element.getXmlName() + "\");" + : "xmlWriter.writeStartElement(" + propertiesManager.getXmlNamespaceConstant( + element.getXmlNamespace()) + ", \"" + element.getXmlName() + "\");"; + ifAction.line(writeStartElement); + } - // Add deserialization for all child types. - List childTypes = getAllChildTypes(model, new ArrayList<>()); - for (ClientModel childType : childTypes) { - ifBlock = ifOrElseIf(methodBlock, ifBlock, "\"" + childType.getSerializedName() + "\".equals(discriminatorValue)", - ifStatement -> ifStatement.methodReturn(childType.getName() + (isSuperTypeWithDiscriminator(childType) - ? ".fromXmlInternal(reader, finalRootElementName)" - : ".fromXml(reader, finalRootElementName)"))); - } + String xmlWrite = elementType.xmlSerializationMethodCall("xmlWriter", + element.getXmlListElementName(), + propertiesManager.getXmlNamespaceConstant(element.getXmlListElementNamespace()), "element", + false, false, true); + ifAction.line("for (%s element : %s) {", elementType, propertyValueGetter); + ifAction.indent(() -> ifAction.line(xmlWrite + ";")); + ifAction.line("}"); - if (ifBlock == null) { - methodBlock.methodReturn("fromXmlInternal(reader, finalRootElementName)"); + if (element.isXmlWrapper()) { + ifAction.line("xmlWriter.writeEndElement();"); + } + }); + } else if (wireType instanceof MapType) { + // Assumption is that the key type for the Map is a String. This may not always hold true and when that + // becomes reality this will need to be reworked to handle that case. + IType valueType = ((MapType) wireType).getValueType(); + + methodBlock.ifBlock(propertyValueGetter + " != null", ifAction -> { + ifAction.line("xmlWriter.writeStartElement(\"" + element.getXmlName() + "\");"); + + if (valueType instanceof ClassType && ((ClassType) valueType).isSwaggerType()) { + String writeStartElement = (element.getXmlNamespace() != null) + ? "xmlWriter.writeStartElement(" + propertiesManager.getXmlNamespaceConstant( + element.getXmlNamespace()) + ", key);" + : "xmlWriter.writeStartElement(key);"; + + ifAction.line("for (Map.Entry entry : %s.entrySet()) {", valueType, + propertyValueGetter); + ifAction.indent(() -> { + ifAction.line(writeStartElement); + ifAction.line("xmlWriter.writeXml(entry.getValue());"); + ifAction.line("xmlWriter.writeEndElement();"); + }); + ifAction.line("}"); + } else { + String xmlWrite = valueType.xmlSerializationMethodCall("xmlWriter", "entry.getKey()", + propertiesManager.getXmlNamespaceConstant(element.getXmlNamespace()), "entry.getValue()", + false, true, true); + + ifAction.line("for (Map.Entry entry : %s.entrySet()) {", valueType, + propertyValueGetter); + ifAction.indent(() -> ifAction.line(xmlWrite + ";")); + ifAction.line("}"); + } + + ifAction.line("xmlWriter.writeEndElement();"); + }); } else { - ifBlock.elseBlock(elseBlock -> elseBlock.methodReturn("fromXmlInternal(reader, finalRootElementName)")); + // TODO (alzimmer): Resolve this as serialization logic generation needs to handle all cases. + throw new RuntimeException("Unknown wire type " + wireType + " in XML element serialization. " + + "Need to add support for it."); } - }, addGeneratedAnnotation); - - readXmlObject(classBlock, propertiesManager, true, - methodBlock -> writeFromXmlDeserialization(methodBlock, propertiesManager, settings), - addGeneratedAnnotation); - } - - /** - * Adds a static method to the class with the signature that handles reading the XML string into the object type. - *

- * If {@code superTypeReading} is true the method will be package-private and named - * {@code fromXmlWithKnownDiscriminator} instead of being public and named {@code fromXml}. This is done as super - * types use their {@code fromXml} method to determine the discriminator value and pass the reader to the specific - * type being deserialized. The specific type being deserialized may be the super type itself, so it cannot pass to - * {@code fromXml} as this will be a circular call and if the specific type being deserialized is an intermediate - * type (a type having both super and subclasses) it will attempt to perform discriminator validation which has - * already been done. - * - * @param classBlock The class where the {@code fromXml} method is being written. - * @param propertiesManager Properties information about the object being deserialized. - * @param superTypeReading Whether the object reading is for a super type. - * @param deserializationBlock Logic for deserializing the object. - * @param addGeneratedAnnotation Consumer for adding the generated annotation to the class. - */ - private static void readXmlObject(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - boolean superTypeReading, Consumer deserializationBlock, - Consumer addGeneratedAnnotation) { - JavaVisibility visibility = superTypeReading ? JavaVisibility.PackagePrivate : JavaVisibility.Public; - String methodName = superTypeReading ? "fromXmlInternal" : "fromXml"; - - String modelName = propertiesManager.getModel().getName(); - boolean hasRequiredProperties = propertiesManager.hasConstructorArguments(); - boolean isPolymorphic = propertiesManager.getDiscriminatorProperty() != null - && CoreUtils.isNullOrEmpty(propertiesManager.getModel().getDerivedModels()); - - if (!superTypeReading) { - fromXmlJavadoc(classBlock, modelName, false, hasRequiredProperties, isPolymorphic); - addGeneratedAnnotation.accept(classBlock); - classBlock.publicStaticMethod(modelName + " fromXml(XmlReader xmlReader) throws XMLStreamException", - methodBlock -> methodBlock.methodReturn("fromXml(xmlReader, null)")); - - fromXmlJavadoc(classBlock, modelName, true, hasRequiredProperties, isPolymorphic); } - addGeneratedAnnotation.accept(classBlock); - classBlock.staticMethod(visibility, modelName + " " + methodName + "(XmlReader xmlReader, String rootElementName) throws XMLStreamException", methodBlock -> { - // For now, use the basic readObject which will return null if the XmlReader is pointing to JsonToken.NULL. - // - // Support for a default value if null will need to be supported and for objects that get their value - // from a JSON value instead of JSON object or are an array type. - String requiredElementName = propertiesManager.getXmlRootElementName(); - String requiredNamespace = propertiesManager.getXmlRootElementNamespace(); + /** + * Writes a super type's {@code fromXml(XmlReader)} method. + * + * @param classBlock The class having {@code fromXml(XmlReader)} written to it. + */ + private void writeSuperTypeFromXml(JavaClass classBlock) { + // Handling polymorphic fields while determining which subclass, or the class itself, to deserialize handles the + // discriminator type always as a String. This is permissible as the found discriminator is never being used in + // a setter or for setting a field, unlike in the actual deserialization method where it needs to be the same + // type as the field. + ClientModelProperty discriminatorProperty = propertiesManager.getDiscriminatorProperty().getProperty(); + readXmlObject(classBlock, false, methodBlock -> { + // Assumption for now for XML, only XML properties are used for handling inheritance. + // If this found to be wrong in the future copy the concept of bufferObject and resettable from azure-json + // into azure-xml as bufferElement and resettable. + methodBlock.line("// Get the XML discriminator attribute."); + if (discriminatorProperty.getXmlNamespace() != null) { + methodBlock.line("String discriminatorValue = reader.getStringAttribute(" + + propertiesManager.getXmlNamespaceConstant(discriminatorProperty.getXmlNamespace()) + ", " + + "\"" + discriminatorProperty.getSerializedName() + "\");"); + } else { + methodBlock.line("String discriminatorValue = reader.getStringAttribute(" + "\"" + + discriminatorProperty.getSerializedName() + "\");"); + } - methodBlock.line("String finalRootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? " - + "\"" + requiredElementName + "\" : rootElementName;"); - if (requiredNamespace != null) { - methodBlock.line("return xmlReader.readObject(" + propertiesManager.getXmlNamespaceConstant(requiredNamespace) + ", finalRootElementName, reader -> {"); - } else { - methodBlock.line("return xmlReader.readObject(finalRootElementName, reader -> {"); - } + methodBlock.line("// Use the discriminator value to determine which subtype should be deserialized."); - deserializationBlock.accept(methodBlock); + // Add deserialization for the super type itself. + JavaIfBlock ifBlock = null; - methodBlock.line("});"); - }); - } + // Add deserialization for all child types. + List childTypes = getAllChildTypes(model, new ArrayList<>()); + for (ClientModel childType : childTypes) { + ifBlock = ifOrElseIf(methodBlock, ifBlock, + "\"" + childType.getSerializedName() + "\".equals(discriminatorValue)", + ifStatement -> ifStatement.methodReturn( + childType.getName() + (isSuperTypeWithDiscriminator(childType) + ? ".fromXmlInternal(reader, finalRootElementName)" + : ".fromXml(reader, finalRootElementName)"))); + } - private static void fromXmlJavadoc(JavaClass classBlock, String modelName, boolean hasRootElementName, - boolean hasRequiredProperties, boolean isPolymorphic) { - classBlock.javadocComment(javadocComment -> { - javadocComment.description("Reads an instance of " + modelName + " from the XmlReader."); - javadocComment.param("xmlReader", "The XmlReader being read."); - if (hasRootElementName) { - javadocComment.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."); - } - javadocComment.methodReturns("An instance of " + modelName + " if the XmlReader was pointing to an " - + "instance of it, or null if it was pointing to XML null."); - - // TODO (alzimmer): Make the throws statement more descriptive by including the polymorphic - // discriminator property name and the required property names. For now this covers the base functionality. - String throwsStatement = null; - if (hasRequiredProperties && isPolymorphic) { - throwsStatement = "If the deserialized XML object was missing any required properties or the " - + "polymorphic discriminator value is invalid."; - } else if (hasRequiredProperties) { - throwsStatement = "If the deserialized XML object was missing any required properties."; - } else if (isPolymorphic) { - throwsStatement = "If the deserialized XML object has an invalid polymorphic discriminator value."; - } + if (ifBlock == null) { + methodBlock.methodReturn("fromXmlInternal(reader, finalRootElementName)"); + } else { + ifBlock.elseBlock( + elseBlock -> elseBlock.methodReturn("fromXmlInternal(reader, finalRootElementName)")); + } + }); - if (throwsStatement != null) { - javadocComment.methodThrows("IllegalStateException", throwsStatement); + readXmlObject(classBlock, true, this::writeFromXmlDeserialization); + } + + /** + * Adds a static method to the class with the signature that handles reading the XML string into the object + * type. + *

+ * If {@code superTypeReading} is true the method will be package-private and named + * {@code fromXmlWithKnownDiscriminator} instead of being public and named {@code fromXml}. This is done as + * super types use their {@code fromXml} method to determine the discriminator value and pass the reader to the + * specific type being deserialized. The specific type being deserialized may be the super type itself, so it + * cannot pass to {@code fromXml} as this will be a circular call and if the specific type being deserialized is + * an intermediate type (a type having both super and subclasses) it will attempt to perform discriminator + * validation which has already been done. + * + * @param classBlock The class where the {@code fromXml} method is being written. + * @param superTypeReading Whether the object reading is for a super type. + * @param deserializationBlock Logic for deserializing the object. + */ + private void readXmlObject(JavaClass classBlock, boolean superTypeReading, + Consumer deserializationBlock) { + JavaVisibility visibility = superTypeReading ? JavaVisibility.PackagePrivate : JavaVisibility.Public; + String methodName = superTypeReading ? "fromXmlInternal" : "fromXml"; + + if (!superTypeReading) { + fromXmlJavadoc(classBlock, false); + addGeneratedAnnotation.accept(classBlock); + classBlock.publicStaticMethod( + model.getName() + " fromXml(XmlReader xmlReader) throws XMLStreamException", + methodBlock -> methodBlock.methodReturn("fromXml(xmlReader, null)")); + + fromXmlJavadoc(classBlock, true); } - javadocComment.methodThrows("XMLStreamException", "If an error occurs while reading the " + modelName + "."); - }); - } + addGeneratedAnnotation.accept(classBlock); + classBlock.staticMethod(visibility, model.getName() + " " + methodName + + "(XmlReader xmlReader, String rootElementName) throws XMLStreamException", methodBlock -> { + // For now, use the basic readObject which will return null if the XmlReader is pointing to JsonToken.NULL. + // + // Support for a default value if null will need to be supported and for objects that get their value + // from a JSON value instead of JSON object or are an array type. + String requiredElementName = propertiesManager.getXmlRootElementName(); + String requiredNamespace = propertiesManager.getXmlRootElementNamespace(); + + methodBlock.line("String finalRootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? " + "\"" + + requiredElementName + "\" : rootElementName;"); + if (requiredNamespace != null) { + methodBlock.line( + "return xmlReader.readObject(" + propertiesManager.getXmlNamespaceConstant(requiredNamespace) + + ", finalRootElementName, reader -> {"); + } else { + methodBlock.line("return xmlReader.readObject(finalRootElementName, reader -> {"); + } - /** - * Writes a terminal type's {@code fromXml(XmlReader)} method. - *

- * A terminal type is either a type without polymorphism or is the terminal type in a polymorphic hierarchy. - * - * @param classBlock The class having {@code fromXml(XmlReader)} written to it. - * @param propertiesManager The properties for the model. - * @param settings The Autorest generation settings. - * @param addGeneratedAnnotation Consumer for adding the generated annotation to the class. - */ - private static void writeTerminalTypeFromXml(JavaClass classBlock, ClientModelPropertiesManager propertiesManager, - JavaSettings settings, Consumer addGeneratedAnnotation) { - readXmlObject(classBlock, propertiesManager, false, - methodBlock -> writeFromXmlDeserialization(methodBlock, propertiesManager, settings), - addGeneratedAnnotation); - } + deserializationBlock.accept(methodBlock); + + methodBlock.line("});"); + }); + } - private static void writeFromXmlDeserialization(JavaBlock methodBlock, - ClientModelPropertiesManager propertiesManager, JavaSettings settings) { + private void fromXmlJavadoc(JavaClass classBlock, boolean hasRootElementName) { + classBlock.javadocComment(javadocComment -> { + javadocComment.description("Reads an instance of " + model.getName() + " from the XmlReader."); + javadocComment.param("xmlReader", "The XmlReader being read."); + if (hasRootElementName) { + javadocComment.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."); + } + javadocComment.methodReturns( + "An instance of " + model.getName() + " if the XmlReader was pointing to an " + + "instance of it, or null if it was pointing to XML null."); + + // TODO (alzimmer): Make the throws statement more descriptive by including the polymorphic + // discriminator property name and the required property names. For now this covers the base functionality. + String throwsStatement = null; + if (propertiesManager.hasConstructorArguments() && model.isPolymorphic()) { + throwsStatement = "If the deserialized XML object was missing any required properties or the " + + "polymorphic discriminator value is invalid."; + } else if (propertiesManager.hasConstructorArguments()) { + throwsStatement = "If the deserialized XML object was missing any required properties."; + } else if (model.isPolymorphic()) { + throwsStatement = "If the deserialized XML object has an invalid polymorphic discriminator value."; + } - // Add the deserialization logic. - methodBlock.indent(() -> { - // Initialize local variables to track what has been deserialized. - initializeLocalVariables(methodBlock, propertiesManager, true, settings); + if (throwsStatement != null) { + javadocComment.methodThrows("IllegalStateException", throwsStatement); + } - // Assumption for XML is polymorphic discriminators are attributes. - if (propertiesManager.getDiscriminatorProperty() != null) { - deserializeXmlAttribute(methodBlock, propertiesManager.getDiscriminatorProperty().getProperty(), - propertiesManager, false); - } + javadocComment.methodThrows("XMLStreamException", + "If an error occurs while reading the " + model.getName() + "."); + }); + } - // Read the XML attribute properties first. - propertiesManager.forEachSuperXmlAttribute(attribute -> deserializeXmlAttribute(methodBlock, attribute, - propertiesManager, true)); - propertiesManager.forEachXmlAttribute(attribute -> deserializeXmlAttribute(methodBlock, attribute, - propertiesManager, false)); + /** + * Writes a terminal type's {@code fromXml(XmlReader)} method. + *

+ * A terminal type is either a type without polymorphism or is the terminal type in a polymorphic hierarchy. + * + * @param classBlock The class having {@code fromXml(XmlReader)} written to it. + */ + private void writeTerminalTypeFromXml(JavaClass classBlock) { + readXmlObject(classBlock, false, this::writeFromXmlDeserialization); + } - // Read the XML text next. - propertiesManager.forEachSuperXmlText(text -> deserializeXmlText(methodBlock, text, propertiesManager, true)); - propertiesManager.forEachXmlText(text -> deserializeXmlText(methodBlock, text, propertiesManager, false)); + private void writeFromXmlDeserialization(JavaBlock methodBlock) { + // Add the deserialization logic. + methodBlock.indent(() -> { + // Initialize local variables to track what has been deserialized. + initializeLocalVariables(methodBlock, true); - // Model didn't have any XML elements, return early. - String fieldNameVariableName = propertiesManager.getXmlReaderNameVariableName(); - if (!propertiesManager.hasXmlElements()) { - // If the model was attributes only a simplified read loop is needed to ensure the end element token - // is reached. - if (!propertiesManager.hasXmlTexts()) { - methodBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", - whileBlock -> whileBlock.line("reader.skipElement();")); + // Assumption for XML is polymorphic discriminators are attributes. + if (propertiesManager.getDiscriminatorProperty() != null) { + deserializeXmlAttribute(methodBlock, propertiesManager.getDiscriminatorProperty().getProperty(), + false); } - return; - } - - // Add the outermost while loop to read the JSON object. - addReaderWhileLoop(methodBlock, true, fieldNameVariableName, true, whileBlock -> { - JavaIfBlock ifBlock = null; - if (propertiesManager.getDiscriminatorProperty() != null - && !propertiesManager.getDiscriminatorProperty().getProperty().isXmlAttribute()) { - ClientModelProperty discriminatorProperty = propertiesManager.getDiscriminatorProperty() - .getProperty(); - String ifStatement = String.format("\"%s\".equals(%s)", propertiesManager.getExpectedDiscriminator(), - fieldNameVariableName); - - ifBlock = methodBlock.ifBlock(ifStatement, ifAction -> { - ifAction.line("String %s = reader.getStringElement().getLocalPart();", discriminatorProperty.getName()); - String ifStatement2 = String.format("!%s.equals(%s)", discriminatorProperty.getDefaultValue(), - discriminatorProperty.getName()); - ifAction.ifBlock(ifStatement2, ifAction2 -> ifAction2.line( - "throw new IllegalStateException(\"'%s' was expected to be non-null and equal to '\"%s\"'. " - + "The found '%s' was '\" + %s + \"'.\");", - discriminatorProperty.getSerializedName(), propertiesManager.getExpectedDiscriminator(), - discriminatorProperty.getSerializedName(), discriminatorProperty.getName())); - }); + // Read the XML attribute properties first. + propertiesManager.forEachSuperXmlAttribute( + attribute -> deserializeXmlAttribute(methodBlock, attribute, true)); + propertiesManager.forEachXmlAttribute( + attribute -> deserializeXmlAttribute(methodBlock, attribute, false)); + + // Read the XML text next. + propertiesManager.forEachSuperXmlText(text -> deserializeXmlText(methodBlock, text, true)); + propertiesManager.forEachXmlText(text -> deserializeXmlText(methodBlock, text, false)); + + // Model didn't have any XML elements, return early. + String fieldNameVariableName = propertiesManager.getXmlReaderNameVariableName(); + if (!propertiesManager.hasXmlElements()) { + // If the model was attributes only a simplified read loop is needed to ensure the end element token + // is reached. + if (!propertiesManager.hasXmlTexts()) { + methodBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", + whileBlock -> whileBlock.line("reader.skipElement();")); + } + return; } - // Loop over all properties and generate their deserialization handling. - AtomicReference ifBlockReference = new AtomicReference<>(ifBlock); - propertiesManager.forEachSuperXmlElement(element -> handleXmlPropertyDeserialization(element, - whileBlock, ifBlockReference, fieldNameVariableName, propertiesManager, true, settings)); - propertiesManager.forEachXmlElement(element -> handleXmlPropertyDeserialization(element, whileBlock, - ifBlockReference, fieldNameVariableName, propertiesManager, false, settings)); + // Add the outermost while loop to read the JSON object. + addReaderWhileLoop(methodBlock, true, true, whileBlock -> { + JavaIfBlock ifBlock = null; + + if (propertiesManager.getDiscriminatorProperty() != null + && !propertiesManager.getDiscriminatorProperty().getProperty().isXmlAttribute()) { + ClientModelProperty discriminatorProperty = propertiesManager.getDiscriminatorProperty() + .getProperty(); + String ifStatement = String.format("\"%s\".equals(%s)", + propertiesManager.getExpectedDiscriminator(), fieldNameVariableName); + + ifBlock = methodBlock.ifBlock(ifStatement, ifAction -> { + ifAction.line("String %s = reader.getStringElement().getLocalPart();", + discriminatorProperty.getName()); + String ifStatement2 = String.format("!%s.equals(%s)", + discriminatorProperty.getDefaultValue(), discriminatorProperty.getName()); + ifAction.ifBlock(ifStatement2, ifAction2 -> ifAction2.line( + "throw new IllegalStateException(\"'%s' was expected to be non-null and equal to '\"%s\"'. " + + "The found '%s' was '\" + %s + \"'.\");", + discriminatorProperty.getSerializedName(), propertiesManager.getExpectedDiscriminator(), + discriminatorProperty.getSerializedName(), discriminatorProperty.getName())); + }); + } - ifBlock = ifBlockReference.get(); + // Loop over all properties and generate their deserialization handling. + AtomicReference ifBlockReference = new AtomicReference<>(ifBlock); + propertiesManager.forEachSuperXmlElement( + element -> handleXmlPropertyDeserialization(element, whileBlock, ifBlockReference, true)); + propertiesManager.forEachXmlElement( + element -> handleXmlPropertyDeserialization(element, whileBlock, ifBlockReference, false)); - // All properties have been checked for, add an else block that will either ignore unknown properties - // or add them into an additional properties bag. - ClientModelProperty additionalProperty = getAdditionalPropertiesPropertyInModelOrFromSuper(propertiesManager); - handleUnknownXmlFieldDeserialization(whileBlock, ifBlock, additionalProperty, - propertiesManager.getXmlReaderNameVariableName()); + ifBlock = ifBlockReference.get(); + + // All properties have been checked for, add an else block that will either ignore unknown + // properties or add them into an additional properties bag. + handleUnknownXmlFieldDeserialization(whileBlock, ifBlock); + }); }); - }); - // Add the validation and return logic. - handleReadReturn(methodBlock, propertiesManager.getModel().getName(), propertiesManager, settings); - } + // Add the validation and return logic. + handleReadReturn(methodBlock); + } - private static void deserializeXmlAttribute(JavaBlock methodBlock, ClientModelProperty attribute, - ClientModelPropertiesManager propertiesManager, boolean fromSuper) { - String xmlAttributeDeserialization = getSimpleXmlDeserialization(attribute.getWireType(), "reader", null, + private void deserializeXmlAttribute(JavaBlock methodBlock, ClientModelProperty attribute, boolean fromSuper) { + String xmlAttributeDeserialization = getSimpleXmlDeserialization(attribute.getWireType(), null, attribute.getXmlName(), propertiesManager.getXmlNamespaceConstant(attribute.getXmlNamespace()), true); - if (attribute.isPolymorphicDiscriminator() - && CoreUtils.isNullOrEmpty(propertiesManager.getModel().getDerivedModels())) { - // Only validate the discriminator if the model has no derived models. - // Super types will deserialize as themselves if the discriminator doesn't match what's expected. - methodBlock.line("String discriminatorValue = " + xmlAttributeDeserialization + ";"); - String ifStatement = String.format("!%s.equals(discriminatorValue)", attribute.getDefaultValue()); - methodBlock.ifBlock(ifStatement, ifAction2 -> ifAction2.line( - "throw new IllegalStateException(\"'%s' was expected to be non-null and equal to '%s'. " - + "The found '%s' was '\" + discriminatorValue + \"'.\");", - attribute.getSerializedName(), propertiesManager.getExpectedDiscriminator(), - attribute.getSerializedName())); + if (attribute.isPolymorphicDiscriminator() && CoreUtils.isNullOrEmpty(model.getDerivedModels())) { + // Only validate the discriminator if the model has no derived models. + // Super types will deserialize as themselves if the discriminator doesn't match what's expected. + methodBlock.line("String discriminatorValue = " + xmlAttributeDeserialization + ";"); + String ifStatement = String.format("!%s.equals(discriminatorValue)", attribute.getDefaultValue()); + methodBlock.ifBlock(ifStatement, ifAction2 -> ifAction2.line( + "throw new IllegalStateException(\"'%s' was expected to be non-null and equal to '%s'. " + + "The found '%s' was '\" + discriminatorValue + \"'.\");", attribute.getSerializedName(), + propertiesManager.getExpectedDiscriminator(), attribute.getSerializedName())); + + xmlAttributeDeserialization = "discriminatorValue"; + } - xmlAttributeDeserialization = "discriminatorValue"; + if (propertiesManager.hasConstructorArguments()) { + methodBlock.line(attribute.getClientType() + " " + attribute.getName() + " = " + xmlAttributeDeserialization + ";"); + } else { + handleSettingDeserializedValue(methodBlock, attribute, xmlAttributeDeserialization, fromSuper); + } } - if (propertiesManager.hasConstructorArguments()) { - methodBlock.line("%s %s = %s;", attribute.getClientType(), attribute.getName(), xmlAttributeDeserialization); - } else { - handleSettingDeserializedValue(methodBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), attribute, xmlAttributeDeserialization, fromSuper, false); + private void deserializeXmlText(JavaBlock methodBlock, ClientModelProperty text, boolean fromSuper) { + String xmlTextDeserialization = getSimpleXmlDeserialization(text.getWireType(), null, null, null, + false); + if (propertiesManager.hasConstructorArguments()) { + methodBlock.line(text.getClientType() + " " + text.getName() + " = " + xmlTextDeserialization + ";"); + } else { + handleSettingDeserializedValue(methodBlock, text, xmlTextDeserialization, fromSuper); + } } - } - private static void deserializeXmlText(JavaBlock methodBlock, ClientModelProperty text, - ClientModelPropertiesManager propertiesManager, boolean fromSuper) { - String xmlTextDeserialization = getSimpleXmlDeserialization(text.getWireType(), "reader", null, null, null, false); - if (propertiesManager.hasConstructorArguments()) { - methodBlock.line(text.getClientType() + " " + text.getName() + " = " + xmlTextDeserialization + ";"); - } else { - handleSettingDeserializedValue(methodBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), text, xmlTextDeserialization, fromSuper, false); - } - } + private void handleXmlPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, + AtomicReference ifBlockReference, boolean fromSuper) { + // Property will be handled later by flattened deserialization. + // XML should never have flattening. + if (property.getNeedsFlatten()) { + return; + } - private static void handleXmlPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, - AtomicReference ifBlockReference, String fieldNameVariableName, - ClientModelPropertiesManager propertiesManager, boolean fromSuper, JavaSettings settings) { - // Property will be handled later by flattened deserialization. - // XML should never have flattening. - if (property.getNeedsFlatten()) { - return; + JavaIfBlock ifBlock = ifBlockReference.get(); + ifBlockReference.set(handleXmlPropertyDeserialization(property, methodBlock, ifBlock, fromSuper)); } - JavaIfBlock ifBlock = ifBlockReference.get(); - ifBlock = handleXmlPropertyDeserialization(property, methodBlock, ifBlock, fieldNameVariableName, - propertiesManager, fromSuper, settings); - - ifBlockReference.set(ifBlock); - } + private JavaIfBlock handleXmlPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, + JavaIfBlock ifBlock, boolean fromSuper) { + String xmlElementName = (property.getClientType() instanceof IterableType && !property.isXmlWrapper()) + ? property.getXmlListElementName() + : property.getXmlName(); + String xmlNamespace = propertiesManager.getXmlNamespaceConstant(property.getXmlNamespace()); - private static JavaIfBlock handleXmlPropertyDeserialization(ClientModelProperty property, JavaBlock methodBlock, - JavaIfBlock ifBlock, String fieldNameVariableName, ClientModelPropertiesManager propertiesManager, - boolean fromSuper, JavaSettings settings) { - String xmlElementName = (property.getClientType() instanceof IterableType && !property.isXmlWrapper()) - ? property.getXmlListElementName() : property.getXmlName(); - String xmlNamespace = propertiesManager.getXmlNamespaceConstant(property.getXmlNamespace()); + if (CoreUtils.isNullOrEmpty(xmlElementName)) { + return ifBlock; + } - if (CoreUtils.isNullOrEmpty(xmlElementName)) { - return ifBlock; + String condition = getXmlNameConditional(xmlElementName, xmlNamespace, + propertiesManager.getXmlReaderNameVariableName(), true); + return ifOrElseIf(methodBlock, ifBlock, condition, + deserializationBlock -> generateXmlDeserializationLogic(deserializationBlock, property, fromSuper)); } - String condition = getXmlNameConditional(xmlElementName, xmlNamespace, fieldNameVariableName, true); - return ifOrElseIf(methodBlock, ifBlock, condition, - deserializationBlock -> generateXmlDeserializationLogic(deserializationBlock, property, propertiesManager, - fromSuper, settings)); - } - - private static void generateXmlDeserializationLogic(JavaBlock deserializationBlock, ClientModelProperty property, - ClientModelPropertiesManager propertiesManager, boolean fromSuper, JavaSettings settings) { - IType wireType = property.getWireType(); + private void generateXmlDeserializationLogic(JavaBlock deserializationBlock, ClientModelProperty property, + boolean fromSuper) { + IType wireType = property.getWireType(); - // Attempt to determine whether the wire type is simple deserialization. - // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. - String simpleDeserialization = getSimpleXmlDeserialization(wireType, "reader", property.getXmlName(), null, + // Attempt to determine whether the wire type is simple deserialization. + // This is primitives, boxed primitives, a small set of string based models, and other ClientModels. + String simpleDeserialization = getSimpleXmlDeserialization(wireType, property.getXmlName(), null, null, false); - if (simpleDeserialization != null) { - if (propertiesManager.hasConstructorArguments()) { - deserializationBlock.line(property.getName() + " = " + simpleDeserialization + ";"); - } else { - handleSettingDeserializedValue(deserializationBlock, propertiesManager.getDeserializedModelName(), - propertiesManager.getModel(), property, simpleDeserialization, fromSuper, false); - } - } else if (wireType instanceof IterableType) { - IType elementType = ((IterableType) wireType).getElementType(); - boolean sameNames = Objects.equals(property.getXmlName(), property.getXmlListElementName()); - String elementDeserialization = getSimpleXmlDeserialization(elementType, "reader", - sameNames ? property.getXmlName() : property.getXmlListElementName(), null, null, false); - String fieldAccess; - if (propertiesManager.hasConstructorArguments()) { - // Cases with constructor arguments will have a local variable based on the name of the property. - fieldAccess = property.getName(); - } else if (fromSuper) { - // Cases where the property is from the super type will need to access the getter. - fieldAccess = propertiesManager.getDeserializedModelName() + "." + property.getGetterName() + "()"; - } else { - // Otherwise access the property directly. - fieldAccess = propertiesManager.getDeserializedModelName() + "." + property.getName(); - } + if (simpleDeserialization != null) { + if (propertiesManager.hasConstructorArguments()) { + deserializationBlock.line(property.getName() + " = " + simpleDeserialization + ";"); + } else { + handleSettingDeserializedValue(deserializationBlock, property, simpleDeserialization, fromSuper); + } + } else if (wireType instanceof IterableType) { + IType elementType = ((IterableType) wireType).getElementType(); + boolean sameNames = Objects.equals(property.getXmlName(), property.getXmlListElementName()); + String elementDeserialization = getSimpleXmlDeserialization(elementType, + sameNames ? property.getXmlName() : property.getXmlListElementName(), null, null, false); + String fieldAccess; + if (propertiesManager.hasConstructorArguments()) { + // Cases with constructor arguments will have a local variable based on the name of the property. + fieldAccess = property.getName(); + } else if (fromSuper) { + // Cases where the property is from the super type will need to access the getter. + fieldAccess = propertiesManager.getDeserializedModelName() + "." + property.getGetterName() + "()"; + } else { + // Otherwise access the property directly. + fieldAccess = propertiesManager.getDeserializedModelName() + "." + property.getName(); + } - if (!property.isXmlWrapper()) { - deserializationBlock.line(fieldAccess + ".add(" + elementDeserialization + ");"); - } else { - deserializationBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", whileBlock -> { - whileBlock.line("elementName = reader.getElementName();"); - String condition = getXmlNameConditional(property.getXmlListElementName(), - propertiesManager.getXmlNamespaceConstant(property.getXmlListElementNamespace()), "elementName", - true); - whileBlock.ifBlock(condition, ifBlock -> { + if (!property.isXmlWrapper()) { + deserializationBlock.line(fieldAccess + ".add(" + elementDeserialization + ");"); + } else { + deserializationBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", whileBlock -> { + whileBlock.line("elementName = reader.getElementName();"); + String condition = getXmlNameConditional(property.getXmlListElementName(), + propertiesManager.getXmlNamespaceConstant(property.getXmlListElementNamespace()), + "elementName", true); + whileBlock.ifBlock(condition, ifBlock -> { // TODO (alzimmer): Handle nested container types when needed. ifBlock.ifBlock(fieldAccess + " == null", ifStatement -> { if (fromSuper) { - ifStatement.line(propertiesManager.getDeserializedModelName() + "." + property.getSetterName() - + "(new ArrayList<>());"); + ifStatement.line( + propertiesManager.getDeserializedModelName() + "." + property.getSetterName() + + "(new ArrayList<>());"); } else { ifStatement.line(fieldAccess + " = new ArrayList<>();"); } }); ifBlock.line(fieldAccess + ".add(" + elementDeserialization + ");"); - }) - .elseBlock(elseBlock -> elseBlock.line("reader.skipElement();")); + }).elseBlock(elseBlock -> elseBlock.line("reader.skipElement();")); + }); + } + } else if (wireType instanceof MapType) { + IType valueType = ((MapType) wireType).getValueType(); + String fieldAccess = propertiesManager.hasConstructorArguments() + ? property.getName() + : propertiesManager.getDeserializedModelName() + "." + property.getName(); + + String valueDeserialization = getSimpleXmlDeserialization(valueType, property.getXmlName(), + null, null, false); + deserializationBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", whileBlock -> { + // TODO (alzimmer): Handle nested container types when needed. + // Assumption is that the key type for the Map is a String. This may not always hold true and when that + // becomes reality this will need to be reworked to handle that case. + whileBlock.ifBlock(fieldAccess + " == null", + ifStatement -> ifStatement.line(fieldAccess + " = new LinkedHashMap<>();")); + + whileBlock.line( + fieldAccess + ".put(reader.getElementName().getLocalPart(), " + valueDeserialization + ");"); }); + } else { + // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. + throw new RuntimeException("Unknown wire type " + wireType + ". Need to add support for it."); } - } else if (wireType instanceof MapType) { - IType valueType = ((MapType) wireType).getValueType(); - String fieldAccess = propertiesManager.hasConstructorArguments() - ? property.getName() - : propertiesManager.getDeserializedModelName() + "." + property.getName(); - - String valueDeserialization = getSimpleXmlDeserialization(valueType, "reader", property.getXmlName(), null, - null, false); - deserializationBlock.block("while (reader.nextElement() != XmlToken.END_ELEMENT)", whileBlock -> { - // TODO (alzimmer): Handle nested container types when needed. - // Assumption is that the key type for the Map is a String. This may not always hold true and when that - // becomes reality this will need to be reworked to handle that case. - whileBlock.ifBlock(fieldAccess + " == null", - ifStatement -> ifStatement.line(fieldAccess + " = new LinkedHashMap<>();")); - - whileBlock.line(fieldAccess + ".put(reader.getElementName().getLocalPart(), " + valueDeserialization + ");"); - }); - } else { - // TODO (alzimmer): Resolve this as deserialization logic generation needs to handle all cases. - throw new RuntimeException("Unknown wire type " + wireType + ". Need to add support for it."); - } - // If the property was required, mark it as found. - if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { - deserializationBlock.line(property.getName() + "Found = true;"); + // If the property was required, mark it as found. + if (includePropertyInConstructor(property, settings) && !settings.isDisableRequiredJsonAnnotation()) { + deserializationBlock.line(property.getName() + "Found = true;"); + } } - } - private static void handleUnknownXmlFieldDeserialization(JavaBlock methodBlock, JavaIfBlock ifBlock, - ClientModelProperty additionalProperties, String fieldNameVariableName) { - Consumer unknownFieldConsumer = javaBlock -> { - if (additionalProperties != null) { - javaBlock.ifBlock(additionalProperties.getName() + " == null", - ifAction -> ifAction.line(additionalProperties.getName() + " = new LinkedHashMap<>();")); - javaBlock.line(); - - // Assumption, additional properties is a Map of String-Object - IType valueType = ((MapType) additionalProperties.getWireType()).getValueType(); - if (valueType == ClassType.OBJECT) { - // String fieldName should be a local variable accessible in this spot of code. - javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", reader.readUntyped());"); + private void handleUnknownXmlFieldDeserialization(JavaBlock methodBlock, JavaIfBlock ifBlock) { + ClientModelProperty additionalProperties = getAdditionalPropertiesPropertyInModelOrFromSuper(); + String fieldNameVariableName = propertiesManager.getXmlReaderNameVariableName(); + Consumer unknownFieldConsumer = javaBlock -> { + if (additionalProperties != null) { + javaBlock.ifBlock(additionalProperties.getName() + " == null", + ifAction -> ifAction.line(additionalProperties.getName() + " = new LinkedHashMap<>();")); + javaBlock.line(); + + // Assumption, additional properties is a Map of String-Object + IType valueType = ((MapType) additionalProperties.getWireType()).getValueType(); + if (valueType == ClassType.OBJECT) { + // String fieldName should be a local variable accessible in this spot of code. + javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + + ", reader.readUntyped());"); + } else { + // Another assumption, the additional properties value type is simple. + javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " + + getSimpleXmlDeserialization(valueType, null, null, null, false) + ");"); + } } else { - // Another assumption, the additional properties value type is simple. - javaBlock.line(additionalProperties.getName() + ".put(" + fieldNameVariableName + ", " - + getSimpleXmlDeserialization(valueType, "reader", null, null, null, false) + ");"); + javaBlock.line("reader.skipElement();"); } - } else { - javaBlock.line("reader.skipElement();"); - } - }; - - if (ifBlock == null) { - unknownFieldConsumer.accept(methodBlock); - } else { - ifBlock.elseBlock(unknownFieldConsumer); - } - } - - private static String getSimpleXmlDeserialization(IType wireType, String readerName, String elementName, - String attributeName, String attributeNamespace, boolean namespaceIsConstant) { - if (wireType instanceof ClassType && ((ClassType) wireType).isSwaggerType()) { - return CoreUtils.isNullOrEmpty(elementName) - ? wireType + ".fromXml(" + readerName + ")" - : wireType + ".fromXml(" + readerName + ", \"" + elementName + "\")"; - } else { - return wireType.xmlDeserializationMethod(readerName, attributeName, attributeNamespace, namespaceIsConstant); - } - } + }; - private static List getClientModelPropertiesInJsonTree( - JsonFlattenedPropertiesTree tree) { - if (tree.getProperty() != null) { - // Terminal node only contains a property. - return Collections.singletonList(tree.getProperty()); - } else { - List treeProperties = new ArrayList<>(); - for (JsonFlattenedPropertiesTree childNode : tree.getChildrenNodes().values()) { - treeProperties.addAll(getClientModelPropertiesInJsonTree(childNode)); + if (ifBlock == null) { + unknownFieldConsumer.accept(methodBlock); + } else { + ifBlock.elseBlock(unknownFieldConsumer); } - - return treeProperties; } - } - private static String getXmlNameConditional(String localPart, String namespace, String elementName, - boolean namespaceIsConstant) { - String condition = "\"" + localPart + "\".equals(" + elementName + ".getLocalPart())"; - if (!CoreUtils.isNullOrEmpty(namespace)) { - if (namespaceIsConstant) { - condition += " && " + namespace + ".equals(" + elementName + ".getNamespaceURI())"; + private static List getClientModelPropertiesInJsonTree( + JsonFlattenedPropertiesTree tree) { + if (tree.getProperty() != null) { + // Terminal node only contains a property. + return Collections.singletonList(tree.getProperty()); } else { - condition += " && \"" + namespace + "\".equals(" + elementName + ".getNamespaceURI())"; + List treeProperties = new ArrayList<>(); + for (JsonFlattenedPropertiesTree childNode : tree.getChildrenNodes().values()) { + treeProperties.addAll(getClientModelPropertiesInJsonTree(childNode)); + } + + return treeProperties; } } - - return condition; } } From 9adcea53068b061121effa909be0e4c16efc750a Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:36:08 -0400 Subject: [PATCH 2/3] Put shared JsonSerializable code behind a feature flag --- Generate.ps1 | 6 +- .../DocumentModelBuildOperationDetails.java | 60 +++++++++++++-- .../DocumentModelComposeOperationDetails.java | 60 +++++++++++++-- .../DocumentModelCopyToOperationDetails.java | 60 +++++++++++++-- .../models/OperationDetails.java | 73 +++++++------------ .../models/Cookiecuttershark.java | 41 ++++++++++- .../implementation/models/DotFish.java | 26 ++----- .../implementation/models/DotSalmon.java | 24 +++++- .../implementation/models/Fish.java | 38 +++------- .../implementation/models/GoblinShark.java | 41 ++++++++++- .../implementation/models/MyBaseType.java | 50 +++++-------- .../implementation/models/MyDerivedType.java | 40 +++++++++- .../implementation/models/Salmon.java | 54 ++++++++------ .../implementation/models/Sawshark.java | 40 +++++++++- .../implementation/models/Shark.java | 56 ++++++++------ .../implementation/models/SmartSalmon.java | 37 +++++++++- .../extension/base/plugin/JavaSettings.java | 31 +++++++- .../PolymorphicDiscriminatorHandler.java | 20 ++--- .../autorest/mapper/GraalVmConfigMapper.java | 3 +- .../model/clientmodel/ClientModel.java | 14 ++++ .../autorest/template/ModelTemplate.java | 13 ++-- .../StreamSerializationModelTemplate.java | 25 ++++--- .../implementation/models/AbstractModel.java | 9 +-- .../implementation/models/RealModel.java | 20 ++++- .../cadl/armresourceprovider/models/Dog.java | 3 +- .../armresourceprovider/models/Golden.java | 19 ++++- .../com/cadl/naming/models/BytesData.java | 19 ++++- .../java/com/cadl/naming/models/Data.java | 22 ++---- .../main/java/com/cadl/patch/models/Fish.java | 36 +++------ .../java/com/cadl/patch/models/Salmon.java | 29 +++++++- .../java/com/cadl/patch/models/SawShark.java | 49 ++++++++++++- .../java/com/cadl/patch/models/Shark.java | 48 +++++++----- .../enumdiscriminator/models/Cobra.java | 20 ++++- .../enumdiscriminator/models/Dog.java | 9 +-- .../enumdiscriminator/models/Golden.java | 20 ++++- .../enumdiscriminator/models/Snake.java | 9 +-- .../enumnesteddiscriminator/models/Fish.java | 9 +-- .../models/GoblinShark.java | 38 +++++++++- .../models/Salmon.java | 20 ++++- .../models/SawShark.java | 38 +++++++++- .../enumnesteddiscriminator/models/Shark.java | 29 +++++--- .../nesteddiscriminator/models/Fish.java | 9 +-- .../models/GoblinShark.java | 38 +++++++++- .../nesteddiscriminator/models/Salmon.java | 20 ++++- .../nesteddiscriminator/models/SawShark.java | 38 +++++++++- .../nesteddiscriminator/models/Shark.java | 29 +++++--- .../singlediscriminator/models/Bird.java | 9 +-- .../singlediscriminator/models/Dinosaur.java | 9 +-- .../singlediscriminator/models/Eagle.java | 20 ++++- .../singlediscriminator/models/Goose.java | 20 ++++- .../singlediscriminator/models/SeaGull.java | 20 ++++- .../singlediscriminator/models/Sparrow.java | 20 ++++- .../singlediscriminator/models/TRex.java | 20 ++++- ...nownAdditionalPropertiesDiscriminated.java | 9 +-- ...itionalPropertiesDiscriminatedDerived.java | 20 ++++- ...nownAdditionalPropertiesDiscriminated.java | 9 +-- ...itionalPropertiesDiscriminatedDerived.java | 20 ++++- .../bodycomplex/models/Cookiecuttershark.java | 18 ++++- .../fixtures/bodycomplex/models/DotFish.java | 3 +- .../bodycomplex/models/DotSalmon.java | 18 ++++- .../fixtures/bodycomplex/models/Fish.java | 3 +- .../bodycomplex/models/Goblinshark.java | 18 ++++- .../bodycomplex/models/MyBaseType.java | 3 +- .../bodycomplex/models/MyDerivedType.java | 18 ++++- .../fixtures/bodycomplex/models/Salmon.java | 18 ++++- .../fixtures/bodycomplex/models/Sawshark.java | 18 ++++- .../fixtures/bodycomplex/models/Shark.java | 18 ++++- .../bodycomplex/models/SmartSalmon.java | 18 ++++- .../discriminatorenum/models/Dog.java | 26 ++----- .../discriminatorenum/models/Golden.java | 24 +++++- .../models/MetricAlertCriteria.java | 3 +- ...tSingleResourceMultipleMetricCriteria.java | 18 ++++- .../models/MetricAlertCriteria.java | 3 +- ...tSingleResourceMultipleMetricCriteria.java | 18 ++++- .../noflatten/models/MetricAlertCriteria.java | 3 +- ...tSingleResourceMultipleMetricCriteria.java | 18 ++++- .../models/MetricAlertCriteria.java | 3 +- ...tSingleResourceMultipleMetricCriteria.java | 18 ++++- .../models/MetricAlertCriteria.java | 3 +- ...tSingleResourceMultipleMetricCriteria.java | 18 ++++- 80 files changed, 1396 insertions(+), 480 deletions(-) diff --git a/Generate.ps1 b/Generate.ps1 index 93cd95831f..3fbded9a15 100644 --- a/Generate.ps1 +++ b/Generate.ps1 @@ -88,9 +88,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 --stream-style-serialization=false", - "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserialization --enable-sync-stack --client-logger", - "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationimmutableoutput --enable-sync-stack --output-model-immutable --client-logger", - "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationctorargs --enable-sync-stack --required-fields-as-ctor-args --client-logger", + "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserialization --enable-sync-stack --client-logger --share-jsonserializable-code", + "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationimmutableoutput --enable-sync-stack --output-model-immutable --client-logger --share-jsonserializable-code", + "$VANILLA_ARGUMENTS --input-file=$SWAGGER_PATH/body-complex.json --namespace=fixtures.streamstyleserializationctorargs --enable-sync-stack --required-fields-as-ctor-args --client-logger --share-jsonserializable-code", "$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", diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java index cca8581922..caeced0c46 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java @@ -5,11 +5,13 @@ package com.azure.ai.formrecognizer.documentanalysis.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.core.util.CoreUtils; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.Map; /** @@ -17,6 +19,11 @@ */ @Fluent public final class DocumentModelBuildOperationDetails extends OperationDetails { + /* + * Type of operation. + */ + private String kind = "documentModelBuild"; + /* * Operation result upon success. */ @@ -26,7 +33,15 @@ public final class DocumentModelBuildOperationDetails extends OperationDetails { * Creates an instance of DocumentModelBuildOperationDetails class. */ public DocumentModelBuildOperationDetails() { - this.kind = "documentModelBuild"; + } + + /** + * Get the kind property: Type of operation. + * + * @return the kind value. + */ + public String getKind() { + return this.kind; } /** @@ -136,7 +151,20 @@ public DocumentModelBuildOperationDetails setError(Error error) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("operationId", getOperationId()); + jsonWriter.writeStringField("status", getStatus() == null ? null : getStatus().toString()); + jsonWriter.writeStringField("createdDateTime", + getCreatedDateTime() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getCreatedDateTime())); + jsonWriter.writeStringField("lastUpdatedDateTime", + getLastUpdatedDateTime() == null + ? null + : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getLastUpdatedDateTime())); + jsonWriter.writeStringField("resourceLocation", getResourceLocation()); + jsonWriter.writeNumberField("percentCompleted", getPercentCompleted()); + jsonWriter.writeStringField("apiVersion", getApiVersion()); + jsonWriter.writeMapField("tags", getTags(), (writer, element) -> writer.writeString(element)); + jsonWriter.writeJsonField("error", getError()); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeJsonField("result", this.result); return jsonWriter.writeEndObject(); } @@ -158,9 +186,31 @@ public static DocumentModelBuildOperationDetails fromJson(JsonReader jsonReader) String fieldName = reader.getFieldName(); reader.nextToken(); - if (OperationDetails.fromJsonShared(reader, fieldName, - deserializedDocumentModelBuildOperationDetails)) { - continue; + if ("operationId".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setOperationId(reader.getString()); + } else if ("status".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails + .setStatus(OperationStatus.fromString(reader.getString())); + } else if ("createdDateTime".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setCreatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("lastUpdatedDateTime".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setLastUpdatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("resourceLocation".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setResourceLocation(reader.getString()); + } else if ("percentCompleted".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails + .setPercentCompleted(reader.getNullable(JsonReader::getInt)); + } else if ("apiVersion".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setApiVersion(reader.getString()); + } else if ("tags".equals(fieldName)) { + Map tags = reader.readMap(reader1 -> reader1.getString()); + deserializedDocumentModelBuildOperationDetails.setTags(tags); + } else if ("error".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.setError(Error.fromJson(reader)); + } else if ("kind".equals(fieldName)) { + deserializedDocumentModelBuildOperationDetails.kind = reader.getString(); } else if ("result".equals(fieldName)) { deserializedDocumentModelBuildOperationDetails.result = DocumentModelDetails.fromJson(reader); } else { diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java index aa000c9aa4..047bfb295d 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java @@ -5,11 +5,13 @@ package com.azure.ai.formrecognizer.documentanalysis.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.core.util.CoreUtils; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.Map; /** @@ -17,6 +19,11 @@ */ @Fluent public final class DocumentModelComposeOperationDetails extends OperationDetails { + /* + * Type of operation. + */ + private String kind = "documentModelCompose"; + /* * Operation result upon success. */ @@ -26,7 +33,15 @@ public final class DocumentModelComposeOperationDetails extends OperationDetails * Creates an instance of DocumentModelComposeOperationDetails class. */ public DocumentModelComposeOperationDetails() { - this.kind = "documentModelCompose"; + } + + /** + * Get the kind property: Type of operation. + * + * @return the kind value. + */ + public String getKind() { + return this.kind; } /** @@ -136,7 +151,20 @@ public DocumentModelComposeOperationDetails setError(Error error) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("operationId", getOperationId()); + jsonWriter.writeStringField("status", getStatus() == null ? null : getStatus().toString()); + jsonWriter.writeStringField("createdDateTime", + getCreatedDateTime() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getCreatedDateTime())); + jsonWriter.writeStringField("lastUpdatedDateTime", + getLastUpdatedDateTime() == null + ? null + : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getLastUpdatedDateTime())); + jsonWriter.writeStringField("resourceLocation", getResourceLocation()); + jsonWriter.writeNumberField("percentCompleted", getPercentCompleted()); + jsonWriter.writeStringField("apiVersion", getApiVersion()); + jsonWriter.writeMapField("tags", getTags(), (writer, element) -> writer.writeString(element)); + jsonWriter.writeJsonField("error", getError()); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeJsonField("result", this.result); return jsonWriter.writeEndObject(); } @@ -158,9 +186,31 @@ public static DocumentModelComposeOperationDetails fromJson(JsonReader jsonReade String fieldName = reader.getFieldName(); reader.nextToken(); - if (OperationDetails.fromJsonShared(reader, fieldName, - deserializedDocumentModelComposeOperationDetails)) { - continue; + if ("operationId".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setOperationId(reader.getString()); + } else if ("status".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails + .setStatus(OperationStatus.fromString(reader.getString())); + } else if ("createdDateTime".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setCreatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("lastUpdatedDateTime".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setLastUpdatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("resourceLocation".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setResourceLocation(reader.getString()); + } else if ("percentCompleted".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails + .setPercentCompleted(reader.getNullable(JsonReader::getInt)); + } else if ("apiVersion".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setApiVersion(reader.getString()); + } else if ("tags".equals(fieldName)) { + Map tags = reader.readMap(reader1 -> reader1.getString()); + deserializedDocumentModelComposeOperationDetails.setTags(tags); + } else if ("error".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.setError(Error.fromJson(reader)); + } else if ("kind".equals(fieldName)) { + deserializedDocumentModelComposeOperationDetails.kind = reader.getString(); } else if ("result".equals(fieldName)) { deserializedDocumentModelComposeOperationDetails.result = DocumentModelDetails.fromJson(reader); } else { diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java index d8dee5235e..021668d886 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java @@ -5,11 +5,13 @@ package com.azure.ai.formrecognizer.documentanalysis.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.core.util.CoreUtils; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.Map; /** @@ -17,6 +19,11 @@ */ @Fluent public final class DocumentModelCopyToOperationDetails extends OperationDetails { + /* + * Type of operation. + */ + private String kind = "documentModelCopyTo"; + /* * Operation result upon success. */ @@ -26,7 +33,15 @@ public final class DocumentModelCopyToOperationDetails extends OperationDetails * Creates an instance of DocumentModelCopyToOperationDetails class. */ public DocumentModelCopyToOperationDetails() { - this.kind = "documentModelCopyTo"; + } + + /** + * Get the kind property: Type of operation. + * + * @return the kind value. + */ + public String getKind() { + return this.kind; } /** @@ -136,7 +151,20 @@ public DocumentModelCopyToOperationDetails setError(Error error) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("operationId", getOperationId()); + jsonWriter.writeStringField("status", getStatus() == null ? null : getStatus().toString()); + jsonWriter.writeStringField("createdDateTime", + getCreatedDateTime() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getCreatedDateTime())); + jsonWriter.writeStringField("lastUpdatedDateTime", + getLastUpdatedDateTime() == null + ? null + : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getLastUpdatedDateTime())); + jsonWriter.writeStringField("resourceLocation", getResourceLocation()); + jsonWriter.writeNumberField("percentCompleted", getPercentCompleted()); + jsonWriter.writeStringField("apiVersion", getApiVersion()); + jsonWriter.writeMapField("tags", getTags(), (writer, element) -> writer.writeString(element)); + jsonWriter.writeJsonField("error", getError()); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeJsonField("result", this.result); return jsonWriter.writeEndObject(); } @@ -158,9 +186,31 @@ public static DocumentModelCopyToOperationDetails fromJson(JsonReader jsonReader String fieldName = reader.getFieldName(); reader.nextToken(); - if (OperationDetails.fromJsonShared(reader, fieldName, - deserializedDocumentModelCopyToOperationDetails)) { - continue; + if ("operationId".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setOperationId(reader.getString()); + } else if ("status".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails + .setStatus(OperationStatus.fromString(reader.getString())); + } else if ("createdDateTime".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setCreatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("lastUpdatedDateTime".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setLastUpdatedDateTime(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("resourceLocation".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setResourceLocation(reader.getString()); + } else if ("percentCompleted".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails + .setPercentCompleted(reader.getNullable(JsonReader::getInt)); + } else if ("apiVersion".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setApiVersion(reader.getString()); + } else if ("tags".equals(fieldName)) { + Map tags = reader.readMap(reader1 -> reader1.getString()); + deserializedDocumentModelCopyToOperationDetails.setTags(tags); + } else if ("error".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.setError(Error.fromJson(reader)); + } else if ("kind".equals(fieldName)) { + deserializedDocumentModelCopyToOperationDetails.kind = reader.getString(); } else if ("result".equals(fieldName)) { deserializedDocumentModelCopyToOperationDetails.result = DocumentModelDetails.fromJson(reader); } else { diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/OperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/OperationDetails.java index 02a512bfab..6cd92ccf5d 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/OperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/OperationDetails.java @@ -23,7 +23,7 @@ public class OperationDetails implements JsonSerializable { /* * Type of operation. */ - String kind; + private String kind = "OperationDetails"; /* * Operation ID @@ -74,7 +74,6 @@ public class OperationDetails implements JsonSerializable { * Creates an instance of OperationDetails class. */ public OperationDetails() { - this.kind = "OperationDetails"; } /** @@ -272,11 +271,6 @@ public OperationDetails setError(Error error) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("operationId", this.operationId); jsonWriter.writeStringField("status", this.status == null ? null : this.status.toString()); jsonWriter.writeStringField("createdDateTime", @@ -291,6 +285,7 @@ void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("apiVersion", this.apiVersion); jsonWriter.writeMapField("tags", this.tags, (writer, element) -> writer.writeString(element)); jsonWriter.writeJsonField("error", this.error); + return jsonWriter.writeEndObject(); } /** @@ -338,7 +333,30 @@ static OperationDetails fromJsonKnownDiscriminator(JsonReader jsonReader) throws String fieldName = reader.getFieldName(); reader.nextToken(); - if (!OperationDetails.fromJsonShared(reader, fieldName, deserializedOperationDetails)) { + if ("operationId".equals(fieldName)) { + deserializedOperationDetails.operationId = reader.getString(); + } else if ("status".equals(fieldName)) { + deserializedOperationDetails.status = OperationStatus.fromString(reader.getString()); + } else if ("createdDateTime".equals(fieldName)) { + deserializedOperationDetails.createdDateTime = reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); + } else if ("lastUpdatedDateTime".equals(fieldName)) { + deserializedOperationDetails.lastUpdatedDateTime = reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); + } else if ("resourceLocation".equals(fieldName)) { + deserializedOperationDetails.resourceLocation = reader.getString(); + } else if ("kind".equals(fieldName)) { + deserializedOperationDetails.kind = reader.getString(); + } else if ("percentCompleted".equals(fieldName)) { + deserializedOperationDetails.percentCompleted = reader.getNullable(JsonReader::getInt); + } else if ("apiVersion".equals(fieldName)) { + deserializedOperationDetails.apiVersion = reader.getString(); + } else if ("tags".equals(fieldName)) { + Map tags = reader.readMap(reader1 -> reader1.getString()); + deserializedOperationDetails.tags = tags; + } else if ("error".equals(fieldName)) { + deserializedOperationDetails.error = Error.fromJson(reader); + } else { reader.skipChildren(); } } @@ -346,43 +364,4 @@ static OperationDetails fromJsonKnownDiscriminator(JsonReader jsonReader) throws return deserializedOperationDetails; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, OperationDetails deserializedOperationDetails) - throws IOException { - if ("operationId".equals(fieldName)) { - deserializedOperationDetails.operationId = reader.getString(); - return true; - } else if ("status".equals(fieldName)) { - deserializedOperationDetails.status = OperationStatus.fromString(reader.getString()); - return true; - } else if ("createdDateTime".equals(fieldName)) { - deserializedOperationDetails.createdDateTime - = reader.getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); - return true; - } else if ("lastUpdatedDateTime".equals(fieldName)) { - deserializedOperationDetails.lastUpdatedDateTime - = reader.getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); - return true; - } else if ("resourceLocation".equals(fieldName)) { - deserializedOperationDetails.resourceLocation = reader.getString(); - return true; - } else if ("kind".equals(fieldName)) { - deserializedOperationDetails.kind = reader.getString(); - return true; - } else if ("percentCompleted".equals(fieldName)) { - deserializedOperationDetails.percentCompleted = reader.getNullable(JsonReader::getInt); - return true; - } else if ("apiVersion".equals(fieldName)) { - deserializedOperationDetails.apiVersion = reader.getString(); - return true; - } else if ("tags".equals(fieldName)) { - Map tags = reader.readMap(reader1 -> reader1.getString()); - deserializedOperationDetails.tags = tags; - return true; - } else if ("error".equals(fieldName)) { - deserializedOperationDetails.error = Error.fromJson(reader); - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java index dfe8230699..410db170ce 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java @@ -5,11 +5,13 @@ package fixtures.bodycomplex.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.core.util.CoreUtils; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** @@ -17,11 +19,24 @@ */ @Fluent public final class Cookiecuttershark extends Shark { + /* + * The fishtype property. + */ + private String fishtype = "cookiecuttershark"; + /** * Creates an instance of Cookiecuttershark class. */ public Cookiecuttershark() { - this.fishtype = "cookiecuttershark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -75,7 +90,13 @@ public Cookiecuttershark setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("birthday", + getBirthday() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getBirthday())); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); + jsonWriter.writeNumberField("age", getAge()); + jsonWriter.writeStringField("fishtype", this.fishtype); return jsonWriter.writeEndObject(); } @@ -95,8 +116,20 @@ public static Cookiecuttershark fromJson(JsonReader jsonReader) throws IOExcepti String fieldName = reader.getFieldName(); reader.nextToken(); - if (Shark.fromJsonShared(reader, fieldName, deserializedCookiecuttershark)) { - continue; + if ("length".equals(fieldName)) { + deserializedCookiecuttershark.setLength(reader.getFloat()); + } else if ("birthday".equals(fieldName)) { + deserializedCookiecuttershark.setBirthday(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("species".equals(fieldName)) { + deserializedCookiecuttershark.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedCookiecuttershark.setSiblings(siblings); + } else if ("age".equals(fieldName)) { + deserializedCookiecuttershark.setAge(reader.getNullable(JsonReader::getInt)); + } else if ("fishtype".equals(fieldName)) { + deserializedCookiecuttershark.fishtype = reader.getString(); } else { reader.skipChildren(); } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotFish.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotFish.java index cd460996e6..74987437b1 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotFish.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotFish.java @@ -19,7 +19,7 @@ public class DotFish implements JsonSerializable { /* * The fish.type property. */ - String fishType; + private String fishType = "DotFish"; /* * The species property. @@ -30,7 +30,6 @@ public class DotFish implements JsonSerializable { * Creates an instance of DotFish class. */ public DotFish() { - this.fishType = "DotFish"; } /** @@ -68,13 +67,9 @@ public DotFish setSpecies(String species) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("fish.type", this.fishType); jsonWriter.writeStringField("species", this.species); + return jsonWriter.writeEndObject(); } /** @@ -117,7 +112,11 @@ static DotFish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExcept String fieldName = reader.getFieldName(); reader.nextToken(); - if (!DotFish.fromJsonShared(reader, fieldName, deserializedDotFish)) { + if ("fish.type".equals(fieldName)) { + deserializedDotFish.fishType = reader.getString(); + } else if ("species".equals(fieldName)) { + deserializedDotFish.species = reader.getString(); + } else { reader.skipChildren(); } } @@ -125,15 +124,4 @@ static DotFish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExcept return deserializedDotFish; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, DotFish deserializedDotFish) throws IOException { - if ("fish.type".equals(fieldName)) { - deserializedDotFish.fishType = reader.getString(); - return true; - } else if ("species".equals(fieldName)) { - deserializedDotFish.species = reader.getString(); - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java index 913aca34ff..c02ea98780 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java @@ -17,6 +17,11 @@ */ @Fluent public final class DotSalmon extends DotFish { + /* + * The fish.type property. + */ + private String fishType = "DotSalmon"; + /* * The location property. */ @@ -32,7 +37,15 @@ public final class DotSalmon extends DotFish { * Creates an instance of DotSalmon class. */ public DotSalmon() { - this.fishType = "DotSalmon"; + } + + /** + * Get the fishType property: The fish.type property. + * + * @return the fishType value. + */ + public String getFishType() { + return this.fishType; } /** @@ -89,7 +102,8 @@ public DotSalmon setSpecies(String species) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeStringField("fish.type", this.fishType); jsonWriter.writeStringField("location", this.location); jsonWriter.writeBooleanField("iswild", this.isWild); return jsonWriter.writeEndObject(); @@ -110,8 +124,10 @@ public static DotSalmon fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (DotFish.fromJsonShared(reader, fieldName, deserializedDotSalmon)) { - continue; + if ("species".equals(fieldName)) { + deserializedDotSalmon.setSpecies(reader.getString()); + } else if ("fish.type".equals(fieldName)) { + deserializedDotSalmon.fishType = reader.getString(); } else if ("location".equals(fieldName)) { deserializedDotSalmon.location = reader.getString(); } else if ("iswild".equals(fieldName)) { diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Fish.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Fish.java index dcf03e2ef1..22ac112064 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Fish.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Fish.java @@ -20,7 +20,7 @@ public class Fish implements JsonSerializable { /* * The fishtype property. */ - String fishtype; + private String fishtype = "Fish"; /* * The species property. @@ -41,7 +41,6 @@ public class Fish implements JsonSerializable { * Creates an instance of Fish class. */ public Fish() { - this.fishtype = "Fish"; } /** @@ -119,15 +118,11 @@ public Fish setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeFloatField("length", this.length); jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeStringField("species", this.species); jsonWriter.writeArrayField("siblings", this.siblings, (writer, element) -> writer.writeJson(element)); + return jsonWriter.writeEndObject(); } /** @@ -181,7 +176,16 @@ static Fish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Fish.fromJsonShared(reader, fieldName, deserializedFish)) { + if ("length".equals(fieldName)) { + deserializedFish.length = reader.getFloat(); + } else if ("fishtype".equals(fieldName)) { + deserializedFish.fishtype = reader.getString(); + } else if ("species".equals(fieldName)) { + deserializedFish.species = reader.getString(); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedFish.siblings = siblings; + } else { reader.skipChildren(); } } @@ -189,22 +193,4 @@ static Fish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException return deserializedFish; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, Fish deserializedFish) throws IOException { - if ("length".equals(fieldName)) { - deserializedFish.length = reader.getFloat(); - return true; - } else if ("fishtype".equals(fieldName)) { - deserializedFish.fishtype = reader.getString(); - return true; - } else if ("species".equals(fieldName)) { - deserializedFish.species = reader.getString(); - return true; - } else if ("siblings".equals(fieldName)) { - List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); - deserializedFish.siblings = siblings; - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java index 119bd9749b..80cbd09828 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java @@ -5,11 +5,13 @@ package fixtures.bodycomplex.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.core.util.CoreUtils; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** @@ -17,6 +19,11 @@ */ @Fluent public final class GoblinShark extends Shark { + /* + * The fishtype property. + */ + private String fishtype = "goblin"; + /* * The jawsize property. */ @@ -31,7 +38,15 @@ public final class GoblinShark extends Shark { * Creates an instance of Goblinshark class. */ public GoblinShark() { - this.fishtype = "goblin"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -125,7 +140,13 @@ public GoblinShark setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("birthday", + getBirthday() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getBirthday())); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); + jsonWriter.writeNumberField("age", getAge()); + jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeNumberField("jawsize", this.jawsize); jsonWriter.writeStringField("color", this.color == null ? null : this.color.toString()); return jsonWriter.writeEndObject(); @@ -147,8 +168,20 @@ public static GoblinShark fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Shark.fromJsonShared(reader, fieldName, deserializedGoblinshark)) { - continue; + if ("length".equals(fieldName)) { + deserializedGoblinshark.setLength(reader.getFloat()); + } else if ("birthday".equals(fieldName)) { + deserializedGoblinshark.setBirthday(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("species".equals(fieldName)) { + deserializedGoblinshark.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedGoblinshark.setSiblings(siblings); + } else if ("age".equals(fieldName)) { + deserializedGoblinshark.setAge(reader.getNullable(JsonReader::getInt)); + } else if ("fishtype".equals(fieldName)) { + deserializedGoblinshark.fishtype = reader.getString(); } else if ("jawsize".equals(fieldName)) { deserializedGoblinshark.jawsize = reader.getNullable(JsonReader::getInt); } else if ("color".equals(fieldName)) { diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyBaseType.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyBaseType.java index 2604a5f8d8..3c45135e04 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyBaseType.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyBaseType.java @@ -19,7 +19,7 @@ public class MyBaseType implements JsonSerializable { /* * The kind property. */ - MyKind kind; + private MyKind kind = MyKind.fromString("MyBaseType"); /* * The propB1 property. @@ -35,7 +35,6 @@ public class MyBaseType implements JsonSerializable { * Creates an instance of MyBaseType class. */ public MyBaseType() { - this.kind = MyKind.fromString("MyBaseType"); } /** @@ -93,11 +92,6 @@ public MyBaseType setPropBH1(String propBH1) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); jsonWriter.writeStringField("propB1", this.propB1); if (propBH1 != null) { @@ -105,6 +99,7 @@ void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("propBH1", this.propBH1); jsonWriter.writeEndObject(); } + return jsonWriter.writeEndObject(); } /** @@ -147,7 +142,22 @@ static MyBaseType fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExc String fieldName = reader.getFieldName(); reader.nextToken(); - if (!MyBaseType.fromJsonShared(reader, fieldName, deserializedMyBaseType)) { + if ("kind".equals(fieldName)) { + deserializedMyBaseType.kind = MyKind.fromString(reader.getString()); + } else if ("propB1".equals(fieldName)) { + deserializedMyBaseType.propB1 = reader.getString(); + } else if ("helper".equals(fieldName) && reader.currentToken() == JsonToken.START_OBJECT) { + while (reader.nextToken() != JsonToken.END_OBJECT) { + fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("propBH1".equals(fieldName)) { + deserializedMyBaseType.propBH1 = reader.getString(); + } else { + reader.skipChildren(); + } + } + } else { reader.skipChildren(); } } @@ -155,28 +165,4 @@ static MyBaseType fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExc return deserializedMyBaseType; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, MyBaseType deserializedMyBaseType) - throws IOException { - if ("kind".equals(fieldName)) { - deserializedMyBaseType.kind = MyKind.fromString(reader.getString()); - return true; - } else if ("propB1".equals(fieldName)) { - deserializedMyBaseType.propB1 = reader.getString(); - return true; - } else if ("helper".equals(fieldName) && reader.currentToken() == JsonToken.START_OBJECT) { - while (reader.nextToken() != JsonToken.END_OBJECT) { - fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("propBH1".equals(fieldName)) { - deserializedMyBaseType.propBH1 = reader.getString(); - } else { - reader.skipChildren(); - } - } - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java index d2b0c8c6bc..d1b4007ef4 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java @@ -15,6 +15,11 @@ */ @Fluent public final class MyDerivedType extends MyBaseType { + /* + * The kind property. + */ + private MyKind kind = MyKind.KIND1; + /* * The propD1 property. */ @@ -24,7 +29,15 @@ public final class MyDerivedType extends MyBaseType { * Creates an instance of MyDerivedType class. */ public MyDerivedType() { - this.kind = MyKind.KIND1; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + public MyKind getKind() { + return this.kind; } /** @@ -71,8 +84,14 @@ public MyDerivedType setPropBH1(String propBH1) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("propB1", getPropB1()); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); jsonWriter.writeStringField("propD1", this.propD1); + if (getPropBH1() != null) { + jsonWriter.writeStartObject("helper"); + jsonWriter.writeStringField("propBH1", getPropBH1()); + jsonWriter.writeEndObject(); + } return jsonWriter.writeEndObject(); } @@ -91,10 +110,23 @@ public static MyDerivedType fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (MyBaseType.fromJsonShared(reader, fieldName, deserializedMyDerivedType)) { - continue; + if ("propB1".equals(fieldName)) { + deserializedMyDerivedType.setPropB1(reader.getString()); + } else if ("kind".equals(fieldName)) { + deserializedMyDerivedType.kind = MyKind.fromString(reader.getString()); } else if ("propD1".equals(fieldName)) { deserializedMyDerivedType.propD1 = reader.getString(); + } else if ("helper".equals(fieldName) && reader.currentToken() == JsonToken.START_OBJECT) { + while (reader.nextToken() != JsonToken.END_OBJECT) { + fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("propBH1".equals(fieldName)) { + deserializedMyDerivedType.setPropBH1(reader.getString()); + } else { + reader.skipChildren(); + } + } } else { reader.skipChildren(); } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java index 4998f8f68f..d85e29609d 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java @@ -16,6 +16,11 @@ */ @Fluent public class Salmon extends Fish { + /* + * The fishtype property. + */ + private String fishtype = "salmon"; + /* * The location property. */ @@ -30,7 +35,15 @@ public class Salmon extends Fish { * Creates an instance of Salmon class. */ public Salmon() { - this.fishtype = "salmon"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -106,14 +119,13 @@ public Salmon setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { - super.toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); + jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeStringField("location", this.location); jsonWriter.writeBooleanField("iswild", this.iswild); + return jsonWriter.writeEndObject(); } /** @@ -157,7 +169,20 @@ static Salmon fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExcepti String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Salmon.fromJsonShared(reader, fieldName, deserializedSalmon)) { + if ("length".equals(fieldName)) { + deserializedSalmon.setLength(reader.getFloat()); + } else if ("species".equals(fieldName)) { + deserializedSalmon.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedSalmon.setSiblings(siblings); + } else if ("fishtype".equals(fieldName)) { + deserializedSalmon.fishtype = reader.getString(); + } else if ("location".equals(fieldName)) { + deserializedSalmon.location = reader.getString(); + } else if ("iswild".equals(fieldName)) { + deserializedSalmon.iswild = reader.getNullable(JsonReader::getBoolean); + } else { reader.skipChildren(); } } @@ -165,17 +190,4 @@ static Salmon fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExcepti return deserializedSalmon; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, Salmon deserializedSalmon) throws IOException { - if (Fish.fromJsonShared(reader, fieldName, deserializedSalmon)) { - return true; - } else if ("location".equals(fieldName)) { - deserializedSalmon.location = reader.getString(); - return true; - } else if ("iswild".equals(fieldName)) { - deserializedSalmon.iswild = reader.getNullable(JsonReader::getBoolean); - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java index 8ecd837da9..204e457d83 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java @@ -11,6 +11,7 @@ import com.azure.json.JsonWriter; import java.io.IOException; import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** @@ -18,6 +19,11 @@ */ @Fluent public final class Sawshark extends Shark { + /* + * The fishtype property. + */ + private String fishtype = "sawshark"; + /* * The picture property. */ @@ -27,7 +33,15 @@ public final class Sawshark extends Shark { * Creates an instance of Sawshark class. */ public Sawshark() { - this.fishtype = "sawshark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -101,7 +115,13 @@ public Sawshark setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("birthday", + getBirthday() == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(getBirthday())); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); + jsonWriter.writeNumberField("age", getAge()); + jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeBinaryField("picture", this.picture); return jsonWriter.writeEndObject(); } @@ -122,8 +142,20 @@ public static Sawshark fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Shark.fromJsonShared(reader, fieldName, deserializedSawshark)) { - continue; + if ("length".equals(fieldName)) { + deserializedSawshark.setLength(reader.getFloat()); + } else if ("birthday".equals(fieldName)) { + deserializedSawshark.setBirthday(reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()))); + } else if ("species".equals(fieldName)) { + deserializedSawshark.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedSawshark.setSiblings(siblings); + } else if ("age".equals(fieldName)) { + deserializedSawshark.setAge(reader.getNullable(JsonReader::getInt)); + } else if ("fishtype".equals(fieldName)) { + deserializedSawshark.fishtype = reader.getString(); } else if ("picture".equals(fieldName)) { deserializedSawshark.picture = reader.getBinary(); } else { diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java index 765aaca7f2..1bb2e89be3 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java @@ -19,6 +19,11 @@ */ @Fluent public class Shark extends Fish { + /* + * The fishtype property. + */ + private String fishtype = "shark"; + /* * The age property. */ @@ -33,7 +38,15 @@ public class Shark extends Fish { * Creates an instance of Shark class. */ public Shark() { - this.fishtype = "shark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -109,15 +122,14 @@ public Shark setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { - super.toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); jsonWriter.writeStringField("birthday", this.birthday == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.birthday)); + jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeNumberField("age", this.age); + return jsonWriter.writeEndObject(); } /** @@ -165,7 +177,21 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Shark.fromJsonShared(reader, fieldName, deserializedShark)) { + if ("length".equals(fieldName)) { + deserializedShark.setLength(reader.getFloat()); + } else if ("species".equals(fieldName)) { + deserializedShark.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedShark.setSiblings(siblings); + } else if ("birthday".equals(fieldName)) { + deserializedShark.birthday = reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); + } else if ("fishtype".equals(fieldName)) { + deserializedShark.fishtype = reader.getString(); + } else if ("age".equals(fieldName)) { + deserializedShark.age = reader.getNullable(JsonReader::getInt); + } else { reader.skipChildren(); } } @@ -173,18 +199,4 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio return deserializedShark; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, Shark deserializedShark) throws IOException { - if (Fish.fromJsonShared(reader, fieldName, deserializedShark)) { - return true; - } else if ("birthday".equals(fieldName)) { - deserializedShark.birthday - = reader.getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); - return true; - } else if ("age".equals(fieldName)) { - deserializedShark.age = reader.getNullable(JsonReader::getInt); - return true; - } - return false; - } } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java index 3ebaf684da..cdb224ef40 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java @@ -18,6 +18,11 @@ */ @Fluent public final class SmartSalmon extends Salmon { + /* + * The fishtype property. + */ + private String fishtype = "smart_salmon"; + /* * The college_degree property. */ @@ -32,7 +37,15 @@ public final class SmartSalmon extends Salmon { * Creates an instance of SmartSalmon class. */ public SmartSalmon() { - this.fishtype = "smart_salmon"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** @@ -126,7 +139,12 @@ public SmartSalmon setSiblings(List siblings) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeFloatField("length", getLength()); + jsonWriter.writeStringField("species", getSpecies()); + jsonWriter.writeArrayField("siblings", getSiblings(), (writer, element) -> writer.writeJson(element)); + jsonWriter.writeStringField("location", getLocation()); + jsonWriter.writeBooleanField("iswild", iswild()); + jsonWriter.writeStringField("fishtype", this.fishtype); jsonWriter.writeStringField("college_degree", this.collegeDegree); if (additionalProperties != null) { for (Map.Entry additionalProperty : additionalProperties.entrySet()) { @@ -153,8 +171,19 @@ public static SmartSalmon fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Salmon.fromJsonShared(reader, fieldName, deserializedSmartSalmon)) { - continue; + if ("length".equals(fieldName)) { + deserializedSmartSalmon.setLength(reader.getFloat()); + } else if ("species".equals(fieldName)) { + deserializedSmartSalmon.setSpecies(reader.getString()); + } else if ("siblings".equals(fieldName)) { + List siblings = reader.readArray(reader1 -> Fish.fromJson(reader1)); + deserializedSmartSalmon.setSiblings(siblings); + } else if ("location".equals(fieldName)) { + deserializedSmartSalmon.setLocation(reader.getString()); + } else if ("iswild".equals(fieldName)) { + deserializedSmartSalmon.setIswild(reader.getNullable(JsonReader::getBoolean)); + } else if ("fishtype".equals(fieldName)) { + deserializedSmartSalmon.fishtype = reader.getString(); } else if ("college_degree".equals(fieldName)) { deserializedSmartSalmon.collegeDegree = reader.getString(); } else { diff --git a/extension-base/src/main/java/com/azure/autorest/extension/base/plugin/JavaSettings.java b/extension-base/src/main/java/com/azure/autorest/extension/base/plugin/JavaSettings.java index d4ced37c95..c588e3198f 100644 --- a/extension-base/src/main/java/com/azure/autorest/extension/base/plugin/JavaSettings.java +++ b/extension-base/src/main/java/com/azure/autorest/extension/base/plugin/JavaSettings.java @@ -180,7 +180,8 @@ public static JavaSettings getInstance() { getBooleanValue(host, "null-byte-array-maps-to-empty-array", false), getBooleanValue(host, "graal-vm-config", false), getStringValue(host, "flavor", "Azure"), - getBooleanValue(host, "disable-typed-headers-methods", false) + getBooleanValue(host, "disable-typed-headers-methods", false), + getBooleanValue(host, "share-jsonserializable-code", false) ); } return instance; @@ -284,6 +285,8 @@ private static Map parseStatusCodeMapping(JsonReader jsonReader * @param flavor The brand name we use to generate SDK. * @param disableTypedHeadersMethods Prevents generating REST API methods that include typed headers. If set to * true, {@code noCustomHeaders} will be ignored as no REST APIs with typed headers will be generated. + * @param shareJsonSerializableCode Whether models implementing {@code JsonSerializable} can attempt to share code + * for {@code toJson} and {@code fromJson}. */ private JavaSettings(AutorestSettings autorestSettings, Map modelerSettings, @@ -346,7 +349,8 @@ private JavaSettings(AutorestSettings autorestSettings, boolean nullByteArrayMapsToEmptyArray, boolean generateGraalVmConfig, String flavor, - boolean disableTypedHeadersMethods) { + boolean disableTypedHeadersMethods, + boolean shareJsonSerializableCode) { this.autorestSettings = autorestSettings; this.modelerSettings = new ModelerSettings(modelerSettings); @@ -445,6 +449,7 @@ private JavaSettings(AutorestSettings autorestSettings, this.generateGraalVmConfig = generateGraalVmConfig; this.flavor = flavor; this.disableTypedHeadersMethods = disableTypedHeadersMethods; + this.shareJsonSerializableCode = shareJsonSerializableCode; } /** @@ -1643,6 +1648,28 @@ public boolean isDisableTypedHeadersMethods() { return disableTypedHeadersMethods; } + private final boolean shareJsonSerializableCode; + + /** + * Whether code generation will attempt to share {@code toJson} and {@code fromJson} code generated for + * {@code JsonSerializable} implementing models. + *

+ * When this feature is enabled, the code generated for {@code toJson} and {@code fromJson} will attempt to be + * shared across polymorphic types. This will only happen when all polymorphic models in the polymorphic hierarchy + * are in the same package and meet a few criteria, such as no constructor arguments in the {@code fromJson} case. + * The aim of this feature is to reduce the amount of code generated by {@code JsonSerializable}, which will aid in + * testing all cases and should help the JVM determine more quickly when to JIT certain code. + *

+ * This feature is still experimental, therefore is disabled by default. In the future this feature will become + * enabled default, and then further out this feature will always be enabled without the ability to be configured. + * + * @return Whether code generation will attempt to share {@code toJson} and {@code fromJson} code generated for + * {@code JsonSerializable} implementing models. + */ + public boolean isShareJsonSerializableCode() { + return shareJsonSerializableCode; + } + private static final String DEFAULT_CODE_GENERATION_HEADER = String.join("\n", "Code generated by Microsoft (R) AutoRest Code Generator %s", "Changes may cause incorrect behavior and will be lost if the code is regenerated."); diff --git a/javagen/src/main/java/com/azure/autorest/implementation/PolymorphicDiscriminatorHandler.java b/javagen/src/main/java/com/azure/autorest/implementation/PolymorphicDiscriminatorHandler.java index 23ea81c156..c58baff03b 100644 --- a/javagen/src/main/java/com/azure/autorest/implementation/PolymorphicDiscriminatorHandler.java +++ b/javagen/src/main/java/com/azure/autorest/implementation/PolymorphicDiscriminatorHandler.java @@ -68,8 +68,8 @@ public static void declareField(ClientModel model, JavaClass classBlock, Consume } declareFieldInternal(model.getPolymorphicDiscriminator(), model, - ClientModelUtil.modelDefinesProperty(model, model.getPolymorphicDiscriminator()), classBlock, - addGeneratedAnnotation, addFieldAnnotations, settings); + model.isPolymorphicDiscriminatorDefinedByModel(), classBlock, addGeneratedAnnotation, addFieldAnnotations, + settings); } private static void declareFieldInternal(ClientModelProperty discriminator, ClientModel model, @@ -88,14 +88,14 @@ private static void declareFieldInternal(ClientModelProperty discriminator, Clie // There can be cases with polymorphic discriminators where they have both a default value and are // required, in which case the default value will be set in the constructor. boolean discriminatorFieldIsInitialized = (!discriminatorUsedInConstructor || discriminator.isConstant()) - && (discriminatorValue != null && !allPolymorphicModelsInSamePackage); + && (discriminatorValue != null && (!allPolymorphicModelsInSamePackage || !settings.isShareJsonSerializableCode())); String fieldSignature = discriminatorFieldIsInitialized ? propertyType + " " + propertyName + " = " + discriminatorValue : propertyType + " " + propertyName; boolean generateCommentAndAnnotations = discriminatorUsedInConstructor - || (allPolymorphicModelsInSamePackage && discriminatorDefinedByModel) - || !allPolymorphicModelsInSamePackage; + || (allPolymorphicModelsInSamePackage && discriminatorDefinedByModel && settings.isShareJsonSerializableCode()) + || (!allPolymorphicModelsInSamePackage || !settings.isShareJsonSerializableCode()); if (generateCommentAndAnnotations) { classBlock.blockComment(comment -> comment.line(discriminator.getDescription())); @@ -108,9 +108,9 @@ private static void declareFieldInternal(ClientModelProperty discriminator, Clie } else { // If the model defines the discriminator and all models in the polymorphic hierarchy are in the same // package, make it package-private to allow derived models to access it. - if (allPolymorphicModelsInSamePackage && discriminatorDefinedByModel) { + if (allPolymorphicModelsInSamePackage && discriminatorDefinedByModel && settings.isShareJsonSerializableCode()) { classBlock.memberVariable(JavaVisibility.PackagePrivate, fieldSignature); - } else if (!allPolymorphicModelsInSamePackage) { + } else if (!allPolymorphicModelsInSamePackage || !settings.isShareJsonSerializableCode()) { classBlock.privateMemberVariable(fieldSignature); } } @@ -123,7 +123,7 @@ public static void initializeInConstructor(ClientModel model, JavaBlock construc // Polymorphic models are contained in different packages, so the discriminator value was set in the field // declaration. - if (!model.isAllPolymorphicModelsInSamePackage()) { + if (!model.isAllPolymorphicModelsInSamePackage() || !settings.isShareJsonSerializableCode()) { return; } @@ -152,10 +152,10 @@ private static void initializeInConstructorInternal(ClientModelProperty discrimi * * @return Whether a getter method should be generated for the discriminator property. */ - public static boolean generateGetter(ClientModel model, ClientModelProperty discriminator) { + public static boolean generateGetter(ClientModel model, ClientModelProperty discriminator, JavaSettings settings) { // If all the polymorphic models aren't in the same package the getter for the discriminator value will be // generated for each model as each model defines properties for all discriminators. - if (!model.isAllPolymorphicModelsInSamePackage()) { + if (!model.isAllPolymorphicModelsInSamePackage() || !settings.isShareJsonSerializableCode()) { return true; } diff --git a/javagen/src/main/java/com/azure/autorest/mapper/GraalVmConfigMapper.java b/javagen/src/main/java/com/azure/autorest/mapper/GraalVmConfigMapper.java index 88dac702e4..cff117077a 100644 --- a/javagen/src/main/java/com/azure/autorest/mapper/GraalVmConfigMapper.java +++ b/javagen/src/main/java/com/azure/autorest/mapper/GraalVmConfigMapper.java @@ -8,6 +8,7 @@ import com.azure.autorest.model.clientmodel.ClientModel; import com.azure.autorest.model.clientmodel.EnumType; import com.azure.autorest.model.clientmodel.GraalVmConfig; +import com.azure.autorest.model.clientmodel.ImplementationDetails; import com.azure.autorest.model.clientmodel.ServiceClient; import java.util.Collection; @@ -56,7 +57,7 @@ public GraalVmConfig map(ServiceAndModel data) { .map(e -> e.getPackage() + "." + e.getName()) .collect(Collectors.toList()); reflects.addAll(data.models.stream() - .filter(m -> !streamStyle || (m.getImplementationDetails() != null && m.getImplementationDetails().isException())) + .filter(m -> !streamStyle || m.hasUsage(ImplementationDetails.Usage.EXCEPTION)) .map(m -> m.getPackage() + "." + m.getName()) .collect(Collectors.toList())); reflects.addAll(data.enums.stream() diff --git a/javagen/src/main/java/com/azure/autorest/model/clientmodel/ClientModel.java b/javagen/src/main/java/com/azure/autorest/model/clientmodel/ClientModel.java index 01d37d8f08..6a047d9ddd 100644 --- a/javagen/src/main/java/com/azure/autorest/model/clientmodel/ClientModel.java +++ b/javagen/src/main/java/com/azure/autorest/model/clientmodel/ClientModel.java @@ -418,6 +418,20 @@ public ImplementationDetails getImplementationDetails() { return implementationDetails; } + /** + * Checks whether the model has the given {@link ImplementationDetails.Usage}. + *

+ * If {@link #getImplementationDetails()} or {@link ImplementationDetails#getUsages()} is null this will always + * return false. + * + * @return Whether the model has the given {@link ImplementationDetails.Usage}. + */ + public boolean hasUsage(ImplementationDetails.Usage usage) { + return implementationDetails != null + && implementationDetails.getUsages() != null + && implementationDetails.getUsages().contains(usage); + } + /** * List the properties that have access (getter or setter) methods. *

diff --git a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java index 67de23a745..202937c284 100644 --- a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java @@ -170,7 +170,7 @@ public final void write(ClientModel model, JavaFile javaFile) { : JavaVisibility.Public; if (!property.isPolymorphicDiscriminator() - || PolymorphicDiscriminatorHandler.generateGetter(model, property)) { + || PolymorphicDiscriminatorHandler.generateGetter(model, property, settings)) { generateGetterJavadoc(classBlock, property); addGeneratedAnnotation(classBlock); if (property.isAdditionalProperties() && !settings.isStreamStyleSerialization()) { @@ -323,7 +323,7 @@ public final void write(ClientModel model, JavaFile javaFile) { } if (requireSerialization) { - writeStreamStyleSerialization(classBlock, model, settings); + writeStreamStyleSerialization(classBlock, propertiesManager); } }); } @@ -334,7 +334,9 @@ private static boolean addOverrideAnnotationToGetter(JavaVisibility visibility, return false; } - if (property.isPolymorphicDiscriminator() && model.isAllPolymorphicModelsInSamePackage()) { + if (!settings.isShareJsonSerializableCode() + && property.isPolymorphicDiscriminator() + && model.isAllPolymorphicModelsInSamePackage()) { return false; } @@ -1215,10 +1217,9 @@ private static boolean modelRequireSerialization(ClientModel model) { * the model uses. * * @param classBlock The class block where serialization methods will be written. - * @param model The model. - * @param settings Autorest generation settings. + * @param propertiesManager The properties manager. */ - protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModel model, JavaSettings settings) { + protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModelPropertiesManager propertiesManager) { // No-op, meant for StreamSerializationModelTemplate. } diff --git a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java index ca6585f794..2b889c590a 100644 --- a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java @@ -279,7 +279,8 @@ private static boolean canUseFromJsonShared(ClientModelPropertiesManager propert // package we can generate a package-private 'toJsonShared' method that can handle deserializing properties // defined in the parent class(es). // This will prevent duplicating the deserialization logic for parent properties in each subclass. - return !propertiesManager.hasConstructorArguments() + return propertiesManager.getSettings().isShareJsonSerializableCode() + && !propertiesManager.hasConstructorArguments() && propertiesManager.getModel().isAllPolymorphicModelsInSamePackage(); } @@ -363,14 +364,14 @@ protected boolean isManagementErrorSubclass(ClientModel model) { } @Override - protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModel model, JavaSettings settings) { + protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModelPropertiesManager propertiesManager) { // Early out as strongly-typed headers do their own thing. - if (model.isStronglyTypedHeader()) { + if (propertiesManager.getModel().isStronglyTypedHeader()) { return; } - new StreamSerializationGenerator(model, settings, - this::isManagementErrorSubclass).writeStreamStyleSerialization(classBlock); + new StreamSerializationGenerator(propertiesManager, this::isManagementErrorSubclass) + .writeStreamStyleSerialization(classBlock); } private static final class StreamSerializationGenerator { @@ -383,11 +384,11 @@ private static final class StreamSerializationGenerator { private final boolean isJsonMergePatchModel; private final boolean useFromJsonShared; - private StreamSerializationGenerator(ClientModel model, JavaSettings settings, + private StreamSerializationGenerator(ClientModelPropertiesManager propertiesManager, Predicate isManagementErrorSubclass) { - this.propertiesManager = new ClientModelPropertiesManager(model, settings); - this.model = model; - this.settings = settings; + this.propertiesManager = propertiesManager; + this.model = propertiesManager.getModel(); + this.settings = propertiesManager.getSettings(); this.isManagementErrorSubclass = isManagementErrorSubclass; this.addGeneratedAnnotation = Templates.getModelTemplate()::addGeneratedAnnotation; @@ -460,10 +461,10 @@ private void writeStreamStyleSerialization(JavaClass classBlock) { * @param isJsonMergePatch Whether the serialization is for a JSON merge patch. */ private void writeToJson(JavaClass classBlock, boolean isJsonMergePatch) { - boolean callToJsonSharedForParentProperties = !isJsonMergePatch + boolean callToJsonSharedForParentProperties = settings.isShareJsonSerializableCode() && !isJsonMergePatch && model.isAllPolymorphicModelsInSamePackage() && !CoreUtils.isNullOrEmpty(model.getParentModelName()); - boolean callToJsonSharedForThisProperties = !isJsonMergePatch && model.isAllPolymorphicModelsInSamePackage() - && model.isPolymorphicParent(); + boolean callToJsonSharedForThisProperties = settings.isShareJsonSerializableCode() && !isJsonMergePatch + && model.isAllPolymorphicModelsInSamePackage() && model.isPolymorphicParent(); classBlock.javadocComment(JavaJavadocComment::inheritDoc); addGeneratedAnnotation.accept(classBlock); diff --git a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/AbstractModel.java b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/AbstractModel.java index a1c9c9c752..6128bdba44 100644 --- a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/AbstractModel.java +++ b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/AbstractModel.java @@ -21,7 +21,7 @@ public class AbstractModel implements JsonSerializable { * Discriminator property for AbstractModel. */ @Generated - String kind; + private String kind = "AbstractModel"; /* * The name property. @@ -37,7 +37,6 @@ public class AbstractModel implements JsonSerializable { @Generated protected AbstractModel(String name) { this.name = name; - this.kind = "AbstractModel"; } /** @@ -67,13 +66,9 @@ public String getName() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("name", this.name); jsonWriter.writeStringField("kind", this.kind); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java index 891e6fa2bd..733bba9b33 100644 --- a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java +++ b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java @@ -16,6 +16,12 @@ */ @Immutable public final class RealModel extends AbstractModel { + /* + * Discriminator property for AbstractModel. + */ + @Generated + private String kind = "real"; + /** * Creates an instance of RealModel class. * @@ -24,7 +30,16 @@ public final class RealModel extends AbstractModel { @Generated private RealModel(String name) { super(name); - this.kind = "real"; + } + + /** + * Get the kind property: Discriminator property for AbstractModel. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ private RealModel(String name) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("name", getName()); + jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Dog.java b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Dog.java index 86e782823c..0fc8c725a0 100644 --- a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Dog.java +++ b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Dog.java @@ -24,7 +24,7 @@ public class Dog { */ @JsonTypeId @JsonProperty(value = "kind", required = true) - DogKind kind; + private DogKind kind = DogKind.fromString("Dog"); /* * Weight of the dog @@ -36,7 +36,6 @@ public class Dog { * Creates an instance of Dog class. */ public Dog() { - this.kind = DogKind.fromString("Dog"); } /** diff --git a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java index 077195d193..0f034f6975 100644 --- a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java +++ b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java @@ -5,6 +5,8 @@ package com.cadl.armresourceprovider.models; import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; @@ -15,11 +17,26 @@ @JsonTypeName("golden") @Fluent public final class Golden extends Dog { + /* + * discriminator property + */ + @JsonTypeId + @JsonProperty(value = "kind", required = true) + private DogKind kind = DogKind.GOLDEN; + /** * Creates an instance of Golden class. */ public Golden() { - this.kind = DogKind.GOLDEN; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + public DogKind kind() { + return this.kind; } /** diff --git a/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java b/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java index bbe0c7965c..f4402abfa7 100644 --- a/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java +++ b/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java @@ -17,6 +17,12 @@ */ @Immutable public final class BytesData extends Data { + /* + * The @data.kind property. + */ + @Generated + private String type = "bytes"; + /* * Data as {@code byte[]} */ @@ -31,7 +37,16 @@ public final class BytesData extends Data { @Generated private BytesData(byte[] dataAsBytes) { this.dataAsBytes = dataAsBytes; - this.type = "bytes"; + } + + /** + * Get the type property: The @data.kind property. + * + * @return the type value. + */ + @Generated + public String getType() { + return this.type; } /** @@ -51,8 +66,8 @@ public byte[] getDataAsBytes() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); jsonWriter.writeBinaryField("data_bytes", this.dataAsBytes); + jsonWriter.writeStringField("@data.kind", this.type); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/cadl/naming/models/Data.java b/typespec-tests/src/main/java/com/cadl/naming/models/Data.java index e2b92b1591..34da609016 100644 --- a/typespec-tests/src/main/java/com/cadl/naming/models/Data.java +++ b/typespec-tests/src/main/java/com/cadl/naming/models/Data.java @@ -22,14 +22,13 @@ public class Data implements JsonSerializable { * The @data.kind property. */ @Generated - String type; + private String type = "Data"; /** * Creates an instance of Data class. */ @Generated protected Data() { - this.type = "Data"; } /** @@ -49,12 +48,8 @@ public String getType() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("@data.kind", this.type); + return jsonWriter.writeEndObject(); } /** @@ -99,7 +94,9 @@ static Data fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Data.fromJsonShared(reader, fieldName, deserializedData)) { + if ("@data.kind".equals(fieldName)) { + deserializedData.type = reader.getString(); + } else { reader.skipChildren(); } } @@ -107,13 +104,4 @@ static Data fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException return deserializedData; }); } - - @Generated - static boolean fromJsonShared(JsonReader reader, String fieldName, Data deserializedData) throws IOException { - if ("@data.kind".equals(fieldName)) { - deserializedData.type = reader.getString(); - return true; - } - return false; - } } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/Fish.java b/typespec-tests/src/main/java/com/cadl/patch/models/Fish.java index 86f0597e4e..d555458b52 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/Fish.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/Fish.java @@ -24,7 +24,7 @@ public class Fish implements JsonSerializable { * Discriminator property for Fish. */ @Generated - String kind; + private String kind = "Fish"; /* * The id property. @@ -104,7 +104,6 @@ public void setColor(Fish model, String color) { */ @Generated public Fish() { - this.kind = "Fish"; } /** @@ -263,7 +262,17 @@ static Fish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Fish.fromJsonShared(reader, fieldName, deserializedFish)) { + if ("id".equals(fieldName)) { + deserializedFish.id = reader.getString(); + } else if ("name".equals(fieldName)) { + deserializedFish.name = reader.getString(); + } else if ("kind".equals(fieldName)) { + deserializedFish.kind = reader.getString(); + } else if ("age".equals(fieldName)) { + deserializedFish.age = reader.getInt(); + } else if ("color".equals(fieldName)) { + deserializedFish.color = reader.getString(); + } else { reader.skipChildren(); } } @@ -271,25 +280,4 @@ static Fish fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException return deserializedFish; }); } - - @Generated - static boolean fromJsonShared(JsonReader reader, String fieldName, Fish deserializedFish) throws IOException { - if ("id".equals(fieldName)) { - deserializedFish.id = reader.getString(); - return true; - } else if ("name".equals(fieldName)) { - deserializedFish.name = reader.getString(); - return true; - } else if ("kind".equals(fieldName)) { - deserializedFish.kind = reader.getString(); - return true; - } else if ("age".equals(fieldName)) { - deserializedFish.age = reader.getInt(); - return true; - } else if ("color".equals(fieldName)) { - deserializedFish.color = reader.getString(); - return true; - } - return false; - } } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java b/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java index 339026314b..1c8e7d3169 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java @@ -22,6 +22,12 @@ */ @Fluent public final class Salmon extends Fish { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "salmon"; + /* * The friends property. */ @@ -51,7 +57,16 @@ public final class Salmon extends Fish { */ @Generated public Salmon() { - this.kind = "salmon"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -230,8 +245,16 @@ public static Salmon fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Fish.fromJsonShared(reader, fieldName, deserializedSalmon)) { - continue; + if ("id".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setId(deserializedSalmon, reader.getString()); + } else if ("name".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setName(deserializedSalmon, reader.getString()); + } else if ("age".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setAge(deserializedSalmon, reader.getInt()); + } else if ("color".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setColor(deserializedSalmon, reader.getString()); + } else if ("kind".equals(fieldName)) { + deserializedSalmon.kind = reader.getString(); } else if ("friends".equals(fieldName)) { List friends = reader.readArray(reader1 -> Fish.fromJson(reader1)); deserializedSalmon.friends = friends; diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java b/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java index 9be54bb8b6..0f1f95094b 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java @@ -19,6 +19,18 @@ */ @Fluent public final class SawShark extends Shark { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "shark"; + + /* + * The sharktype property. + */ + @Generated + private String sharktype = "saw"; + /** * Stores updated model property, the value is property name, not serialized name. */ @@ -30,8 +42,26 @@ public final class SawShark extends Shark { */ @Generated public SawShark() { - this.kind = "shark"; - this.sharktype = "saw"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; + } + + /** + * Get the sharktype property: The sharktype property. + * + * @return the sharktype value. + */ + @Generated + public String getSharktype() { + return this.sharktype; } /** @@ -128,8 +158,19 @@ public static SawShark fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Shark.fromJsonShared(reader, fieldName, deserializedSawShark)) { - continue; + if ("id".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setId(deserializedSawShark, reader.getString()); + } else if ("name".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setName(deserializedSawShark, reader.getString()); + } else if ("age".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setAge(deserializedSawShark, reader.getInt()); + } else if ("color".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setColor(deserializedSawShark, reader.getString()); + } else if ("weight".equals(fieldName)) { + JsonMergePatchHelper.getSharkAccessor() + .setWeight(deserializedSawShark, reader.getNullable(JsonReader::getInt)); + } else if ("sharktype".equals(fieldName)) { + deserializedSawShark.sharktype = reader.getString(); } else { reader.skipChildren(); } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java b/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java index 0e383f40ac..44306f0bb9 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java @@ -19,11 +19,17 @@ */ @Fluent public class Shark extends Fish { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "shark"; + /* * The sharktype property. */ @Generated - String sharktype; + private String sharktype = "shark"; /* * The weight property. @@ -51,8 +57,16 @@ public void setWeight(Shark model, Integer weight) { */ @Generated public Shark() { - this.kind = "shark"; - this.sharktype = "shark"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -197,7 +211,19 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Shark.fromJsonShared(reader, fieldName, deserializedShark)) { + if ("id".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setId(deserializedShark, reader.getString()); + } else if ("name".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setName(deserializedShark, reader.getString()); + } else if ("age".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setAge(deserializedShark, reader.getInt()); + } else if ("color".equals(fieldName)) { + JsonMergePatchHelper.getFishAccessor().setColor(deserializedShark, reader.getString()); + } else if ("sharktype".equals(fieldName)) { + deserializedShark.sharktype = reader.getString(); + } else if ("weight".equals(fieldName)) { + deserializedShark.weight = reader.getNullable(JsonReader::getInt); + } else { reader.skipChildren(); } } @@ -205,18 +231,4 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio return deserializedShark; }); } - - @Generated - static boolean fromJsonShared(JsonReader reader, String fieldName, Shark deserializedShark) throws IOException { - if (Fish.fromJsonShared(reader, fieldName, deserializedShark)) { - return true; - } else if ("sharktype".equals(fieldName)) { - deserializedShark.sharktype = reader.getString(); - return true; - } else if ("weight".equals(fieldName)) { - deserializedShark.weight = reader.getNullable(JsonReader::getInt); - return true; - } - return false; - } } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java index e1a2e30962..2ee70748ef 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java @@ -16,6 +16,12 @@ */ @Immutable public final class Cobra extends Snake { + /* + * discriminator property + */ + @Generated + private SnakeKind kind = SnakeKind.COBRA; + /** * Creates an instance of Cobra class. * @@ -24,7 +30,16 @@ public final class Cobra extends Snake { @Generated public Cobra(int length) { super(length); - this.kind = SnakeKind.COBRA; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public SnakeKind getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ public Cobra(int length) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("length", getLength()); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Dog.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Dog.java index ed5732e978..d4f046b81f 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Dog.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Dog.java @@ -21,7 +21,7 @@ public class Dog implements JsonSerializable { * discriminator property */ @Generated - DogKind kind; + private DogKind kind = DogKind.fromString("Dog"); /* * Weight of the dog @@ -37,7 +37,6 @@ public class Dog implements JsonSerializable { @Generated public Dog(int weight) { this.weight = weight; - this.kind = DogKind.fromString("Dog"); } /** @@ -67,13 +66,9 @@ public int getWeight() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("weight", this.weight); jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java index 6e0b671054..37eb805775 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java @@ -16,6 +16,12 @@ */ @Immutable public final class Golden extends Dog { + /* + * discriminator property + */ + @Generated + private DogKind kind = DogKind.GOLDEN; + /** * Creates an instance of Golden class. * @@ -24,7 +30,16 @@ public final class Golden extends Dog { @Generated public Golden(int weight) { super(weight); - this.kind = DogKind.GOLDEN; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public DogKind getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ public Golden(int weight) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("weight", getWeight()); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Snake.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Snake.java index b92d6efba5..cea781f69a 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Snake.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Snake.java @@ -21,7 +21,7 @@ public class Snake implements JsonSerializable { * discriminator property */ @Generated - SnakeKind kind; + private SnakeKind kind = SnakeKind.fromString("Snake"); /* * Length of the snake @@ -37,7 +37,6 @@ public class Snake implements JsonSerializable { @Generated public Snake(int length) { this.length = length; - this.kind = SnakeKind.fromString("Snake"); } /** @@ -67,13 +66,9 @@ public int getLength() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("length", this.length); jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Fish.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Fish.java index 7fe697f6c6..238873d1f7 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Fish.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Fish.java @@ -21,7 +21,7 @@ public class Fish implements JsonSerializable { * discriminator property */ @Generated - FishKind kind; + private FishKind kind = FishKind.fromString("Fish"); /* * The age property. @@ -37,7 +37,6 @@ public class Fish implements JsonSerializable { @Generated public Fish(int age) { this.age = age; - this.kind = FishKind.fromString("Fish"); } /** @@ -67,13 +66,9 @@ public int getAge() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("age", this.age); jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java index 4eacca66e1..a21e1a18ff 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java @@ -16,6 +16,18 @@ */ @Immutable public final class GoblinShark extends Shark { + /* + * discriminator property + */ + @Generated + private FishKind kind = FishKind.SHARK; + + /* + * The sharktype property. + */ + @Generated + private SharkKind sharktype = SharkKind.GOBLIN; + /** * Creates an instance of GoblinShark class. * @@ -24,8 +36,26 @@ public final class GoblinShark extends Shark { @Generated public GoblinShark(int age) { super(age); - this.kind = FishKind.SHARK; - this.sharktype = SharkKind.GOBLIN; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public FishKind getKind() { + return this.kind; + } + + /** + * Get the sharktype property: The sharktype property. + * + * @return the sharktype value. + */ + @Generated + public SharkKind getSharktype() { + return this.sharktype; } /** @@ -35,7 +65,9 @@ public GoblinShark(int age) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("sharktype", this.sharktype == null ? null : this.sharktype.toString()); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java index aacf0fa511..37fa0dbcb9 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java @@ -19,6 +19,12 @@ */ @Fluent public final class Salmon extends Fish { + /* + * discriminator property + */ + @Generated + private FishKind kind = FishKind.SALMON; + /* * The friends property. */ @@ -45,7 +51,16 @@ public final class Salmon extends Fish { @Generated public Salmon(int age) { super(age); - this.kind = FishKind.SALMON; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public FishKind getKind() { + return this.kind; } /** @@ -121,7 +136,8 @@ public Salmon setPartner(Fish partner) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); jsonWriter.writeArrayField("friends", this.friends, (writer, element) -> writer.writeJson(element)); jsonWriter.writeMapField("hate", this.hate, (writer, element) -> writer.writeJson(element)); jsonWriter.writeJsonField("partner", this.partner); diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java index 7986fca5a5..4fb21422a7 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java @@ -16,6 +16,18 @@ */ @Immutable public final class SawShark extends Shark { + /* + * discriminator property + */ + @Generated + private FishKind kind = FishKind.SHARK; + + /* + * The sharktype property. + */ + @Generated + private SharkKind sharktype = SharkKind.SAW; + /** * Creates an instance of SawShark class. * @@ -24,8 +36,26 @@ public final class SawShark extends Shark { @Generated public SawShark(int age) { super(age); - this.kind = FishKind.SHARK; - this.sharktype = SharkKind.SAW; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public FishKind getKind() { + return this.kind; + } + + /** + * Get the sharktype property: The sharktype property. + * + * @return the sharktype value. + */ + @Generated + public SharkKind getSharktype() { + return this.sharktype; } /** @@ -35,7 +65,9 @@ public SawShark(int age) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("sharktype", this.sharktype == null ? null : this.sharktype.toString()); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java index 88f6d8d492..7144805fc3 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java @@ -16,11 +16,17 @@ */ @Immutable public class Shark extends Fish { + /* + * discriminator property + */ + @Generated + private FishKind kind = FishKind.SHARK; + /* * The sharktype property. */ @Generated - SharkKind sharktype; + private SharkKind sharktype = SharkKind.fromString("shark"); /** * Creates an instance of Shark class. @@ -30,8 +36,16 @@ public class Shark extends Fish { @Generated public Shark(int age) { super(age); - this.kind = FishKind.SHARK; - this.sharktype = SharkKind.fromString("shark"); + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + @Generated + public FishKind getKind() { + return this.kind; } /** @@ -51,13 +65,10 @@ public SharkKind getSharktype() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { - super.toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + jsonWriter.writeIntField("age", getAge()); jsonWriter.writeStringField("sharktype", this.sharktype == null ? null : this.sharktype.toString()); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Fish.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Fish.java index a1c40de55f..982c7bbcf0 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Fish.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Fish.java @@ -21,7 +21,7 @@ public class Fish implements JsonSerializable { * Discriminator property for Fish. */ @Generated - String kind; + private String kind = "Fish"; /* * The age property. @@ -37,7 +37,6 @@ public class Fish implements JsonSerializable { @Generated public Fish(int age) { this.age = age; - this.kind = "Fish"; } /** @@ -67,13 +66,9 @@ public int getAge() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("age", this.age); jsonWriter.writeStringField("kind", this.kind); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java index d736745470..e7a9225738 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java @@ -16,6 +16,18 @@ */ @Immutable public final class GoblinShark extends Shark { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "shark"; + + /* + * The sharktype property. + */ + @Generated + private String sharktype = "goblin"; + /** * Creates an instance of GoblinShark class. * @@ -24,8 +36,26 @@ public final class GoblinShark extends Shark { @Generated public GoblinShark(int age) { super(age); - this.kind = "shark"; - this.sharktype = "goblin"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; + } + + /** + * Get the sharktype property: The sharktype property. + * + * @return the sharktype value. + */ + @Generated + public String getSharktype() { + return this.sharktype; } /** @@ -35,7 +65,9 @@ public GoblinShark(int age) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("sharktype", this.sharktype); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java index 0e2eb07bc0..d4ac50818a 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java @@ -19,6 +19,12 @@ */ @Fluent public final class Salmon extends Fish { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "salmon"; + /* * The friends property. */ @@ -45,7 +51,16 @@ public final class Salmon extends Fish { @Generated public Salmon(int age) { super(age); - this.kind = "salmon"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -121,7 +136,8 @@ public Salmon setPartner(Fish partner) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeArrayField("friends", this.friends, (writer, element) -> writer.writeJson(element)); jsonWriter.writeMapField("hate", this.hate, (writer, element) -> writer.writeJson(element)); jsonWriter.writeJsonField("partner", this.partner); diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java index 9078c1e9d0..73e76ed194 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java @@ -16,6 +16,18 @@ */ @Immutable public final class SawShark extends Shark { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "shark"; + + /* + * The sharktype property. + */ + @Generated + private String sharktype = "saw"; + /** * Creates an instance of SawShark class. * @@ -24,8 +36,26 @@ public final class SawShark extends Shark { @Generated public SawShark(int age) { super(age); - this.kind = "shark"; - this.sharktype = "saw"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; + } + + /** + * Get the sharktype property: The sharktype property. + * + * @return the sharktype value. + */ + @Generated + public String getSharktype() { + return this.sharktype; } /** @@ -35,7 +65,9 @@ public SawShark(int age) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind); + jsonWriter.writeIntField("age", getAge()); + jsonWriter.writeStringField("sharktype", this.sharktype); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java index fd2e4f822e..221890824d 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java @@ -16,11 +16,17 @@ */ @Immutable public class Shark extends Fish { + /* + * Discriminator property for Fish. + */ + @Generated + private String kind = "shark"; + /* * The sharktype property. */ @Generated - String sharktype; + private String sharktype = "shark"; /** * Creates an instance of Shark class. @@ -30,8 +36,16 @@ public class Shark extends Fish { @Generated public Shark(int age) { super(age); - this.kind = "shark"; - this.sharktype = "shark"; + } + + /** + * Get the kind property: Discriminator property for Fish. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -51,13 +65,10 @@ public String getSharktype() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { - super.toJsonShared(jsonWriter); + jsonWriter.writeStringField("kind", this.kind); + jsonWriter.writeIntField("age", getAge()); jsonWriter.writeStringField("sharktype", this.sharktype); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Bird.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Bird.java index 29caef9d20..6855214445 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Bird.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Bird.java @@ -21,7 +21,7 @@ public class Bird implements JsonSerializable { * The kind property. */ @Generated - String kind; + private String kind = "Bird"; /* * The wingspan property. @@ -37,7 +37,6 @@ public class Bird implements JsonSerializable { @Generated public Bird(int wingspan) { this.wingspan = wingspan; - this.kind = "Bird"; } /** @@ -67,13 +66,9 @@ public int getWingspan() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("wingspan", this.wingspan); jsonWriter.writeStringField("kind", this.kind); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Dinosaur.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Dinosaur.java index 7067fd9f90..940c920603 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Dinosaur.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Dinosaur.java @@ -21,7 +21,7 @@ public class Dinosaur implements JsonSerializable { * Discriminator property for Dinosaur. */ @Generated - String kind; + private String kind = "Dinosaur"; /* * The size property. @@ -37,7 +37,6 @@ public class Dinosaur implements JsonSerializable { @Generated protected Dinosaur(int size) { this.size = size; - this.kind = "Dinosaur"; } /** @@ -67,13 +66,9 @@ public int getSize() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("size", this.size); jsonWriter.writeStringField("kind", this.kind); + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java index 6b68a67b22..ed1b17ab32 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java @@ -19,6 +19,12 @@ */ @Fluent public final class Eagle extends Bird { + /* + * The kind property. + */ + @Generated + private String kind = "eagle"; + /* * The friends property. */ @@ -45,7 +51,16 @@ public final class Eagle extends Bird { @Generated public Eagle(int wingspan) { super(wingspan); - this.kind = "eagle"; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -121,7 +136,8 @@ public Eagle setPartner(Bird partner) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("wingspan", getWingspan()); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeArrayField("friends", this.friends, (writer, element) -> writer.writeJson(element)); jsonWriter.writeMapField("hate", this.hate, (writer, element) -> writer.writeJson(element)); jsonWriter.writeJsonField("partner", this.partner); diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java index 0ac82567b8..200f98290c 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java @@ -16,6 +16,12 @@ */ @Immutable public final class Goose extends Bird { + /* + * The kind property. + */ + @Generated + private String kind = "goose"; + /** * Creates an instance of Goose class. * @@ -24,7 +30,16 @@ public final class Goose extends Bird { @Generated public Goose(int wingspan) { super(wingspan); - this.kind = "goose"; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ public Goose(int wingspan) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("wingspan", getWingspan()); + jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java index 8f7f1db554..4702f258e8 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java @@ -16,6 +16,12 @@ */ @Immutable public final class SeaGull extends Bird { + /* + * The kind property. + */ + @Generated + private String kind = "seagull"; + /** * Creates an instance of SeaGull class. * @@ -24,7 +30,16 @@ public final class SeaGull extends Bird { @Generated public SeaGull(int wingspan) { super(wingspan); - this.kind = "seagull"; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ public SeaGull(int wingspan) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("wingspan", getWingspan()); + jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java index b9a00e0c16..6e844b0aa2 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java @@ -16,6 +16,12 @@ */ @Immutable public final class Sparrow extends Bird { + /* + * The kind property. + */ + @Generated + private String kind = "sparrow"; + /** * Creates an instance of Sparrow class. * @@ -24,7 +30,16 @@ public final class Sparrow extends Bird { @Generated public Sparrow(int wingspan) { super(wingspan); - this.kind = "sparrow"; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ public Sparrow(int wingspan) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("wingspan", getWingspan()); + jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java index d0ccee9b82..3eeca7c711 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java @@ -16,6 +16,12 @@ */ @Immutable public final class TRex extends Dinosaur { + /* + * Discriminator property for Dinosaur. + */ + @Generated + private String kind = "t-rex"; + /** * Creates an instance of TRex class. * @@ -24,7 +30,16 @@ public final class TRex extends Dinosaur { @Generated private TRex(int size) { super(size); - this.kind = "t-rex"; + } + + /** + * Get the kind property: Discriminator property for Dinosaur. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -34,7 +49,8 @@ private TRex(int size) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("size", getSize()); + jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminated.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminated.java index 59b128de47..c336bbe475 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminated.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminated.java @@ -24,7 +24,7 @@ public class ExtendsUnknownAdditionalPropertiesDiscriminated * The discriminator */ @Generated - String kind; + private String kind = "ExtendsUnknownAdditionalPropertiesDiscriminated"; /* * The name property @@ -46,7 +46,6 @@ public class ExtendsUnknownAdditionalPropertiesDiscriminated @Generated public ExtendsUnknownAdditionalPropertiesDiscriminated(String name) { this.name = name; - this.kind = "ExtendsUnknownAdditionalPropertiesDiscriminated"; } /** @@ -99,11 +98,6 @@ public Map getAdditionalProperties() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("name", this.name); jsonWriter.writeStringField("kind", this.kind); if (additionalProperties != null) { @@ -111,6 +105,7 @@ void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue()); } } + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java index 029927ebd5..edfa97d6b1 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java @@ -19,6 +19,12 @@ @Fluent public final class ExtendsUnknownAdditionalPropertiesDiscriminatedDerived extends ExtendsUnknownAdditionalPropertiesDiscriminated { + /* + * The discriminator + */ + @Generated + private String kind = "derived"; + /* * The index property */ @@ -41,7 +47,16 @@ public final class ExtendsUnknownAdditionalPropertiesDiscriminatedDerived public ExtendsUnknownAdditionalPropertiesDiscriminatedDerived(String name, int index) { super(name); this.index = index; - this.kind = "derived"; + } + + /** + * Get the kind property: The discriminator. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -83,8 +98,9 @@ public ExtendsUnknownAdditionalPropertiesDiscriminatedDerived setAge(Double age) @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("name", getName()); jsonWriter.writeIntField("index", this.index); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeNumberField("age", this.age); if (getAdditionalProperties() != null) { for (Map.Entry additionalProperty : getAdditionalProperties().entrySet()) { diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminated.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminated.java index b0192eb43f..91dcdb0987 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminated.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminated.java @@ -24,7 +24,7 @@ public class IsUnknownAdditionalPropertiesDiscriminated * The discriminator */ @Generated - String kind; + private String kind = "IsUnknownAdditionalPropertiesDiscriminated"; /* * The name property @@ -46,7 +46,6 @@ public class IsUnknownAdditionalPropertiesDiscriminated @Generated public IsUnknownAdditionalPropertiesDiscriminated(String name) { this.name = name; - this.kind = "IsUnknownAdditionalPropertiesDiscriminated"; } /** @@ -99,11 +98,6 @@ public Map getAdditionalProperties() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("name", this.name); jsonWriter.writeStringField("kind", this.kind); if (additionalProperties != null) { @@ -111,6 +105,7 @@ void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeUntypedField(additionalProperty.getKey(), additionalProperty.getValue()); } } + return jsonWriter.writeEndObject(); } /** diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java index 692ee746d5..c40d083f2f 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java @@ -19,6 +19,12 @@ @Fluent public final class IsUnknownAdditionalPropertiesDiscriminatedDerived extends IsUnknownAdditionalPropertiesDiscriminated { + /* + * The discriminator + */ + @Generated + private String kind = "derived"; + /* * The index property */ @@ -41,7 +47,16 @@ public final class IsUnknownAdditionalPropertiesDiscriminatedDerived public IsUnknownAdditionalPropertiesDiscriminatedDerived(String name, int index) { super(name); this.index = index; - this.kind = "derived"; + } + + /** + * Get the kind property: The discriminator. + * + * @return the kind value. + */ + @Generated + public String getKind() { + return this.kind; } /** @@ -83,8 +98,9 @@ public IsUnknownAdditionalPropertiesDiscriminatedDerived setAge(Double age) { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeStringField("name", getName()); jsonWriter.writeIntField("index", this.index); + jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeNumberField("age", this.age); if (getAdditionalProperties() != null) { for (Map.Entry additionalProperty : getAdditionalProperties().entrySet()) { diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java index 1fb252aa14..60b64b5956 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java @@ -7,6 +7,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.time.OffsetDateTime; @@ -19,6 +20,13 @@ @JsonTypeName("cookiecuttershark") @Fluent public final class Cookiecuttershark extends Shark { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "cookiecuttershark"; + /** * Creates an instance of Cookiecuttershark class. * @@ -29,7 +37,15 @@ public final class Cookiecuttershark extends Shark { public Cookiecuttershark(@JsonProperty(value = "length", required = true) float length, @JsonProperty(value = "birthday", required = true) OffsetDateTime birthday) { super(length, birthday); - this.fishtype = "cookiecuttershark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotFish.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotFish.java index ed38e7887d..e6186ef89a 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotFish.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotFish.java @@ -24,7 +24,7 @@ public class DotFish { */ @JsonTypeId @JsonProperty(value = "fish.type", required = true) - String fishType; + private String fishType = "DotFish"; /* * The species property. @@ -36,7 +36,6 @@ public class DotFish { * Creates an instance of DotFish class. */ protected DotFish() { - this.fishType = "DotFish"; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java index f56496dcc4..532031873d 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Immutable; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; @@ -16,6 +17,13 @@ @JsonTypeName("DotSalmon") @Immutable public final class DotSalmon extends DotFish { + /* + * The fish.type property. + */ + @JsonTypeId + @JsonProperty(value = "fish.type", required = true) + private String fishType = "DotSalmon"; + /* * The location property. */ @@ -32,7 +40,15 @@ public final class DotSalmon extends DotFish { * Creates an instance of DotSalmon class. */ private DotSalmon() { - this.fishType = "DotSalmon"; + } + + /** + * Get the fishType property: The fish.type property. + * + * @return the fishType value. + */ + public String getFishType() { + return this.fishType; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Fish.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Fish.java index 01e4f12d09..6360324e91 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Fish.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Fish.java @@ -28,7 +28,7 @@ public class Fish { */ @JsonTypeId @JsonProperty(value = "fishtype", required = true) - String fishtype; + private String fishtype = "Fish"; /* * The species property. @@ -56,7 +56,6 @@ public class Fish { @JsonCreator public Fish(@JsonProperty(value = "length", required = true) float length) { this.length = length; - this.fishtype = "Fish"; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java index a29f785b62..2d0507d965 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java @@ -7,6 +7,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.time.OffsetDateTime; @@ -19,6 +20,13 @@ @JsonTypeName("goblin") @Fluent public final class Goblinshark extends Shark { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "goblin"; + /* * The jawsize property. */ @@ -41,7 +49,15 @@ public final class Goblinshark extends Shark { public Goblinshark(@JsonProperty(value = "length", required = true) float length, @JsonProperty(value = "birthday", required = true) OffsetDateTime birthday) { super(length, birthday); - this.fishtype = "goblin"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyBaseType.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyBaseType.java index 3510ead913..8f6302682b 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyBaseType.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyBaseType.java @@ -26,7 +26,7 @@ public class MyBaseType { */ @JsonTypeId @JsonProperty(value = "kind", required = true) - MyKind kind; + private MyKind kind = MyKind.fromString("MyBaseType"); /* * The propB1 property. @@ -44,7 +44,6 @@ public class MyBaseType { * Creates an instance of MyBaseType class. */ protected MyBaseType() { - this.kind = MyKind.fromString("MyBaseType"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java index 4f2f09ad79..c7bf56b7c5 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Immutable; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; @@ -16,6 +17,13 @@ @JsonTypeName("Kind1") @Immutable public final class MyDerivedType extends MyBaseType { + /* + * The kind property. + */ + @JsonTypeId + @JsonProperty(value = "kind", required = true) + private MyKind kind = MyKind.KIND1; + /* * The propD1 property. */ @@ -26,7 +34,15 @@ public final class MyDerivedType extends MyBaseType { * Creates an instance of MyDerivedType class. */ private MyDerivedType() { - this.kind = MyKind.KIND1; + } + + /** + * Get the kind property: The kind property. + * + * @return the kind value. + */ + public MyKind getKind() { + return this.kind; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java index a7e095c915..1b0f1502c2 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -20,6 +21,13 @@ @JsonSubTypes({ @JsonSubTypes.Type(name = "smart_salmon", value = SmartSalmon.class) }) @Fluent public class Salmon extends Fish { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "salmon"; + /* * The location property. */ @@ -40,7 +48,15 @@ public class Salmon extends Fish { @JsonCreator public Salmon(@JsonProperty(value = "length", required = true) float length) { super(length); - this.fishtype = "salmon"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java index 61b41a4e68..e93661297b 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java @@ -8,6 +8,7 @@ import com.azure.core.util.CoreUtils; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.time.OffsetDateTime; @@ -20,6 +21,13 @@ @JsonTypeName("sawshark") @Fluent public final class Sawshark extends Shark { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "sawshark"; + /* * The picture property. */ @@ -36,7 +44,15 @@ public final class Sawshark extends Shark { public Sawshark(@JsonProperty(value = "length", required = true) float length, @JsonProperty(value = "birthday", required = true) OffsetDateTime birthday) { super(length, birthday); - this.fishtype = "sawshark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java index 76e11161b1..f7b9b54f62 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.time.OffsetDateTime; @@ -25,6 +26,13 @@ @JsonSubTypes.Type(name = "cookiecuttershark", value = Cookiecuttershark.class) }) @Fluent public class Shark extends Fish { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "shark"; + /* * The age property. */ @@ -48,7 +56,15 @@ public Shark(@JsonProperty(value = "length", required = true) float length, @JsonProperty(value = "birthday", required = true) OffsetDateTime birthday) { super(length); this.birthday = birthday; - this.fishtype = "shark"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java index 95065781fe..276c5baf60 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.LinkedHashMap; @@ -23,6 +24,13 @@ @JsonTypeName("smart_salmon") @Fluent public final class SmartSalmon extends Salmon { + /* + * The fishtype property. + */ + @JsonTypeId + @JsonProperty(value = "fishtype", required = true) + private String fishtype = "smart_salmon"; + /* * The college_degree property. */ @@ -43,7 +51,15 @@ public final class SmartSalmon extends Salmon { @JsonCreator public SmartSalmon(@JsonProperty(value = "length", required = true) float length) { super(length); - this.fishtype = "smart_salmon"; + } + + /** + * Get the fishtype property: The fishtype property. + * + * @return the fishtype value. + */ + public String getFishtype() { + return this.fishtype; } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Dog.java b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Dog.java index 7ebe914a34..0374dbc373 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Dog.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Dog.java @@ -19,7 +19,7 @@ public class Dog implements JsonSerializable { /* * discriminator property */ - DogKind kind; + private DogKind kind = DogKind.fromString("Dog"); /* * Weight of the dog @@ -30,7 +30,6 @@ public class Dog implements JsonSerializable { * Creates an instance of Dog class. */ public Dog() { - this.kind = DogKind.fromString("Dog"); } /** @@ -76,13 +75,9 @@ public void validate() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); - return jsonWriter.writeEndObject(); - } - - void toJsonShared(JsonWriter jsonWriter) throws IOException { jsonWriter.writeIntField("weight", this.weight); jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); } /** @@ -126,7 +121,11 @@ static Dog fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException String fieldName = reader.getFieldName(); reader.nextToken(); - if (!Dog.fromJsonShared(reader, fieldName, deserializedDog)) { + if ("weight".equals(fieldName)) { + deserializedDog.weight = reader.getInt(); + } else if ("kind".equals(fieldName)) { + deserializedDog.kind = DogKind.fromString(reader.getString()); + } else { reader.skipChildren(); } } @@ -134,15 +133,4 @@ static Dog fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException return deserializedDog; }); } - - static boolean fromJsonShared(JsonReader reader, String fieldName, Dog deserializedDog) throws IOException { - if ("weight".equals(fieldName)) { - deserializedDog.weight = reader.getInt(); - return true; - } else if ("kind".equals(fieldName)) { - deserializedDog.kind = DogKind.fromString(reader.getString()); - return true; - } - return false; - } } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java index 8a2e745b9f..c622e2246a 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java @@ -15,11 +15,24 @@ */ @Fluent public final class Golden extends Dog { + /* + * discriminator property + */ + private DogKind kind = DogKind.GOLDEN; + /** * Creates an instance of Golden class. */ public Golden() { - this.kind = DogKind.GOLDEN; + } + + /** + * Get the kind property: discriminator property. + * + * @return the kind value. + */ + public DogKind getKind() { + return this.kind; } /** @@ -46,7 +59,8 @@ public void validate() { @Override public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); - toJsonShared(jsonWriter); + jsonWriter.writeIntField("weight", getWeight()); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); return jsonWriter.writeEndObject(); } @@ -66,8 +80,10 @@ public static Golden fromJson(JsonReader jsonReader) throws IOException { String fieldName = reader.getFieldName(); reader.nextToken(); - if (Dog.fromJsonShared(reader, fieldName, deserializedGolden)) { - continue; + if ("weight".equals(fieldName)) { + deserializedGolden.setWeight(reader.getInt()); + } else if ("kind".equals(fieldName)) { + deserializedGolden.kind = DogKind.fromString(reader.getString()); } else { reader.skipChildren(); } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertCriteria.java index 9771aaccf8..1391b842a4 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertCriteria.java @@ -36,7 +36,7 @@ public class MetricAlertCriteria { */ @JsonTypeId @JsonProperty(value = "odata.type", required = true) - Odatatype odataType; + private Odatatype odataType = Odatatype.fromString("MetricAlertCriteria"); /* * The rule criteria that defines the conditions of the alert rule. @@ -48,7 +48,6 @@ public class MetricAlertCriteria { * Creates an instance of MetricAlertCriteria class. */ public MetricAlertCriteria() { - this.odataType = Odatatype.fromString("MetricAlertCriteria"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java index a97dac717e..d248d550e1 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -21,6 +22,13 @@ @JsonTypeName("Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria") @Fluent public final class MetricAlertSingleResourceMultipleMetricCriteria extends MetricAlertCriteria { + /* + * specifies the type of the alert criteria. + */ + @JsonTypeId + @JsonProperty(value = "odata.type", required = true) + private Odatatype odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + /* * The list of metric criteria for this 'all of' operation. */ @@ -31,7 +39,15 @@ public final class MetricAlertSingleResourceMultipleMetricCriteria extends Metri * Creates an instance of MetricAlertSingleResourceMultipleMetricCriteria class. */ public MetricAlertSingleResourceMultipleMetricCriteria() { - this.odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + } + + /** + * Get the odataType property: specifies the type of the alert criteria. + * + * @return the odataType value. + */ + public Odatatype getOdataType() { + return this.odataType; } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertCriteria.java index 9ed2e1d50f..1199ca38f7 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertCriteria.java @@ -36,7 +36,7 @@ public class MetricAlertCriteria { */ @JsonTypeId @JsonProperty(value = "odata.type", required = true) - Odatatype odataType; + private Odatatype odataType = Odatatype.fromString("MetricAlertCriteria"); /* * The rule criteria that defines the conditions of the alert rule. @@ -48,7 +48,6 @@ public class MetricAlertCriteria { * Creates an instance of MetricAlertCriteria class. */ public MetricAlertCriteria() { - this.odataType = Odatatype.fromString("MetricAlertCriteria"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java index ddb6039843..cea792d388 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -21,6 +22,13 @@ @JsonTypeName("Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria") @Fluent public final class MetricAlertSingleResourceMultipleMetricCriteria extends MetricAlertCriteria { + /* + * specifies the type of the alert criteria. + */ + @JsonTypeId + @JsonProperty(value = "odata.type", required = true) + private Odatatype odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + /* * The list of metric criteria for this 'all of' operation. */ @@ -31,7 +39,15 @@ public final class MetricAlertSingleResourceMultipleMetricCriteria extends Metri * Creates an instance of MetricAlertSingleResourceMultipleMetricCriteria class. */ public MetricAlertSingleResourceMultipleMetricCriteria() { - this.odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + } + + /** + * Get the odataType property: specifies the type of the alert criteria. + * + * @return the odataType value. + */ + public Odatatype getOdataType() { + return this.odataType; } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertCriteria.java index 5099313a8b..6f8d209353 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertCriteria.java @@ -36,7 +36,7 @@ public class MetricAlertCriteria { */ @JsonTypeId @JsonProperty(value = "odata.type", required = true) - Odatatype odataType; + private Odatatype odataType = Odatatype.fromString("MetricAlertCriteria"); /* * The rule criteria that defines the conditions of the alert rule. @@ -48,7 +48,6 @@ public class MetricAlertCriteria { * Creates an instance of MetricAlertCriteria class. */ public MetricAlertCriteria() { - this.odataType = Odatatype.fromString("MetricAlertCriteria"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java index 28f2dff6aa..049be98e48 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -21,6 +22,13 @@ @JsonTypeName("Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria") @Fluent public final class MetricAlertSingleResourceMultipleMetricCriteria extends MetricAlertCriteria { + /* + * specifies the type of the alert criteria. + */ + @JsonTypeId + @JsonProperty(value = "odata.type", required = true) + private Odatatype odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + /* * The list of metric criteria for this 'all of' operation. */ @@ -31,7 +39,15 @@ public final class MetricAlertSingleResourceMultipleMetricCriteria extends Metri * Creates an instance of MetricAlertSingleResourceMultipleMetricCriteria class. */ public MetricAlertSingleResourceMultipleMetricCriteria() { - this.odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + } + + /** + * Get the odataType property: specifies the type of the alert criteria. + * + * @return the odataType value. + */ + public Odatatype getOdataType() { + return this.odataType; } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertCriteria.java index 26ae67572b..2f805623d6 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertCriteria.java @@ -36,7 +36,7 @@ public class MetricAlertCriteria { */ @JsonTypeId @JsonProperty(value = "odata.type", required = true) - Odatatype odataType; + private Odatatype odataType = Odatatype.fromString("MetricAlertCriteria"); /* * The rule criteria that defines the conditions of the alert rule. @@ -48,7 +48,6 @@ public class MetricAlertCriteria { * Creates an instance of MetricAlertCriteria class. */ public MetricAlertCriteria() { - this.odataType = Odatatype.fromString("MetricAlertCriteria"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java index e22f32d9b1..6cf2970fdb 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -21,6 +22,13 @@ @JsonTypeName("Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria") @Fluent public final class MetricAlertSingleResourceMultipleMetricCriteria extends MetricAlertCriteria { + /* + * specifies the type of the alert criteria. + */ + @JsonTypeId + @JsonProperty(value = "odata.type", required = true) + private Odatatype odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + /* * The list of metric criteria for this 'all of' operation. */ @@ -31,7 +39,15 @@ public final class MetricAlertSingleResourceMultipleMetricCriteria extends Metri * Creates an instance of MetricAlertSingleResourceMultipleMetricCriteria class. */ public MetricAlertSingleResourceMultipleMetricCriteria() { - this.odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + } + + /** + * Get the odataType property: specifies the type of the alert criteria. + * + * @return the odataType value. + */ + public Odatatype getOdataType() { + return this.odataType; } /** diff --git a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertCriteria.java b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertCriteria.java index 48c0e1459f..7fbf8db03a 100644 --- a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertCriteria.java @@ -36,7 +36,7 @@ public class MetricAlertCriteria { */ @JsonTypeId @JsonProperty(value = "odata.type", required = true) - Odatatype odataType; + private Odatatype odataType = Odatatype.fromString("MetricAlertCriteria"); /* * The rule criteria that defines the conditions of the alert rule. @@ -48,7 +48,6 @@ public class MetricAlertCriteria { * Creates an instance of MetricAlertCriteria class. */ public MetricAlertCriteria() { - this.odataType = Odatatype.fromString("MetricAlertCriteria"); } /** diff --git a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java index c30ef1dc98..f444d1b7ac 100644 --- a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -6,6 +6,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeId; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.List; @@ -21,6 +22,13 @@ @JsonTypeName("Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria") @Fluent public final class MetricAlertSingleResourceMultipleMetricCriteria extends MetricAlertCriteria { + /* + * specifies the type of the alert criteria. + */ + @JsonTypeId + @JsonProperty(value = "odata.type", required = true) + private Odatatype odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + /* * The list of metric criteria for this 'all of' operation. */ @@ -31,7 +39,15 @@ public final class MetricAlertSingleResourceMultipleMetricCriteria extends Metri * Creates an instance of MetricAlertSingleResourceMultipleMetricCriteria class. */ public MetricAlertSingleResourceMultipleMetricCriteria() { - this.odataType = Odatatype.MICROSOFT_AZURE_MONITOR_SINGLE_RESOURCE_MULTIPLE_METRIC_CRITERIA; + } + + /** + * Get the odataType property: specifies the type of the alert criteria. + * + * @return the odataType value. + */ + public Odatatype getOdataType() { + return this.odataType; } /** From 784742798fc5bf84a2187099fddc157bae5b7d52 Mon Sep 17 00:00:00 2001 From: alzimmermsft <48699787+alzimmermsft@users.noreply.github.com> Date: Fri, 23 Aug 2024 09:33:44 -0400 Subject: [PATCH 3/3] Fix override missing --- .../models/DocumentModelBuildOperationDetails.java | 1 + .../models/DocumentModelComposeOperationDetails.java | 1 + .../models/DocumentModelCopyToOperationDetails.java | 1 + .../bodycomplex/implementation/models/Cookiecuttershark.java | 1 + .../fixtures/bodycomplex/implementation/models/DotSalmon.java | 1 + .../fixtures/bodycomplex/implementation/models/GoblinShark.java | 1 + .../bodycomplex/implementation/models/MyDerivedType.java | 1 + .../java/fixtures/bodycomplex/implementation/models/Salmon.java | 1 + .../fixtures/bodycomplex/implementation/models/Sawshark.java | 1 + .../java/fixtures/bodycomplex/implementation/models/Shark.java | 1 + .../fixtures/bodycomplex/implementation/models/SmartSalmon.java | 1 + .../main/java/com/azure/autorest/template/ModelTemplate.java | 2 +- .../core/access/implementation/models/RealModel.java | 1 + .../main/java/com/cadl/armresourceprovider/models/Golden.java | 1 + .../src/main/java/com/cadl/naming/models/BytesData.java | 1 + typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java | 1 + .../src/main/java/com/cadl/patch/models/SawShark.java | 2 ++ typespec-tests/src/main/java/com/cadl/patch/models/Shark.java | 1 + .../type/model/inheritance/enumdiscriminator/models/Cobra.java | 1 + .../type/model/inheritance/enumdiscriminator/models/Golden.java | 1 + .../inheritance/enumnesteddiscriminator/models/GoblinShark.java | 2 ++ .../inheritance/enumnesteddiscriminator/models/Salmon.java | 1 + .../inheritance/enumnesteddiscriminator/models/SawShark.java | 2 ++ .../model/inheritance/enumnesteddiscriminator/models/Shark.java | 1 + .../inheritance/nesteddiscriminator/models/GoblinShark.java | 2 ++ .../model/inheritance/nesteddiscriminator/models/Salmon.java | 1 + .../model/inheritance/nesteddiscriminator/models/SawShark.java | 2 ++ .../model/inheritance/nesteddiscriminator/models/Shark.java | 1 + .../model/inheritance/singlediscriminator/models/Eagle.java | 1 + .../model/inheritance/singlediscriminator/models/Goose.java | 1 + .../model/inheritance/singlediscriminator/models/SeaGull.java | 1 + .../model/inheritance/singlediscriminator/models/Sparrow.java | 1 + .../type/model/inheritance/singlediscriminator/models/TRex.java | 1 + .../ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java | 1 + .../IsUnknownAdditionalPropertiesDiscriminatedDerived.java | 1 + .../java/fixtures/bodycomplex/models/Cookiecuttershark.java | 1 + .../src/main/java/fixtures/bodycomplex/models/DotSalmon.java | 1 + .../src/main/java/fixtures/bodycomplex/models/Goblinshark.java | 1 + .../main/java/fixtures/bodycomplex/models/MyDerivedType.java | 1 + .../src/main/java/fixtures/bodycomplex/models/Salmon.java | 1 + .../src/main/java/fixtures/bodycomplex/models/Sawshark.java | 1 + .../src/main/java/fixtures/bodycomplex/models/Shark.java | 1 + .../src/main/java/fixtures/bodycomplex/models/SmartSalmon.java | 1 + .../src/main/java/fixtures/discriminatorenum/models/Golden.java | 1 + .../models/MetricAlertSingleResourceMultipleMetricCriteria.java | 1 + .../models/MetricAlertSingleResourceMultipleMetricCriteria.java | 1 + .../models/MetricAlertSingleResourceMultipleMetricCriteria.java | 1 + .../models/MetricAlertSingleResourceMultipleMetricCriteria.java | 1 + .../models/MetricAlertSingleResourceMultipleMetricCriteria.java | 1 + 49 files changed, 54 insertions(+), 1 deletion(-) diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java index caeced0c46..112638e6b1 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelBuildOperationDetails.java @@ -40,6 +40,7 @@ public DocumentModelBuildOperationDetails() { * * @return the kind value. */ + @Override public String getKind() { return this.kind; } diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java index 047bfb295d..53e76abb03 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelComposeOperationDetails.java @@ -40,6 +40,7 @@ public DocumentModelComposeOperationDetails() { * * @return the kind value. */ + @Override public String getKind() { return this.kind; } diff --git a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java index 021668d886..c942545629 100644 --- a/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java +++ b/azure-dataplane-tests/src/main/java/com/azure/ai/formrecognizer/documentanalysis/implementation/models/DocumentModelCopyToOperationDetails.java @@ -40,6 +40,7 @@ public DocumentModelCopyToOperationDetails() { * * @return the kind value. */ + @Override public String getKind() { return this.kind; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java index 410db170ce..d9229e8d33 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Cookiecuttershark.java @@ -35,6 +35,7 @@ public Cookiecuttershark() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java index c02ea98780..2da12ebf4d 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/DotSalmon.java @@ -44,6 +44,7 @@ public DotSalmon() { * * @return the fishType value. */ + @Override public String getFishType() { return this.fishType; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java index 80cbd09828..94893a4b08 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/GoblinShark.java @@ -45,6 +45,7 @@ public GoblinShark() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java index d1b4007ef4..672da0abca 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/MyDerivedType.java @@ -36,6 +36,7 @@ public MyDerivedType() { * * @return the kind value. */ + @Override public MyKind getKind() { return this.kind; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java index d85e29609d..868607d85d 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Salmon.java @@ -42,6 +42,7 @@ public Salmon() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java index 204e457d83..336dc6812c 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Sawshark.java @@ -40,6 +40,7 @@ public Sawshark() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java index 1bb2e89be3..ba4eb86e7c 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/Shark.java @@ -45,6 +45,7 @@ public Shark() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java index cdb224ef40..c55551b36c 100644 --- a/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java +++ b/customization-tests/src/main/java/fixtures/bodycomplex/implementation/models/SmartSalmon.java @@ -44,6 +44,7 @@ public SmartSalmon() { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java index 202937c284..12f7f6a964 100644 --- a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java @@ -334,7 +334,7 @@ private static boolean addOverrideAnnotationToGetter(JavaVisibility visibility, return false; } - if (!settings.isShareJsonSerializableCode() + if (settings.isShareJsonSerializableCode() && property.isPolymorphicDiscriminator() && model.isAllPolymorphicModelsInSamePackage()) { return false; diff --git a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java index 733bba9b33..93611ab134 100644 --- a/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java +++ b/typespec-tests/src/main/java/com/_specs_/azure/clientgenerator/core/access/implementation/models/RealModel.java @@ -38,6 +38,7 @@ private RealModel(String name) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java index 0f034f6975..79f6822549 100644 --- a/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java +++ b/typespec-tests/src/main/java/com/cadl/armresourceprovider/models/Golden.java @@ -35,6 +35,7 @@ public Golden() { * * @return the kind value. */ + @Override public DogKind kind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java b/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java index f4402abfa7..c67dcc97b4 100644 --- a/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java +++ b/typespec-tests/src/main/java/com/cadl/naming/models/BytesData.java @@ -45,6 +45,7 @@ private BytesData(byte[] dataAsBytes) { * @return the type value. */ @Generated + @Override public String getType() { return this.type; } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java b/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java index 1c8e7d3169..475b15ac32 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/Salmon.java @@ -65,6 +65,7 @@ public Salmon() { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java b/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java index 0f1f95094b..f08773eb1b 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/SawShark.java @@ -50,6 +50,7 @@ public SawShark() { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } @@ -60,6 +61,7 @@ public String getKind() { * @return the sharktype value. */ @Generated + @Override public String getSharktype() { return this.sharktype; } diff --git a/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java b/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java index 44306f0bb9..0e22b21bdb 100644 --- a/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java +++ b/typespec-tests/src/main/java/com/cadl/patch/models/Shark.java @@ -65,6 +65,7 @@ public Shark() { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java index 2ee70748ef..cf7169baac 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Cobra.java @@ -38,6 +38,7 @@ public Cobra(int length) { * @return the kind value. */ @Generated + @Override public SnakeKind getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java index 37eb805775..fef197d7eb 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumdiscriminator/models/Golden.java @@ -38,6 +38,7 @@ public Golden(int weight) { * @return the kind value. */ @Generated + @Override public DogKind getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java index a21e1a18ff..4670c898d8 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/GoblinShark.java @@ -44,6 +44,7 @@ public GoblinShark(int age) { * @return the kind value. */ @Generated + @Override public FishKind getKind() { return this.kind; } @@ -54,6 +55,7 @@ public FishKind getKind() { * @return the sharktype value. */ @Generated + @Override public SharkKind getSharktype() { return this.sharktype; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java index 37fa0dbcb9..add46a8de1 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Salmon.java @@ -59,6 +59,7 @@ public Salmon(int age) { * @return the kind value. */ @Generated + @Override public FishKind getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java index 4fb21422a7..3dfdf3c573 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/SawShark.java @@ -44,6 +44,7 @@ public SawShark(int age) { * @return the kind value. */ @Generated + @Override public FishKind getKind() { return this.kind; } @@ -54,6 +55,7 @@ public FishKind getKind() { * @return the sharktype value. */ @Generated + @Override public SharkKind getSharktype() { return this.sharktype; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java index 7144805fc3..49f2a677ad 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/enumnesteddiscriminator/models/Shark.java @@ -44,6 +44,7 @@ public Shark(int age) { * @return the kind value. */ @Generated + @Override public FishKind getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java index e7a9225738..c2fc08553f 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/GoblinShark.java @@ -44,6 +44,7 @@ public GoblinShark(int age) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } @@ -54,6 +55,7 @@ public String getKind() { * @return the sharktype value. */ @Generated + @Override public String getSharktype() { return this.sharktype; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java index d4ac50818a..44b7b1494b 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Salmon.java @@ -59,6 +59,7 @@ public Salmon(int age) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java index 73e76ed194..4120bcd9ad 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/SawShark.java @@ -44,6 +44,7 @@ public SawShark(int age) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } @@ -54,6 +55,7 @@ public String getKind() { * @return the sharktype value. */ @Generated + @Override public String getSharktype() { return this.sharktype; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java index 221890824d..640495c57b 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/nesteddiscriminator/models/Shark.java @@ -44,6 +44,7 @@ public Shark(int age) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java index ed1b17ab32..c49d2e0ed3 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Eagle.java @@ -59,6 +59,7 @@ public Eagle(int wingspan) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java index 200f98290c..d097786368 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Goose.java @@ -38,6 +38,7 @@ public Goose(int wingspan) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java index 4702f258e8..07256e55c6 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/SeaGull.java @@ -38,6 +38,7 @@ public SeaGull(int wingspan) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java index 6e844b0aa2..93da94c4b7 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/Sparrow.java @@ -38,6 +38,7 @@ public Sparrow(int wingspan) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java index 3eeca7c711..90902817d5 100644 --- a/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java +++ b/typespec-tests/src/main/java/com/type/model/inheritance/singlediscriminator/models/TRex.java @@ -38,6 +38,7 @@ private TRex(int size) { * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java index edfa97d6b1..7fb248f4d3 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/ExtendsUnknownAdditionalPropertiesDiscriminatedDerived.java @@ -55,6 +55,7 @@ public ExtendsUnknownAdditionalPropertiesDiscriminatedDerived(String name, int i * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java index c40d083f2f..3d3c6049c1 100644 --- a/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java +++ b/typespec-tests/src/main/java/com/type/property/additionalproperties/models/IsUnknownAdditionalPropertiesDiscriminatedDerived.java @@ -55,6 +55,7 @@ public IsUnknownAdditionalPropertiesDiscriminatedDerived(String name, int index) * @return the kind value. */ @Generated + @Override public String getKind() { return this.kind; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java index 60b64b5956..410320f592 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Cookiecuttershark.java @@ -44,6 +44,7 @@ public Cookiecuttershark(@JsonProperty(value = "length", required = true) float * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java index 532031873d..48622fa472 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/DotSalmon.java @@ -47,6 +47,7 @@ private DotSalmon() { * * @return the fishType value. */ + @Override public String getFishType() { return this.fishType; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java index 2d0507d965..ea48ce47ba 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Goblinshark.java @@ -56,6 +56,7 @@ public Goblinshark(@JsonProperty(value = "length", required = true) float length * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java index c7bf56b7c5..8fa462fa1d 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/MyDerivedType.java @@ -41,6 +41,7 @@ private MyDerivedType() { * * @return the kind value. */ + @Override public MyKind getKind() { return this.kind; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java index 1b0f1502c2..31aca6fc8e 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Salmon.java @@ -55,6 +55,7 @@ public Salmon(@JsonProperty(value = "length", required = true) float length) { * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java index e93661297b..3e5970029e 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Sawshark.java @@ -51,6 +51,7 @@ public Sawshark(@JsonProperty(value = "length", required = true) float length, * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java index f7b9b54f62..7480f85f9c 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/Shark.java @@ -63,6 +63,7 @@ public Shark(@JsonProperty(value = "length", required = true) float length, * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java index 276c5baf60..5c8879704c 100644 --- a/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java +++ b/vanilla-tests/src/main/java/fixtures/bodycomplex/models/SmartSalmon.java @@ -58,6 +58,7 @@ public SmartSalmon(@JsonProperty(value = "length", required = true) float length * * @return the fishtype value. */ + @Override public String getFishtype() { return this.fishtype; } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java index c622e2246a..6b15da979a 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorenum/models/Golden.java @@ -31,6 +31,7 @@ public Golden() { * * @return the kind value. */ + @Override public DogKind getKind() { return this.kind; } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java index d248d550e1..5da2050b87 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/clientflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -46,6 +46,7 @@ public MetricAlertSingleResourceMultipleMetricCriteria() { * * @return the odataType value. */ + @Override public Odatatype getOdataType() { return this.odataType; } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java index cea792d388..383f06ed88 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -46,6 +46,7 @@ public MetricAlertSingleResourceMultipleMetricCriteria() { * * @return the odataType value. */ + @Override public Odatatype getOdataType() { return this.odataType; } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java index 049be98e48..d5e55b8c0f 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/noflatten/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -46,6 +46,7 @@ public MetricAlertSingleResourceMultipleMetricCriteria() { * * @return the odataType value. */ + @Override public Odatatype getOdataType() { return this.odataType; } diff --git a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java index 6cf2970fdb..7be6b94dd7 100644 --- a/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/discriminatorflattening/requirexmsflattened/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -46,6 +46,7 @@ public MetricAlertSingleResourceMultipleMetricCriteria() { * * @return the odataType value. */ + @Override public Odatatype getOdataType() { return this.odataType; } diff --git a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java index f444d1b7ac..b74ce6da13 100644 --- a/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java +++ b/vanilla-tests/src/main/java/fixtures/inheritance/passdiscriminator/models/MetricAlertSingleResourceMultipleMetricCriteria.java @@ -46,6 +46,7 @@ public MetricAlertSingleResourceMultipleMetricCriteria() { * * @return the odataType value. */ + @Override public Odatatype getOdataType() { return this.odataType; }