From 667b3ef05ae99cfa3c1ff63a6d52728eb06b67c2 Mon Sep 17 00:00:00 2001 From: xiaofeicao Date: Mon, 10 Jun 2024 23:36:21 +0800 Subject: [PATCH 1/9] test case swagger test deserialization --- .../java/com/azure/mgmttest/RuntimeTests.java | 6 ++-- .../swagger/stream-style-serialization.json | 13 ++++++++ .../tsp/arm-stream-style-serialization.tsp | 33 ++++++++++++++++++- typespec-tests/tspconfig.yaml | 1 + 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java b/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java index 5c009dc082..d823e929ba 100644 --- a/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java +++ b/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java @@ -486,14 +486,16 @@ private static void assertMethodExist(Class clazz, String methodName, Str @Test public void testStreamStyleSerialization() throws IOException { SerializerAdapter serializerAdapter = SerializerFactory.createDefaultManagementSerializerAdapter(); - String pirCommunityGalleryResourceJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\"}"; + String pirCommunityGalleryResourceJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\", \"identifier\": {\"uniqueId\": \"abc\"}}"; PirCommunityGalleryResource pirCommunityGalleryResource = serializerAdapter.deserialize(pirCommunityGalleryResourceJson, PirCommunityGalleryResource.class, SerializerEncoding.JSON); Assertions.assertEquals("myName", pirCommunityGalleryResource.name()); + Assertions.assertEquals("abc", pirCommunityGalleryResource.uniqueId()); - String galleryJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\",\"disclaimer\":\"myDisclaimer\"}"; + String galleryJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\",\"disclaimer\":\"myDisclaimer\", \"identifier\": {\"uniqueId\": \"abc\"}}"; CommunityGalleryInner galleryInner = serializerAdapter.deserialize(galleryJson, CommunityGalleryInner.class, SerializerEncoding.JSON); Assertions.assertEquals("myName", galleryInner.name()); Assertions.assertEquals("myDisclaimer", galleryInner.disclaimer()); + Assertions.assertEquals("abc", pirCommunityGalleryResource.uniqueId()); } } diff --git a/fluent-tests/swagger/stream-style-serialization.json b/fluent-tests/swagger/stream-style-serialization.json index 10c06a4e51..c88bf96fa8 100644 --- a/fluent-tests/swagger/stream-style-serialization.json +++ b/fluent-tests/swagger/stream-style-serialization.json @@ -48,10 +48,23 @@ "readOnly": true, "type": "string", "description": "Resource type" + }, + "identifier": { + "x-ms-client-flatten": true, + "$ref": "#/definitions/CommunityGalleryIdentifier" } }, "description": "Base information about the community gallery resource in azure compute gallery." }, + "CommunityGalleryIdentifier": { + "properties": { + "uniqueId": { + "type": "string", + "description": "The unique id of this community gallery." + } + }, + "description": "The identifier information of community gallery." + }, "CommunityGallery": { "properties": { "disclaimer": { diff --git a/typespec-tests/tsp/arm-stream-style-serialization.tsp b/typespec-tests/tsp/arm-stream-style-serialization.tsp index baa5171a37..3ad3825324 100644 --- a/typespec-tests/tsp/arm-stream-style-serialization.tsp +++ b/typespec-tests/tsp/arm-stream-style-serialization.tsp @@ -36,6 +36,9 @@ model Fish { @visibility("create", "read") dna: string; + + properties: FishProperties; + anotherProperties: AnotherFishProperties; } @doc("The second level model in polymorphic multiple levels inheritance and it defines a new discriminator.") @@ -53,6 +56,26 @@ model Salmon extends Fish { partner?: Fish; } +model FishProperties { + tailProperties: TailProperties; +} + +model TailProperties { + length: float32; + @visibility("read") + patten: string; +} + +model AnotherFishProperties { + eyeProperties: EyeProperties; +} + +model EyeProperties { + length: float32; + @visibility("read") + patten: string; +} + @doc("The third level model SawShark in polymorphic multiple levels inheritance.") model SawShark extends Shark { sharktype: "saw"; @@ -79,12 +102,20 @@ model TopLevelArmResourceProperties { description?: string; } +@route("/model") interface Fishes { - @route("/model") @get getModel(): Fish; + + @put + putModel(@body fish: Fish): Fish; } interface TopLevelArmResources { update is ArmCustomPatchAsync; } + +@@flattenProperty(Fish.properties); +@@flattenProperty(FishProperties.tailProperties); +@@flattenProperty(Fish.anotherProperties); +@@flattenProperty(AnotherFishProperties.eyeProperties); \ No newline at end of file diff --git a/typespec-tests/tspconfig.yaml b/typespec-tests/tspconfig.yaml index f38c42a954..105c9595c9 100644 --- a/typespec-tests/tspconfig.yaml +++ b/typespec-tests/tspconfig.yaml @@ -8,6 +8,7 @@ options: generate-tests: true examples-directory: "{project-root}/tsp/examples" flavor: "Azure" + stream-style-serialization: true dev-options: generate-code-model: true loglevel: info From 3bc20e231605f4b7382292ca2f3a1edb5adc242b Mon Sep 17 00:00:00 2001 From: xiaofeicao Date: Fri, 14 Jun 2024 15:18:34 +0800 Subject: [PATCH 2/9] fix flatten --- .../autorest/template/ModelTemplate.java | 39 +++++++++--- .../StreamSerializationModelTemplate.java | 62 ++++++++++++++++++- 2 files changed, 89 insertions(+), 12 deletions(-) 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 bce2372f78..8a0d1dab39 100644 --- a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java @@ -267,7 +267,8 @@ public final void write(ClientModel model, JavaFile javaFile) { if (settings.getClientFlattenAnnotationTarget() == JavaSettings.ClientFlattenAnnotationTarget.NONE) { // reference to properties from flattened client model for (ClientModelPropertyReference propertyReference : propertyReferences) { - if (!propertyReference.isFromFlattenedProperty()) { + propertyReference = getLocalFlattenedModelPropertyReference(propertyReference); + if (propertyReference == null) { continue; } @@ -299,9 +300,10 @@ public final void write(ClientModel model, JavaFile javaFile) { if (!propertyIsReadOnly) { generateSetterJavadoc(classBlock, model, property); addGeneratedAnnotation(classBlock); + ClientModelPropertyReference propertyReferenceFinal = propertyReference; classBlock.publicMethod(String.format("%s %s(%s %s)", model.getName(), propertyReference.getSetterName(), propertyClientType, property.getName()), methodBlock -> { methodBlock.ifBlock(String.format("this.%s() == null", targetProperty.getGetterName()), ifBlock -> - methodBlock.line(String.format("this.%s = new %s();", targetProperty.getName(), propertyReference.getTargetModelType()))); + methodBlock.line(String.format("this.%s = new %s();", targetProperty.getName(), propertyReferenceFinal.getTargetModelType()))); methodBlock.line(String.format("this.%s().%s(%s);", targetProperty.getGetterName(), property.getSetterName(), property.getName())); methodBlock.methodReturn("this"); @@ -322,6 +324,20 @@ public final void write(ClientModel model, JavaFile javaFile) { }); } + /** + * Get the property reference referring to the local(field) flattened property. + * + * @param propertyReference propertyReference to check + * @return the property reference referring to the local(field) flattened property, null if it's not + */ + protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference(ClientModelPropertyReference propertyReference) { + if (propertyReference.isFromFlattenedProperty()) { + return propertyReference; + } + // Not a flattening property, return null. + return null; + } + /** * Whether the property's getter overrides parent getter. * @param model the client model @@ -412,27 +428,30 @@ protected void addSerializationImports(Set imports, ClientModel model, J } /** - * Override parent setters if: 1. parent property has setter 2. child does not contain property that shadow this - * parent property, otherwise overridden parent setter methods will collide with child setter methods + * Override parent setters if: + * 1. parent property has setter + * 2. child does not contain property that shadow this parent property, otherwise overridden parent setter methods + * will collide with child setter methods + * 3. the propertyReference isn't flattening property or we don't generate local getter/setter * * @see Issue 1320 */ protected List getParentSettersToOverride(ClientModel model, JavaSettings settings, List propertyReferences) { - Set modelPropertyNames = model.getProperties().stream().map(ClientModelProperty::getName) + Set modelPropertyNames = getFieldProperties(model, settings).stream().map(ClientModelProperty::getName) .collect(Collectors.toSet()); return propertyReferences.stream() - .filter(ClientModelPropertyReference::isFromParentModel) - .map(ClientModelPropertyReference::getReferenceProperty) - .filter(parentProperty -> { + .filter(ClientModelPropertyReference::isFromParentModel) + .map(ClientModelPropertyReference::getReferenceProperty) + .filter(parentProperty -> { // parent property doesn't have setter if (!ClientModelUtil.hasSetter(parentProperty, settings)) { return false; } // child does not contain property that shadow this parent property return !modelPropertyNames.contains(parentProperty.getName()); - } - ).collect(Collectors.toList()); + }) + .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 4c2ba5f1e1..08925527ba 100644 --- a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java @@ -10,6 +10,8 @@ import com.azure.autorest.model.clientmodel.ClassType; import com.azure.autorest.model.clientmodel.ClientModel; import com.azure.autorest.model.clientmodel.ClientModelProperty; +import com.azure.autorest.model.clientmodel.ClientModelPropertyAccess; +import com.azure.autorest.model.clientmodel.ClientModelPropertyReference; import com.azure.autorest.model.clientmodel.IType; import com.azure.autorest.model.clientmodel.IterableType; import com.azure.autorest.model.clientmodel.MapType; @@ -246,6 +248,7 @@ protected List getFieldProperties(ClientModel model, JavaSe // parent discriminators are already passed to children, see @see in method javadoc !property.isPolymorphicDiscriminator() && readOnlyNotInCtor(model, property, settings) + || property.getClientFlatten() ) ).collect(Collectors.toList()); } @@ -262,6 +265,61 @@ protected boolean isOverrideParentGetter(ClientModel model, ClientModelProperty return !modelDefinesProperty(model, property) && (property.isPolymorphicDiscriminator() || readOnlyNotInCtor(model, property, settings)); } + /** + * 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                    <--------------
+     *                                                       |
+     *         Model1                                        |
+     *          - innerProperties: FlattenProperties         |
+     *          - property1FromFlatten    ^    <--           |
+     *              - referenceProperty   |      |       ----|
+     *              - targetProperty    ---      |
+     *                                           |
+     *         Model2 extends Model1             |
+     *          (- property1FromParent)          |
+     *              - referenceProperty      ----|
+     *              - 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. + * + * @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 + */ + @Override + 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()) { + return (ClientModelPropertyReference) parentProperty; + } + } + // Not a flattening property, return null. + return null; + } + + @Override + protected List getParentSettersToOverride(ClientModel model, JavaSettings settings, List propertyReferences) { + return super.getParentSettersToOverride(model, settings, propertyReferences) + .stream() + // If the propertyReference is flattening property, and we generate local getter/setter + // for it, then we don't need to override its parent setter. + .filter(propertyReference -> + !(propertyReference instanceof ClientModelPropertyReference) + || getLocalFlattenedModelPropertyReference((ClientModelPropertyReference) propertyReference) == null) + .collect(Collectors.toList()); + } + private static boolean readOnlyNotInCtor(ClientModel model, ClientModelProperty property, JavaSettings settings) { return // not required and in constructor !(property.isRequired() && settings.isRequiredFieldsAsConstructorArgs()) @@ -1507,8 +1565,8 @@ private static void handleSettingDeserializedValue(JavaBlock methodBlock, String // 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 read-only from parent, it will be shadowed in child class. - && !readOnlyNotInCtor(model, property, JavaSettings.getInstance())) { + // If the property is flattened or read-only from parent, it will be shadowed in child class. + && (!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 From a224119af35ac54677427267e4bd027c22463599 Mon Sep 17 00:00:00 2001 From: xiaofeicao Date: Fri, 14 Jun 2024 12:14:45 +0800 Subject: [PATCH 3/9] avoid shadow properties conflict --- .../java/com/azure/mgmttest/RuntimeTests.java | 2 +- .../swagger/stream-style-serialization.json | 18 +++++++++++-- .../StreamSerializationModelTemplate.java | 26 ++++++++++--------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java b/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java index d823e929ba..e0fde5f302 100644 --- a/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java +++ b/fluent-tests/src/test/java/com/azure/mgmttest/RuntimeTests.java @@ -492,7 +492,7 @@ public void testStreamStyleSerialization() throws IOException { Assertions.assertEquals("myName", pirCommunityGalleryResource.name()); Assertions.assertEquals("abc", pirCommunityGalleryResource.uniqueId()); - String galleryJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\",\"disclaimer\":\"myDisclaimer\", \"identifier\": {\"uniqueId\": \"abc\"}}"; + String galleryJson = "{\"name\":\"myName\",\"location\":\"myLocation\",\"type\":\"myType\", \"properties\": {\"disclaimer\":\"myDisclaimer\"}, \"identifier\": {\"uniqueId\": \"abc\"}}"; CommunityGalleryInner galleryInner = serializerAdapter.deserialize(galleryJson, CommunityGalleryInner.class, SerializerEncoding.JSON); Assertions.assertEquals("myName", galleryInner.name()); Assertions.assertEquals("myDisclaimer", galleryInner.disclaimer()); diff --git a/fluent-tests/swagger/stream-style-serialization.json b/fluent-tests/swagger/stream-style-serialization.json index c88bf96fa8..443c05f4cb 100644 --- a/fluent-tests/swagger/stream-style-serialization.json +++ b/fluent-tests/swagger/stream-style-serialization.json @@ -67,10 +67,14 @@ }, "CommunityGallery": { "properties": { - "disclaimer": { + "name": { "readOnly": true, "type": "string", - "description": "Community gallery disclaimer" + "description": "Resource name in Child" + }, + "properties": { + "x-ms-client-flatten": true, + "$ref": "#/definitions/CommunityGalleryProperties" } }, "allOf": [ @@ -79,6 +83,16 @@ } ], "description": "Specifies information about the Community Gallery that you want to create or update." + }, + "CommunityGalleryProperties": { + "type": "object", + "properties": { + "disclaimer": { + "type": "string", + "description": "Resource name" + } + }, + "description": "Describes the properties of a community gallery." } }, "parameters": { 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 08925527ba..631cc7d663 100644 --- a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java @@ -44,7 +44,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; -import java.util.stream.Stream; import static com.azure.autorest.util.ClientModelUtil.JSON_MERGE_PATCH_HELPER_CLASS_NAME; import static com.azure.autorest.util.ClientModelUtil.includePropertyInConstructor; @@ -240,17 +239,20 @@ protected void writeStreamStyleSerialization(JavaClass classBlock, ClientModel m */ @Override protected List getFieldProperties(ClientModel model, JavaSettings settings) { - return Stream.concat( - super.getFieldProperties(model, settings).stream(), - ClientModelUtil.getParentProperties(model) - .stream() - .filter(property -> - // parent discriminators are already passed to children, see @see in method javadoc - !property.isPolymorphicDiscriminator() - && readOnlyNotInCtor(model, property, settings) - || property.getClientFlatten() - ) - ).collect(Collectors.toList()); + List fieldProperties = super.getFieldProperties(model, settings); + Set propertySerializedNames = fieldProperties.stream().map(ClientModelProperty::getSerializedName).collect(Collectors.toSet()); + for (ClientModelProperty parentProperty : ClientModelUtil.getParentProperties(model)) { + 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 + && readOnlyNotInCtor(model, parentProperty, settings) // we shadow parent read-only properties in child class + || parentProperty.getClientFlatten()) { // we shadow parent flattened property in child class + fieldProperties.add(parentProperty); + } + } + return fieldProperties; } /** From 8c8daf1d46b74d0421ff853bb1588fdb35371907 Mon Sep 17 00:00:00 2001 From: actions-user Date: Fri, 14 Jun 2024 07:27:26 +0000 Subject: [PATCH 4/9] re-generate test code --- .../fluent/FishesClient.java | 26 +++ .../fluent/models/AnotherFishProperties.java | 125 ++++++++++++++ .../fluent/models/EyeProperties.java | 110 +++++++++++++ .../fluent/models/FishInner.java | 143 +++++++++++++++- .../fluent/models/FishProperties.java | 125 ++++++++++++++ .../fluent/models/SalmonInner.java | 155 ++++++++++++++++-- .../fluent/models/TailProperties.java | 110 +++++++++++++ .../implementation/FishImpl.java | 16 ++ .../implementation/FishesClientImpl.java | 107 ++++++++++++ .../implementation/FishesImpl.java | 19 +++ .../implementation/SalmonImpl.java | 16 ++ .../models/Fish.java | 28 ++++ .../models/Fishes.java | 25 +++ .../models/GoblinShark.java | 124 ++++++++++++-- .../models/Salmon.java | 28 ++++ .../models/SawShark.java | 124 ++++++++++++-- .../models/Shark.java | 124 ++++++++++++-- 17 files changed, 1328 insertions(+), 77 deletions(-) create mode 100644 typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/AnotherFishProperties.java create mode 100644 typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/EyeProperties.java create mode 100644 typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishProperties.java create mode 100644 typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/TailProperties.java diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/FishesClient.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/FishesClient.java index de5031e469..5a613b66f8 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/FishesClient.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/FishesClient.java @@ -36,4 +36,30 @@ public interface FishesClient { */ @ServiceMethod(returns = ReturnType.SINGLE) FishInner getModel(); + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator along with + * {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + Response putModelWithResponse(FishInner fish, Context context); + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + FishInner putModel(FishInner fish); } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/AnotherFishProperties.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/AnotherFishProperties.java new file mode 100644 index 0000000000..62879a4e45 --- /dev/null +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/AnotherFishProperties.java @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.cadl.armstreamstyleserialization.fluent.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.util.logging.ClientLogger; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The AnotherFishProperties model. + */ +@Fluent +public final class AnotherFishProperties implements JsonSerializable { + /* + * The eyeProperties property. + */ + private EyeProperties innerEyeProperties = new EyeProperties(); + + /** + * Creates an instance of AnotherFishProperties class. + */ + public AnotherFishProperties() { + } + + /** + * Get the innerEyeProperties property: The eyeProperties property. + * + * @return the innerEyeProperties value. + */ + private EyeProperties innerEyeProperties() { + return this.innerEyeProperties; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerEyeProperties() == null ? 0.0 : this.innerEyeProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the AnotherFishProperties object itself. + */ + public AnotherFishProperties withLength(double length) { + if (this.innerEyeProperties() == null) { + this.innerEyeProperties = new EyeProperties(); + } + this.innerEyeProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerEyeProperties() == null ? null : this.innerEyeProperties().patten(); + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { + if (innerEyeProperties() == null) { + throw LOGGER.atError() + .log(new IllegalArgumentException( + "Missing required property innerEyeProperties in model AnotherFishProperties")); + } else { + innerEyeProperties().validate(); + } + } + + private static final ClientLogger LOGGER = new ClientLogger(AnotherFishProperties.class); + + /** + * {@inheritDoc} + */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeJsonField("eyeProperties", this.innerEyeProperties); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of AnotherFishProperties from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of AnotherFishProperties if the JsonReader was pointing to an instance of it, or null if it + * was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the AnotherFishProperties. + */ + public static AnotherFishProperties fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + AnotherFishProperties deserializedAnotherFishProperties = new AnotherFishProperties(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("eyeProperties".equals(fieldName)) { + deserializedAnotherFishProperties.innerEyeProperties = EyeProperties.fromJson(reader); + } else { + reader.skipChildren(); + } + } + + return deserializedAnotherFishProperties; + }); + } +} diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/EyeProperties.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/EyeProperties.java new file mode 100644 index 0000000000..241ce55ef6 --- /dev/null +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/EyeProperties.java @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.cadl.armstreamstyleserialization.fluent.models; + +import com.azure.core.annotation.Fluent; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The EyeProperties model. + */ +@Fluent +public final class EyeProperties implements JsonSerializable { + /* + * The length property. + */ + private double length; + + /* + * The patten property. + */ + private String patten; + + /** + * Creates an instance of EyeProperties class. + */ + public EyeProperties() { + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.length; + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the EyeProperties object itself. + */ + public EyeProperties withLength(double length) { + this.length = length; + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.patten; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { + } + + /** + * {@inheritDoc} + */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeDoubleField("length", this.length); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of EyeProperties from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of EyeProperties if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the EyeProperties. + */ + public static EyeProperties fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + EyeProperties deserializedEyeProperties = new EyeProperties(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("length".equals(fieldName)) { + deserializedEyeProperties.length = reader.getDouble(); + } else if ("patten".equals(fieldName)) { + deserializedEyeProperties.patten = reader.getString(); + } else { + reader.skipChildren(); + } + } + + return deserializedEyeProperties; + }); + } +} diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java index 19f4e2e8d5..3f0137b403 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java @@ -4,7 +4,7 @@ package com.cadl.armstreamstyleserialization.fluent.models; -import com.azure.core.annotation.Immutable; +import com.azure.core.annotation.Fluent; import com.azure.core.util.logging.ClientLogger; import com.azure.json.JsonReader; import com.azure.json.JsonSerializable; @@ -16,7 +16,7 @@ /** * This is base model for polymorphic multiple levels inheritance with a discriminator. */ -@Immutable +@Fluent public class FishInner implements JsonSerializable { /* * Discriminator property for Fish. @@ -33,10 +33,20 @@ public class FishInner implements JsonSerializable { */ private String dna; + /* + * The properties property. + */ + private FishProperties innerProperties = new FishProperties(); + + /* + * The anotherProperties property. + */ + private AnotherFishProperties innerAnotherProperties = new AnotherFishProperties(); + /** * Creates an instance of FishInner class. */ - protected FishInner() { + public FishInner() { } /** @@ -63,7 +73,7 @@ public int age() { * @param age the age value to set. * @return the FishInner object itself. */ - FishInner withAge(int age) { + public FishInner withAge(int age) { this.age = age; return this; } @@ -83,11 +93,115 @@ public String dna() { * @param dna the dna value to set. * @return the FishInner object itself. */ - FishInner withDna(String dna) { + public FishInner withDna(String dna) { this.dna = dna; return this; } + /** + * Get the innerProperties property: The properties property. + * + * @return the innerProperties value. + */ + private FishProperties innerProperties() { + return this.innerProperties; + } + + /** + * Set the innerProperties property: The properties property. + * + * @param innerProperties the innerProperties value to set. + * @return the FishInner object itself. + */ + FishInner withInnerProperties(FishProperties innerProperties) { + this.innerProperties = innerProperties; + return this; + } + + /** + * Get the innerAnotherProperties property: The anotherProperties property. + * + * @return the innerAnotherProperties value. + */ + private AnotherFishProperties innerAnotherProperties() { + return this.innerAnotherProperties; + } + + /** + * Set the innerAnotherProperties property: The anotherProperties property. + * + * @param innerAnotherProperties the innerAnotherProperties value to set. + * @return the FishInner object itself. + */ + FishInner withInnerAnotherProperties(AnotherFishProperties innerAnotherProperties) { + this.innerAnotherProperties = innerAnotherProperties; + return this; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerProperties() == null ? 0.0 : this.innerProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the FishInner object itself. + */ + public FishInner withLength(double length) { + if (this.innerProperties() == null) { + this.innerProperties = new FishProperties(); + } + this.innerProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerProperties() == null ? null : this.innerProperties().patten(); + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double lengthAnotherPropertiesLength() { + return this.innerAnotherProperties() == null ? 0.0 : this.innerAnotherProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the FishInner object itself. + */ + public FishInner withLengthAnotherPropertiesLength(double length) { + if (this.innerAnotherProperties() == null) { + this.innerAnotherProperties = new AnotherFishProperties(); + } + this.innerAnotherProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String pattenAnotherPropertiesPatten() { + return this.innerAnotherProperties() == null ? null : this.innerAnotherProperties().patten(); + } + /** * Validates the instance. * @@ -98,6 +212,19 @@ public void validate() { throw LOGGER.atError() .log(new IllegalArgumentException("Missing required property dna in model FishInner")); } + if (innerProperties() == null) { + throw LOGGER.atError() + .log(new IllegalArgumentException("Missing required property innerProperties in model FishInner")); + } else { + innerProperties().validate(); + } + if (innerAnotherProperties() == null) { + throw LOGGER.atError() + .log(new IllegalArgumentException( + "Missing required property innerAnotherProperties in model FishInner")); + } else { + innerAnotherProperties().validate(); + } } private static final ClientLogger LOGGER = new ClientLogger(FishInner.class); @@ -110,6 +237,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeIntField("age", this.age); jsonWriter.writeStringField("dna", this.dna); + jsonWriter.writeJsonField("properties", this.innerProperties); + jsonWriter.writeJsonField("anotherProperties", this.innerAnotherProperties); jsonWriter.writeStringField("kind", this.kind); return jsonWriter.writeEndObject(); } @@ -161,6 +290,10 @@ static FishInner fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExce deserializedFishInner.age = reader.getInt(); } else if ("dna".equals(fieldName)) { deserializedFishInner.dna = reader.getString(); + } else if ("properties".equals(fieldName)) { + deserializedFishInner.innerProperties = FishProperties.fromJson(reader); + } else if ("anotherProperties".equals(fieldName)) { + deserializedFishInner.innerAnotherProperties = AnotherFishProperties.fromJson(reader); } else if ("kind".equals(fieldName)) { deserializedFishInner.kind = reader.getString(); } else { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishProperties.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishProperties.java new file mode 100644 index 0000000000..9b97c3f4dd --- /dev/null +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishProperties.java @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.cadl.armstreamstyleserialization.fluent.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.util.logging.ClientLogger; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The FishProperties model. + */ +@Fluent +public final class FishProperties implements JsonSerializable { + /* + * The tailProperties property. + */ + private TailProperties innerTailProperties = new TailProperties(); + + /** + * Creates an instance of FishProperties class. + */ + public FishProperties() { + } + + /** + * Get the innerTailProperties property: The tailProperties property. + * + * @return the innerTailProperties value. + */ + private TailProperties innerTailProperties() { + return this.innerTailProperties; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerTailProperties() == null ? 0.0 : this.innerTailProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the FishProperties object itself. + */ + public FishProperties withLength(double length) { + if (this.innerTailProperties() == null) { + this.innerTailProperties = new TailProperties(); + } + this.innerTailProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerTailProperties() == null ? null : this.innerTailProperties().patten(); + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { + if (innerTailProperties() == null) { + throw LOGGER.atError() + .log(new IllegalArgumentException( + "Missing required property innerTailProperties in model FishProperties")); + } else { + innerTailProperties().validate(); + } + } + + private static final ClientLogger LOGGER = new ClientLogger(FishProperties.class); + + /** + * {@inheritDoc} + */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeJsonField("tailProperties", this.innerTailProperties); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of FishProperties from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of FishProperties if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the FishProperties. + */ + public static FishProperties fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + FishProperties deserializedFishProperties = new FishProperties(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("tailProperties".equals(fieldName)) { + deserializedFishProperties.innerTailProperties = TailProperties.fromJson(reader); + } else { + reader.skipChildren(); + } + } + + return deserializedFishProperties; + }); + } +} diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java index 55511d88d7..212b5981c9 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java @@ -4,7 +4,7 @@ package com.cadl.armstreamstyleserialization.fluent.models; -import com.azure.core.annotation.Immutable; +import com.azure.core.annotation.Fluent; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; @@ -16,7 +16,7 @@ * The second level model in polymorphic multiple levels inheritance which contains references to other polymorphic * instances. */ -@Immutable +@Fluent public final class SalmonInner extends FishInner { /* * Discriminator property for Fish. @@ -39,19 +39,19 @@ public final class SalmonInner extends FishInner { private FishInner partner; /* - * The age property. + * The properties property. */ - private int age; + private FishProperties innerProperties = new FishProperties(); /* - * The dna property. + * The anotherProperties property. */ - private String dna; + private AnotherFishProperties innerAnotherProperties = new AnotherFishProperties(); /** * Creates an instance of SalmonInner class. */ - private SalmonInner() { + public SalmonInner() { } /** @@ -73,6 +73,17 @@ public List friends() { return this.friends; } + /** + * Set the friends property: The friends property. + * + * @param friends the friends value to set. + * @return the SalmonInner object itself. + */ + public SalmonInner withFriends(List friends) { + this.friends = friends; + return this; + } + /** * Get the hate property: The hate property. * @@ -82,6 +93,17 @@ public Map hate() { return this.hate; } + /** + * Set the hate property: The hate property. + * + * @param hate the hate value to set. + * @return the SalmonInner object itself. + */ + public SalmonInner withHate(Map hate) { + this.hate = hate; + return this; + } + /** * Get the partner property: The partner property. * @@ -92,23 +114,114 @@ public FishInner partner() { } /** - * Get the age property: The age property. + * Set the partner property: The partner property. * - * @return the age value. + * @param partner the partner value to set. + * @return the SalmonInner object itself. */ - @Override - public int age() { - return this.age; + public SalmonInner withPartner(FishInner partner) { + this.partner = partner; + return this; + } + + /** + * Get the innerProperties property: The properties property. + * + * @return the innerProperties value. + */ + private FishProperties innerProperties() { + return this.innerProperties; } /** - * Get the dna property: The dna property. + * Get the innerAnotherProperties property: The anotherProperties property. * - * @return the dna value. + * @return the innerAnotherProperties value. + */ + private AnotherFishProperties innerAnotherProperties() { + return this.innerAnotherProperties; + } + + /** + * {@inheritDoc} */ @Override - public String dna() { - return this.dna; + public SalmonInner withAge(int age) { + super.withAge(age); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public SalmonInner withDna(String dna) { + super.withDna(dna); + return this; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerProperties() == null ? 0.0 : this.innerProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the SalmonInner object itself. + */ + public SalmonInner withLength(double length) { + if (this.innerProperties() == null) { + this.innerProperties = new FishProperties(); + } + this.innerProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerProperties() == null ? null : this.innerProperties().patten(); + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double lengthAnotherPropertiesLength() { + return this.innerAnotherProperties() == null ? 0.0 : this.innerAnotherProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the SalmonInner object itself. + */ + public SalmonInner withLengthAnotherPropertiesLength(double length) { + if (this.innerAnotherProperties() == null) { + this.innerAnotherProperties = new AnotherFishProperties(); + } + this.innerAnotherProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String pattenAnotherPropertiesPatten() { + return this.innerAnotherProperties() == null ? null : this.innerAnotherProperties().patten(); } /** @@ -142,6 +255,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeIntField("age", age()); jsonWriter.writeStringField("dna", dna()); + jsonWriter.writeJsonField("properties", innerProperties()); + jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); 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)); @@ -166,9 +281,13 @@ public static SalmonInner fromJson(JsonReader jsonReader) throws IOException { reader.nextToken(); if ("age".equals(fieldName)) { - deserializedSalmonInner.age = reader.getInt(); + deserializedSalmonInner.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedSalmonInner.dna = reader.getString(); + deserializedSalmonInner.withDna(reader.getString()); + } else if ("properties".equals(fieldName)) { + deserializedSalmonInner.innerProperties = FishProperties.fromJson(reader); + } else if ("anotherProperties".equals(fieldName)) { + deserializedSalmonInner.innerAnotherProperties = AnotherFishProperties.fromJson(reader); } else if ("kind".equals(fieldName)) { deserializedSalmonInner.kind = reader.getString(); } else if ("friends".equals(fieldName)) { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/TailProperties.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/TailProperties.java new file mode 100644 index 0000000000..1c8a7dcc3c --- /dev/null +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/TailProperties.java @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.cadl.armstreamstyleserialization.fluent.models; + +import com.azure.core.annotation.Fluent; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The TailProperties model. + */ +@Fluent +public final class TailProperties implements JsonSerializable { + /* + * The length property. + */ + private double length; + + /* + * The patten property. + */ + private String patten; + + /** + * Creates an instance of TailProperties class. + */ + public TailProperties() { + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.length; + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the TailProperties object itself. + */ + public TailProperties withLength(double length) { + this.length = length; + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.patten; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { + } + + /** + * {@inheritDoc} + */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeDoubleField("length", this.length); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of TailProperties from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of TailProperties if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the TailProperties. + */ + public static TailProperties fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + TailProperties deserializedTailProperties = new TailProperties(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("length".equals(fieldName)) { + deserializedTailProperties.length = reader.getDouble(); + } else if ("patten".equals(fieldName)) { + deserializedTailProperties.patten = reader.getString(); + } else { + reader.skipChildren(); + } + } + + return deserializedTailProperties; + }); + } +} diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishImpl.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishImpl.java index e2dc11a506..68162abc5a 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishImpl.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishImpl.java @@ -30,6 +30,22 @@ public String dna() { return this.innerModel().dna(); } + public double length() { + return this.innerModel().length(); + } + + public String patten() { + return this.innerModel().patten(); + } + + public double lengthAnotherPropertiesLength() { + return this.innerModel().lengthAnotherPropertiesLength(); + } + + public String pattenAnotherPropertiesPatten() { + return this.innerModel().pattenAnotherPropertiesPatten(); + } + public FishInner innerModel() { return this.innerObject; } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesClientImpl.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesClientImpl.java index 253258fc1a..86f1103f2e 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesClientImpl.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesClientImpl.java @@ -4,12 +4,14 @@ package com.cadl.armstreamstyleserialization.implementation; +import com.azure.core.annotation.BodyParam; import com.azure.core.annotation.ExpectedResponses; import com.azure.core.annotation.Get; import com.azure.core.annotation.HeaderParam; import com.azure.core.annotation.Headers; import com.azure.core.annotation.Host; import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.Put; import com.azure.core.annotation.ReturnType; import com.azure.core.annotation.ServiceInterface; import com.azure.core.annotation.ServiceMethod; @@ -60,6 +62,13 @@ public interface FishesService { @UnexpectedResponseExceptionType(ManagementException.class) Mono> getModel(@HostParam("endpoint") String endpoint, @HeaderParam("accept") String accept, Context context); + + @Headers({ "Content-Type: application/json" }) + @Put("/model") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(ManagementException.class) + Mono> putModel(@HostParam("endpoint") String endpoint, @HeaderParam("accept") String accept, + @BodyParam("application/json") FishInner fish, Context context); } /** @@ -141,4 +150,102 @@ public Response getModelWithResponse(Context context) { public FishInner getModel() { return getModelWithResponse(Context.NONE).getValue(); } + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator along with + * {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> putModelWithResponseAsync(FishInner fish) { + if (this.client.getEndpoint() == null) { + return Mono.error( + new IllegalArgumentException("Parameter this.client.getEndpoint() is required and cannot be null.")); + } + if (fish == null) { + return Mono.error(new IllegalArgumentException("Parameter fish is required and cannot be null.")); + } else { + fish.validate(); + } + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.putModel(this.client.getEndpoint(), accept, fish, context)) + .contextWrite(context -> context.putAll(FluxUtil.toReactorContext(this.client.getContext()).readOnly())); + } + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator along with + * {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> putModelWithResponseAsync(FishInner fish, Context context) { + if (this.client.getEndpoint() == null) { + return Mono.error( + new IllegalArgumentException("Parameter this.client.getEndpoint() is required and cannot be null.")); + } + if (fish == null) { + return Mono.error(new IllegalArgumentException("Parameter fish is required and cannot be null.")); + } else { + fish.validate(); + } + final String accept = "application/json"; + context = this.client.mergeContext(context); + return service.putModel(this.client.getEndpoint(), accept, fish, context); + } + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator on successful + * completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono putModelAsync(FishInner fish) { + return putModelWithResponseAsync(fish).flatMap(res -> Mono.justOrEmpty(res.getValue())); + } + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator along with + * {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response putModelWithResponse(FishInner fish, Context context) { + return putModelWithResponseAsync(fish, context).block(); + } + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public FishInner putModel(FishInner fish) { + return putModelWithResponse(fish, Context.NONE).getValue(); + } } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesImpl.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesImpl.java index c34f9f0545..dbfaf4e3fc 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesImpl.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/FishesImpl.java @@ -45,6 +45,25 @@ public Fish getModel() { } } + public Response putModelWithResponse(FishInner fish, Context context) { + Response inner = this.serviceClient().putModelWithResponse(fish, context); + if (inner != null) { + return new SimpleResponse<>(inner.getRequest(), inner.getStatusCode(), inner.getHeaders(), + new FishImpl(inner.getValue(), this.manager())); + } else { + return null; + } + } + + public Fish putModel(FishInner fish) { + FishInner inner = this.serviceClient().putModel(fish); + if (inner != null) { + return new FishImpl(inner, this.manager()); + } else { + return null; + } + } + private FishesClient serviceClient() { return this.innerClient; } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/SalmonImpl.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/SalmonImpl.java index 8afa7a3133..b02d9b97bf 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/SalmonImpl.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/implementation/SalmonImpl.java @@ -32,6 +32,22 @@ public String dna() { return this.innerModel().dna(); } + public double length() { + return this.innerModel().length(); + } + + public String patten() { + return this.innerModel().patten(); + } + + public double lengthAnotherPropertiesLength() { + return this.innerModel().lengthAnotherPropertiesLength(); + } + + public String pattenAnotherPropertiesPatten() { + return this.innerModel().pattenAnotherPropertiesPatten(); + } + public String kind() { return this.innerModel().kind(); } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fish.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fish.java index 4b01608aca..71089c994c 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fish.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fish.java @@ -31,6 +31,34 @@ public interface Fish { */ String dna(); + /** + * Gets the length property: The length property. + * + * @return the length value. + */ + double length(); + + /** + * Gets the patten property: The patten property. + * + * @return the patten value. + */ + String patten(); + + /** + * Gets the lengthAnotherPropertiesLength property: The length property. + * + * @return the lengthAnotherPropertiesLength value. + */ + double lengthAnotherPropertiesLength(); + + /** + * Gets the pattenAnotherPropertiesPatten property: The patten property. + * + * @return the pattenAnotherPropertiesPatten value. + */ + String pattenAnotherPropertiesPatten(); + /** * Gets the inner com.cadl.armstreamstyleserialization.fluent.models.FishInner object. * diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fishes.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fishes.java index 4c6e5deabf..6df6e1c44f 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fishes.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Fishes.java @@ -6,6 +6,7 @@ import com.azure.core.http.rest.Response; import com.azure.core.util.Context; +import com.cadl.armstreamstyleserialization.fluent.models.FishInner; /** * Resource collection API of Fishes. @@ -31,4 +32,28 @@ public interface Fishes { * @return this is base model for polymorphic multiple levels inheritance with a discriminator. */ Fish getModel(); + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator along with + * {@link Response}. + */ + Response putModelWithResponse(FishInner fish, Context context); + + /** + * The putModel operation. + * + * @param fish The fish parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return this is base model for polymorphic multiple levels inheritance with a discriminator. + */ + Fish putModel(FishInner fish); } diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java index e053a7373f..a918838e52 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java @@ -4,16 +4,18 @@ package com.cadl.armstreamstyleserialization.models; -import com.azure.core.annotation.Immutable; +import com.azure.core.annotation.Fluent; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; +import com.cadl.armstreamstyleserialization.fluent.models.AnotherFishProperties; +import com.cadl.armstreamstyleserialization.fluent.models.FishProperties; import java.io.IOException; /** * The third level model GoblinShark in polymorphic multiple levels inheritance. */ -@Immutable +@Fluent public final class GoblinShark extends Shark { /* * Discriminator property for Fish. @@ -26,19 +28,19 @@ public final class GoblinShark extends Shark { private String sharktype = "goblin"; /* - * The age property. + * The properties property. */ - private int age; + private FishProperties innerProperties = new FishProperties(); /* - * The dna property. + * The anotherProperties property. */ - private String dna; + private AnotherFishProperties innerAnotherProperties = new AnotherFishProperties(); /** * Creates an instance of GoblinShark class. */ - private GoblinShark() { + public GoblinShark() { } /** @@ -62,23 +64,103 @@ public String sharktype() { } /** - * Get the age property: The age property. + * Get the innerProperties property: The properties property. * - * @return the age value. + * @return the innerProperties value. */ - @Override - public int age() { - return this.age; + private FishProperties innerProperties() { + return this.innerProperties; } /** - * Get the dna property: The dna property. + * Get the innerAnotherProperties property: The anotherProperties property. * - * @return the dna value. + * @return the innerAnotherProperties value. + */ + private AnotherFishProperties innerAnotherProperties() { + return this.innerAnotherProperties; + } + + /** + * {@inheritDoc} */ @Override - public String dna() { - return this.dna; + public GoblinShark withAge(int age) { + super.withAge(age); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public GoblinShark withDna(String dna) { + super.withDna(dna); + return this; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerProperties() == null ? 0.0 : this.innerProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the GoblinShark object itself. + */ + public GoblinShark withLength(double length) { + if (this.innerProperties() == null) { + this.innerProperties = new FishProperties(); + } + this.innerProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerProperties() == null ? null : this.innerProperties().patten(); + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double lengthAnotherPropertiesLength() { + return this.innerAnotherProperties() == null ? 0.0 : this.innerAnotherProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the GoblinShark object itself. + */ + public GoblinShark withLengthAnotherPropertiesLength(double length) { + if (this.innerAnotherProperties() == null) { + this.innerAnotherProperties = new AnotherFishProperties(); + } + this.innerAnotherProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String pattenAnotherPropertiesPatten() { + return this.innerAnotherProperties() == null ? null : this.innerAnotherProperties().patten(); } /** @@ -100,6 +182,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); jsonWriter.writeStringField("dna", dna()); + jsonWriter.writeJsonField("properties", innerProperties()); + jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); return jsonWriter.writeEndObject(); } @@ -121,9 +205,13 @@ public static GoblinShark fromJson(JsonReader jsonReader) throws IOException { reader.nextToken(); if ("age".equals(fieldName)) { - deserializedGoblinShark.age = reader.getInt(); + deserializedGoblinShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedGoblinShark.dna = reader.getString(); + deserializedGoblinShark.withDna(reader.getString()); + } else if ("properties".equals(fieldName)) { + deserializedGoblinShark.innerProperties = FishProperties.fromJson(reader); + } else if ("anotherProperties".equals(fieldName)) { + deserializedGoblinShark.innerAnotherProperties = AnotherFishProperties.fromJson(reader); } else if ("sharktype".equals(fieldName)) { deserializedGoblinShark.sharktype = reader.getString(); } else { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Salmon.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Salmon.java index 4eac1b71bf..bef9a90f84 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Salmon.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Salmon.java @@ -26,6 +26,34 @@ public interface Salmon { */ String dna(); + /** + * Gets the length property: The length property. + * + * @return the length value. + */ + double length(); + + /** + * Gets the patten property: The patten property. + * + * @return the patten value. + */ + String patten(); + + /** + * Gets the lengthAnotherPropertiesLength property: The length property. + * + * @return the lengthAnotherPropertiesLength value. + */ + double lengthAnotherPropertiesLength(); + + /** + * Gets the pattenAnotherPropertiesPatten property: The patten property. + * + * @return the pattenAnotherPropertiesPatten value. + */ + String pattenAnotherPropertiesPatten(); + /** * Gets the kind property: Discriminator property for Fish. * diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java index b15dffcaa1..9fda2f385f 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java @@ -4,16 +4,18 @@ package com.cadl.armstreamstyleserialization.models; -import com.azure.core.annotation.Immutable; +import com.azure.core.annotation.Fluent; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; +import com.cadl.armstreamstyleserialization.fluent.models.AnotherFishProperties; +import com.cadl.armstreamstyleserialization.fluent.models.FishProperties; import java.io.IOException; /** * The third level model SawShark in polymorphic multiple levels inheritance. */ -@Immutable +@Fluent public final class SawShark extends Shark { /* * Discriminator property for Fish. @@ -26,19 +28,19 @@ public final class SawShark extends Shark { private String sharktype = "saw"; /* - * The age property. + * The properties property. */ - private int age; + private FishProperties innerProperties = new FishProperties(); /* - * The dna property. + * The anotherProperties property. */ - private String dna; + private AnotherFishProperties innerAnotherProperties = new AnotherFishProperties(); /** * Creates an instance of SawShark class. */ - private SawShark() { + public SawShark() { } /** @@ -62,23 +64,103 @@ public String sharktype() { } /** - * Get the age property: The age property. + * Get the innerProperties property: The properties property. * - * @return the age value. + * @return the innerProperties value. */ - @Override - public int age() { - return this.age; + private FishProperties innerProperties() { + return this.innerProperties; } /** - * Get the dna property: The dna property. + * Get the innerAnotherProperties property: The anotherProperties property. * - * @return the dna value. + * @return the innerAnotherProperties value. + */ + private AnotherFishProperties innerAnotherProperties() { + return this.innerAnotherProperties; + } + + /** + * {@inheritDoc} */ @Override - public String dna() { - return this.dna; + public SawShark withAge(int age) { + super.withAge(age); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public SawShark withDna(String dna) { + super.withDna(dna); + return this; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerProperties() == null ? 0.0 : this.innerProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the SawShark object itself. + */ + public SawShark withLength(double length) { + if (this.innerProperties() == null) { + this.innerProperties = new FishProperties(); + } + this.innerProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerProperties() == null ? null : this.innerProperties().patten(); + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double lengthAnotherPropertiesLength() { + return this.innerAnotherProperties() == null ? 0.0 : this.innerAnotherProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the SawShark object itself. + */ + public SawShark withLengthAnotherPropertiesLength(double length) { + if (this.innerAnotherProperties() == null) { + this.innerAnotherProperties = new AnotherFishProperties(); + } + this.innerAnotherProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String pattenAnotherPropertiesPatten() { + return this.innerAnotherProperties() == null ? null : this.innerAnotherProperties().patten(); } /** @@ -100,6 +182,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); jsonWriter.writeStringField("dna", dna()); + jsonWriter.writeJsonField("properties", innerProperties()); + jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); return jsonWriter.writeEndObject(); } @@ -121,9 +205,13 @@ public static SawShark fromJson(JsonReader jsonReader) throws IOException { reader.nextToken(); if ("age".equals(fieldName)) { - deserializedSawShark.age = reader.getInt(); + deserializedSawShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedSawShark.dna = reader.getString(); + deserializedSawShark.withDna(reader.getString()); + } else if ("properties".equals(fieldName)) { + deserializedSawShark.innerProperties = FishProperties.fromJson(reader); + } else if ("anotherProperties".equals(fieldName)) { + deserializedSawShark.innerAnotherProperties = AnotherFishProperties.fromJson(reader); } else if ("sharktype".equals(fieldName)) { deserializedSawShark.sharktype = reader.getString(); } else { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java index a82e8c50c8..24a59bb21d 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java @@ -4,17 +4,19 @@ package com.cadl.armstreamstyleserialization.models; -import com.azure.core.annotation.Immutable; +import com.azure.core.annotation.Fluent; import com.azure.json.JsonReader; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; +import com.cadl.armstreamstyleserialization.fluent.models.AnotherFishProperties; import com.cadl.armstreamstyleserialization.fluent.models.FishInner; +import com.cadl.armstreamstyleserialization.fluent.models.FishProperties; import java.io.IOException; /** * The second level model in polymorphic multiple levels inheritance and it defines a new discriminator. */ -@Immutable +@Fluent public class Shark extends FishInner { /* * Discriminator property for Fish. @@ -27,19 +29,19 @@ public class Shark extends FishInner { private String sharktype = "shark"; /* - * The age property. + * The properties property. */ - private int age; + private FishProperties innerProperties = new FishProperties(); /* - * The dna property. + * The anotherProperties property. */ - private String dna; + private AnotherFishProperties innerAnotherProperties = new AnotherFishProperties(); /** * Creates an instance of Shark class. */ - protected Shark() { + public Shark() { } /** @@ -62,23 +64,103 @@ public String sharktype() { } /** - * Get the age property: The age property. + * Get the innerProperties property: The properties property. * - * @return the age value. + * @return the innerProperties value. */ - @Override - public int age() { - return this.age; + private FishProperties innerProperties() { + return this.innerProperties; } /** - * Get the dna property: The dna property. + * Get the innerAnotherProperties property: The anotherProperties property. * - * @return the dna value. + * @return the innerAnotherProperties value. + */ + private AnotherFishProperties innerAnotherProperties() { + return this.innerAnotherProperties; + } + + /** + * {@inheritDoc} */ @Override - public String dna() { - return this.dna; + public Shark withAge(int age) { + super.withAge(age); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Shark withDna(String dna) { + super.withDna(dna); + return this; + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double length() { + return this.innerProperties() == null ? 0.0 : this.innerProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the Shark object itself. + */ + public Shark withLength(double length) { + if (this.innerProperties() == null) { + this.innerProperties = new FishProperties(); + } + this.innerProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String patten() { + return this.innerProperties() == null ? null : this.innerProperties().patten(); + } + + /** + * Get the length property: The length property. + * + * @return the length value. + */ + public double lengthAnotherPropertiesLength() { + return this.innerAnotherProperties() == null ? 0.0 : this.innerAnotherProperties().length(); + } + + /** + * Set the length property: The length property. + * + * @param length the length value to set. + * @return the Shark object itself. + */ + public Shark withLengthAnotherPropertiesLength(double length) { + if (this.innerAnotherProperties() == null) { + this.innerAnotherProperties = new AnotherFishProperties(); + } + this.innerAnotherProperties().withLength(length); + return this; + } + + /** + * Get the patten property: The patten property. + * + * @return the patten value. + */ + public String pattenAnotherPropertiesPatten() { + return this.innerAnotherProperties() == null ? null : this.innerAnotherProperties().patten(); } /** @@ -100,6 +182,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); jsonWriter.writeStringField("dna", dna()); + jsonWriter.writeJsonField("properties", innerProperties()); + jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); return jsonWriter.writeEndObject(); } @@ -148,9 +232,13 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio reader.nextToken(); if ("age".equals(fieldName)) { - deserializedShark.age = reader.getInt(); + deserializedShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedShark.dna = reader.getString(); + deserializedShark.withDna(reader.getString()); + } else if ("properties".equals(fieldName)) { + deserializedShark.innerProperties = FishProperties.fromJson(reader); + } else if ("anotherProperties".equals(fieldName)) { + deserializedShark.innerAnotherProperties = AnotherFishProperties.fromJson(reader); } else if ("sharktype".equals(fieldName)) { deserializedShark.sharktype = reader.getString(); } else { From dcf64a8e2eed0be781a101fccab55c9551c2e803 Mon Sep 17 00:00:00 2001 From: xiaofeicao Date: Fri, 14 Jun 2024 16:33:03 +0800 Subject: [PATCH 5/9] format --- typespec-tests/tsp/arm-stream-style-serialization.tsp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/typespec-tests/tsp/arm-stream-style-serialization.tsp b/typespec-tests/tsp/arm-stream-style-serialization.tsp index 3ad3825324..78f41b7a03 100644 --- a/typespec-tests/tsp/arm-stream-style-serialization.tsp +++ b/typespec-tests/tsp/arm-stream-style-serialization.tsp @@ -62,6 +62,7 @@ model FishProperties { model TailProperties { length: float32; + @visibility("read") patten: string; } @@ -72,6 +73,7 @@ model AnotherFishProperties { model EyeProperties { length: float32; + @visibility("read") patten: string; } @@ -118,4 +120,4 @@ interface TopLevelArmResources { @@flattenProperty(Fish.properties); @@flattenProperty(FishProperties.tailProperties); @@flattenProperty(Fish.anotherProperties); -@@flattenProperty(AnotherFishProperties.eyeProperties); \ No newline at end of file +@@flattenProperty(AnotherFishProperties.eyeProperties); From a7d8e81b899615aa114d2f48c558a4a3675fa491 Mon Sep 17 00:00:00 2001 From: xiaofeicao Date: Fri, 14 Jun 2024 17:03:12 +0800 Subject: [PATCH 6/9] changelog --- typespec-extension/changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/typespec-extension/changelog.md b/typespec-extension/changelog.md index cb61b733d2..d79ee0136d 100644 --- a/typespec-extension/changelog.md +++ b/typespec-extension/changelog.md @@ -1,5 +1,12 @@ # Release History +## 0.17.1 (Unreleased) + +Compatible with compiler 0.57. + +- Bug fix for stream-style-serialization for ARM. +- Enabled stream-style-serialization by default for ARM. + ## 0.17.0 (2024-06-14) Compatible with compiler 0.57. From 0652c2ca0f36a7a6952efc22aca390f7ad761362 Mon Sep 17 00:00:00 2001 From: XiaofeiCao Date: Mon, 17 Jun 2024 15:58:36 +0800 Subject: [PATCH 7/9] address comments --- customization-base/README.md | 1440 ++++++++--------- .../fluent/template/ModelTemplateTests.java | 8 +- .../autorest/template/ModelTemplate.java | 33 +- .../StreamSerializationModelTemplate.java | 14 +- .../azure/autorest/util/ClientModelUtil.java | 25 +- .../tsp/arm-stream-style-serialization.tsp | 2 +- typespec-tests/tspconfig.yaml | 1 - 7 files changed, 756 insertions(+), 767 deletions(-) diff --git a/customization-base/README.md b/customization-base/README.md index b44cc8e503..747c906709 100644 --- a/customization-base/README.md +++ b/customization-base/README.md @@ -1,720 +1,720 @@ -# Overview - -The `azure-autorest-customization` package provides APIs for customizing Autorest code generation safely and -programmatically to support special cases not supported by Autorest code generation directly using Eclipse language -server to ensure valid Java code. - -To set up customizations, create a Maven project with dependency: - -```xml - - com.azure.tools - azure-autorest-customization - 1.0.0-beta.8 - -``` - -Create a customization class extending from `com.azure.autorest.customization.Customization` and override the -`void customize(LibraryCustomization, Logger)` method. You will have access to a `LibraryCustomization` class where you -will be able to customize the generated Java code before it's written to the disk. Currently, the following -customizations are supported: - -- [Change class modifier](#change-class-modifier) -- [Change method modifier](#change-method-modifier) -- [Change method return type](#change-method-return-type) -- [Add an annotation to a class](#add-an-annotation-to-a-class) -- [Add an annotation to a method](#add-an-annotation-to-a-method) -- [Remove an annotation from a class](#remove-an-annotation-from-a-class) -- [Refactor: Rename a class](#refactor-rename-a-class) -- [Refactor: Rename a method](#refactor-rename-a-method) -- [Refactor: Generate the getter and setter methods for a property](#refactor-generate-the-getter-and-setter-methods-for-a-property) -- [Refactor: Rename a property and its corresponding getter and setter methods](#refactor-rename-a-property-and-its-corresponding-getter-and-setter-methods) -- [Refactor: Rename an enum member name](#refactor-rename-an-enum-member-name) -- [Javadoc: Set the description for a class / method](#javadoc-set-the-description-for-a-class--method) -- [Javadoc: Set / remove a parameter's javadoc on a method](#javadoc-set--remove-a-parameters-javadoc-on-a-method) -- [Javadoc: Set the return javadoc on a method](#javadoc-set-the-return-javadoc-on-a-method) -- [Javadoc: Set / remove an exception's javadoc on a method ](#javadoc-add--remove-an-exceptions-javadoc-on-a-method) - -## Navigate through the packages and classes - -There are five primary customization classes currently available, `LibraryCustomization`, `PackageCustomization`, -`ClassCustomization`, `MethodCustomization` and `JavadocCustomization`. From a given `LibraryCustomization`, you can -navigate through the packages, classes, and methods intuitively with the following methods: - -```java readme-sample-implementation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - /* code to customize on the package level */ - ClassCustomization foo = models.getClass("Foo"); - /* code to customize the Foo class */ - MethodCustomization getBar = foo.getMethod("getBar"); - /* code to customize the getBar method */ - JavadocCustomization getBarJavadoc = getBar.getJavadoc(); - /* code to customize javadoc for getBar() method */ -} -``` - -## Change class modifier - -A class `Foo` - -```java readme-sample-change-class-modifier-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-change-class-modifier-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.setModifier(0); // 0 is a special modifier that sets package private -} -``` - -will generate - -```java readme-sample-change-class-modifier-result -class Foo { -} -``` - -## Change method modifier - -A method `getBar` in the `Foo` class - -```java readme-sample-change-method-modifier-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-change-method-modifier-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getBar = foo.getMethod("getBar"); - getBar.setModifier(Modifier.PRIVATE); // change to private -} -``` - -will generate - -```java readme-sample-change-method-modifier-result -public class Foo { - private Bar bar; - - private Bar getBar() { - return this.bar; - } -} -``` - -## Change method return type - -You can change a method's return type, and pass a String formatter to transform the original return value statement. -If the original return type is `void`, simply pass the full return value String expression in place of the String -formatter; if the new return type is `void`, simply pass `null`. - -A method `getId` in the `Foo` class - -```java readme-sample-change-method-return-type-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-change-method-return-type-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getId = foo.getMethod("getId"); - getId.setReturnType("UUID", "UUID.fromString(%s)"); // change return type to UUID -} -``` - -will generate - -```java readme-sample-change-method-return-type-result -public class Foo { - private String id; - - public UUID getId() { - String returnValue = this.id; - return UUID.fromString(returnValue); - } -} -``` - -The `UUID` class will be automatically imported. - -## Add an annotation to a class - -A class `Foo` - -```java readme-sample-add-class-annotation-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-add-class-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.addAnnotation("JsonClassDescription(\"Foo class\")"); -} -``` - -will generate - -```java readme-sample-add-class-annotation-result -@JsonClassDescription("Foo class") -public class Foo { -} -``` - -The `JsonClassDescription` class will be automatically imported. - -## Add an annotation to a method - -A method `getBar` in the `Foo` class - -```java readme-sample-add-method-annotation-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-add-method-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getBar = foo.getMethod("getBar"); - getBar.addAnnotation("Deprecated"); -} -``` - -will generate - -```java readme-sample-add-method-annotation-result -public class Foo { - private Bar bar; - - @Deprecated - public Bar getBar() { - return this.bar; - } -} -``` - -The `Deprecated` class will be automatically imported. - -## Remove an annotation from a class - -A class `Foo` - -```java readme-sample-remove-class-annotation-initial -@JsonClassDescription("Foo class") -public class Foo { -} -``` - -with customization - -```java readme-sample-remove-class-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.removeAnnotation("JsonClassDescription"); -} -``` - -will generate - -```java readme-sample-remove-class-annotation-result -public class Foo { -} -``` - -## Refactor: Rename a class - -A class `Foo` - -```java readme-sample-rename-class-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-rename-class-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.rename("FooInfo"); -} -``` - -will generate - -```java readme-sample-rename-class-result -public class FooInfo { -} -``` - -All references of `Foo` will be modified to `FooInfo`. When a valid value is provided, this customization is guaranteed -to not break the build. - -## Refactor: Rename a method - -A method `isSupportsUnicode` in the `Foo` class - -```java readme-sample-rename-method-initial -public class Foo { - private boolean supportsUnicode; - - public boolean isSupportsUnicode() { - return this.supportsUnicode; - } -} -``` - -with customization - -```java readme-sample-rename-method-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization isSupportsUnicode = foo.getMethod("isSupportsUnicode"); - isSupportsUnicode.rename("isUnicodeSupported"); -} -``` - -will generate - -```java readme-sample-rename-method-result -public class Foo { - private boolean supportsUnicode; - - public boolean isUnicodeSupported() { - return this.supportsUnicode; - } -} -``` - -All references of `isSupportsUnicode()` will be modified to `isUnicodeSupported()`. When a valid value is provided, this -customization is guaranteed to not break the build. - -## Refactor: Generate the getter and setter methods for a property - -A property `active` in the `Foo` class - -```java readme-sample-generate-getter-and-setter-initial -public class Foo { - private boolean active; -} -``` - -with customization - -```java readme-sample-generate-getter-and-setter-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - PropertyCustomization active = foo.getProperty("active"); - active.generateGetterAndSetter(); -} -``` - -will generate - -```java readme-sample-generate-getter-and-setter-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -If the class already contains a getter or a setter method, the current method will be kept. This customization is -guaranteed to not break the build. - -## Refactor: Rename a property and its corresponding getter and setter methods - -A property `whitelist` in the `Foo` class - -```java readme-sample-rename-property-initial -public class Foo { - private List whiteList; - - public List getWhiteList() { - return this.whiteList; - } - - public Foo setWhiteList(List whiteList) { - this.whiteList = whiteList; - return this; - } -} -``` - -with customization - -```java readme-sample-rename-property-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - PropertyCustomization active = foo.getProperty("active"); - active.rename("allowList"); -} -``` - -will generate - -```java readme-sample-rename-property-result -public class Foo { - private List allowList; - - public List getAllowList() { - return this.allowList; - } - - public Foo setAllowList(List allowList) { - this.allowList = allowList; - return this; - } -} -``` - -This customization is guaranteed to not break the build. - -## Refactor: Rename an enum member name - -An enum member `JPG` in an enum class `ImageFileType`: - -```java readme-sample-rename-enum-member-initial -public enum ImageFileType { - GIF("gif"), - JPG("jpg"), - TIFF("tiff"), - PNG("png"); - - private final String value; - - ImageFileType(String value) { - this.value = value; - } -} -``` - -with customization - -```java readme-sample-rename-enum-member-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.renameEnumMember("JPG", "JPEG"); -} -``` - -will generate - -```java readme-sample-rename-enum-member-result -public enum ImageFileType { - GIF("gif"), - JPEG("jpg"), - TIFF("tiff"), - PNG("png"); - - private final String value; - - ImageFileType(String value) { - this.value = value; - } -} -``` - -This customization is guaranteed to not break the build. - -## Javadoc: Set the description for a class / method - -A class `Foo` - -```java readme-sample-change-javadoc-description-initial -/** Class Foo. */ -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-description-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization fooJavadoc = foo.getJavadoc(); - fooJavadoc.setDescription("A Foo object stored in Azure."); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setDescription("Set the active value."); -} -``` - -will generate - -```java readme-sample-change-javadoc-description-result -/** - * A Foo object stored in Azure. - */ -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Set / remove a parameter's javadoc on a method - -A class `Foo` - -```java readme-sample-change-javadoc-param-initial -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-param-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setParam("active", "if the foo object is in active state"); -} -``` - -will generate - -```java readme-sample-change-javadoc-param-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Set the return javadoc on a method - -A `Foo` class - -```java readme-sample-change-javadoc-return-initial -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-return-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setReturn("the current foo object"); -} -``` - -will generate - -```java readme-sample-change-javadoc-return-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - * @return the current foo object - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Add / remove an exception's javadoc on a method - -A `FooClient` class - -```java readme-sample-change-javadoc-throws-initial -public class FooClient { - /** - * Create a Foo object. - * - * @param foo the foo object to create in Azure - * @return the response for creating the foo object - */ - public CreateFooResponse createFoo(Foo foo) { - /* REST call to create foo */ - return null; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-throws-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.addThrows("RuntimeException", "An unsuccessful response is received"); -} -``` - -will generate - -```java readme-sample-change-javadoc-throws-result -/** - * Create a Foo object. - * - * @param foo the foo object to create in Azure - * @return the response for creating the foo object - * @throws RuntimeException An unsuccessful response is received - */ -public CreateFooResponse createFoo(Foo foo) { - /* REST call to create foo */ - return null; -} -``` - -# Troubleshooting - -## AutoRest fails with "Unable to format output file" - -The cause is that the customized Java code has syntax error. - -Possible root cause: -* Bug in customization code. -* Bug in the `customization-base` package. - -Steps to diagnose and fix: -1. Add `skip-formatting` flag to skip Java code formatting, and hence not checking the syntax error. -2. Compile or inspect the generated code, find the error. -3. Determine the root cause. If it is caused by bug in customization code, fix it. If it is caused by bug in `customization-base` package, report it in GitHub issues. -4. Remove `skip-formatting` flag. - -# Developer note - -`azure-autorest-customization` passes all generated code files to an Eclipse language server process to enable richer, -IDE-like functionality. For this to work correctly all required dependencies must be passed to the language server using -a dummy `pom.xml`, which can be found in `src/main/resources`. If you make changes to code generation and begin seeing -code customizations failing it may be that the `pom.xml` is missing required dependencies and is causing the language -server to change processing from IDE-like to a regex, or find and replace, style. +# Overview + +The `azure-autorest-customization` package provides APIs for customizing Autorest code generation safely and +programmatically to support special cases not supported by Autorest code generation directly using Eclipse language +server to ensure valid Java code. + +To set up customizations, create a Maven project with dependency: + +```xml + + com.azure.tools + azure-autorest-customization + 1.0.0-beta.8 + +``` + +Create a customization class extending from `com.azure.autorest.customization.Customization` and override the +`void customize(LibraryCustomization, Logger)` method. You will have access to a `LibraryCustomization` class where you +will be able to customize the generated Java code before it's written to the disk. Currently, the following +customizations are supported: + +- [Change class modifier](#change-class-modifier) +- [Change method modifier](#change-method-modifier) +- [Change method return type](#change-method-return-type) +- [Add an annotation to a class](#add-an-annotation-to-a-class) +- [Add an annotation to a method](#add-an-annotation-to-a-method) +- [Remove an annotation from a class](#remove-an-annotation-from-a-class) +- [Refactor: Rename a class](#refactor-rename-a-class) +- [Refactor: Rename a method](#refactor-rename-a-method) +- [Refactor: Generate the getter and setter methods for a property](#refactor-generate-the-getter-and-setter-methods-for-a-property) +- [Refactor: Rename a property and its corresponding getter and setter methods](#refactor-rename-a-property-and-its-corresponding-getter-and-setter-methods) +- [Refactor: Rename an enum member name](#refactor-rename-an-enum-member-name) +- [Javadoc: Set the description for a class / method](#javadoc-set-the-description-for-a-class--method) +- [Javadoc: Set / remove a parameter's javadoc on a method](#javadoc-set--remove-a-parameters-javadoc-on-a-method) +- [Javadoc: Set the return javadoc on a method](#javadoc-set-the-return-javadoc-on-a-method) +- [Javadoc: Set / remove an exception's javadoc on a method ](#javadoc-add--remove-an-exceptions-javadoc-on-a-method) + +## Navigate through the packages and classes + +There are five primary customization classes currently available, `LibraryCustomization`, `PackageCustomization`, +`ClassCustomization`, `MethodCustomization` and `JavadocCustomization`. From a given `LibraryCustomization`, you can +navigate through the packages, classes, and methods intuitively with the following methods: + +```java readme-sample-implementation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + /* code to customize on the package level */ + ClassCustomization foo = models.getClass("Foo"); + /* code to customize the Foo class */ + MethodCustomization getBar = foo.getMethod("getBar"); + /* code to customize the getBar method */ + JavadocCustomization getBarJavadoc = getBar.getJavadoc(); + /* code to customize javadoc for getBar() method */ +} +``` + +## Change class modifier + +A class `Foo` + +```java readme-sample-change-class-modifier-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-change-class-modifier-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.setModifier(0); // 0 is a special modifier that sets package private +} +``` + +will generate + +```java readme-sample-change-class-modifier-result +class Foo { +} +``` + +## Change method modifier + +A method `getBar` in the `Foo` class + +```java readme-sample-change-method-modifier-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-change-method-modifier-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getBar = foo.getMethod("getBar"); + getBar.setModifier(Modifier.PRIVATE); // change to private +} +``` + +will generate + +```java readme-sample-change-method-modifier-result +public class Foo { + private Bar bar; + + private Bar getBar() { + return this.bar; + } +} +``` + +## Change method return type + +You can change a method's return type, and pass a String formatter to transform the original return value statement. +If the original return type is `void`, simply pass the full return value String expression in place of the String +formatter; if the new return type is `void`, simply pass `null`. + +A method `getId` in the `Foo` class + +```java readme-sample-change-method-return-type-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-change-method-return-type-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getId = foo.getMethod("getId"); + getId.setReturnType("UUID", "UUID.fromString(%s)"); // change return type to UUID +} +``` + +will generate + +```java readme-sample-change-method-return-type-result +public class Foo { + private String id; + + public UUID getId() { + String returnValue = this.id; + return UUID.fromString(returnValue); + } +} +``` + +The `UUID` class will be automatically imported. + +## Add an annotation to a class + +A class `Foo` + +```java readme-sample-add-class-annotation-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-add-class-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.addAnnotation("JsonClassDescription(\"Foo class\")"); +} +``` + +will generate + +```java readme-sample-add-class-annotation-result +@JsonClassDescription("Foo class") +public class Foo { +} +``` + +The `JsonClassDescription` class will be automatically imported. + +## Add an annotation to a method + +A method `getBar` in the `Foo` class + +```java readme-sample-add-method-annotation-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-add-method-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getBar = foo.getMethod("getBar"); + getBar.addAnnotation("Deprecated"); +} +``` + +will generate + +```java readme-sample-add-method-annotation-result +public class Foo { + private Bar bar; + + @Deprecated + public Bar getBar() { + return this.bar; + } +} +``` + +The `Deprecated` class will be automatically imported. + +## Remove an annotation from a class + +A class `Foo` + +```java readme-sample-remove-class-annotation-initial +@JsonClassDescription("Foo class") +public class Foo { +} +``` + +with customization + +```java readme-sample-remove-class-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.removeAnnotation("JsonClassDescription"); +} +``` + +will generate + +```java readme-sample-remove-class-annotation-result +public class Foo { +} +``` + +## Refactor: Rename a class + +A class `Foo` + +```java readme-sample-rename-class-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-rename-class-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.rename("FooInfo"); +} +``` + +will generate + +```java readme-sample-rename-class-result +public class FooInfo { +} +``` + +All references of `Foo` will be modified to `FooInfo`. When a valid value is provided, this customization is guaranteed +to not break the build. + +## Refactor: Rename a method + +A method `isSupportsUnicode` in the `Foo` class + +```java readme-sample-rename-method-initial +public class Foo { + private boolean supportsUnicode; + + public boolean isSupportsUnicode() { + return this.supportsUnicode; + } +} +``` + +with customization + +```java readme-sample-rename-method-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization isSupportsUnicode = foo.getMethod("isSupportsUnicode"); + isSupportsUnicode.rename("isUnicodeSupported"); +} +``` + +will generate + +```java readme-sample-rename-method-result +public class Foo { + private boolean supportsUnicode; + + public boolean isUnicodeSupported() { + return this.supportsUnicode; + } +} +``` + +All references of `isSupportsUnicode()` will be modified to `isUnicodeSupported()`. When a valid value is provided, this +customization is guaranteed to not break the build. + +## Refactor: Generate the getter and setter methods for a property + +A property `active` in the `Foo` class + +```java readme-sample-generate-getter-and-setter-initial +public class Foo { + private boolean active; +} +``` + +with customization + +```java readme-sample-generate-getter-and-setter-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + PropertyCustomization active = foo.getProperty("active"); + active.generateGetterAndSetter(); +} +``` + +will generate + +```java readme-sample-generate-getter-and-setter-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +If the class already contains a getter or a setter method, the current method will be kept. This customization is +guaranteed to not break the build. + +## Refactor: Rename a property and its corresponding getter and setter methods + +A property `whitelist` in the `Foo` class + +```java readme-sample-rename-property-initial +public class Foo { + private List whiteList; + + public List getWhiteList() { + return this.whiteList; + } + + public Foo setWhiteList(List whiteList) { + this.whiteList = whiteList; + return this; + } +} +``` + +with customization + +```java readme-sample-rename-property-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + PropertyCustomization active = foo.getProperty("active"); + active.rename("allowList"); +} +``` + +will generate + +```java readme-sample-rename-property-result +public class Foo { + private List allowList; + + public List getAllowList() { + return this.allowList; + } + + public Foo setAllowList(List allowList) { + this.allowList = allowList; + return this; + } +} +``` + +This customization is guaranteed to not break the build. + +## Refactor: Rename an enum member name + +An enum member `JPG` in an enum class `ImageFileType`: + +```java readme-sample-rename-enum-member-initial +public enum ImageFileType { + GIF("gif"), + JPG("jpg"), + TIFF("tiff"), + PNG("png"); + + private final String value; + + ImageFileType(String value) { + this.value = value; + } +} +``` + +with customization + +```java readme-sample-rename-enum-member-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.renameEnumMember("JPG", "JPEG"); +} +``` + +will generate + +```java readme-sample-rename-enum-member-result +public enum ImageFileType { + GIF("gif"), + JPEG("jpg"), + TIFF("tiff"), + PNG("png"); + + private final String value; + + ImageFileType(String value) { + this.value = value; + } +} +``` + +This customization is guaranteed to not break the build. + +## Javadoc: Set the description for a class / method + +A class `Foo` + +```java readme-sample-change-javadoc-description-initial +/** Class Foo. */ +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-description-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization fooJavadoc = foo.getJavadoc(); + fooJavadoc.setDescription("A Foo object stored in Azure."); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setDescription("Set the active value."); +} +``` + +will generate + +```java readme-sample-change-javadoc-description-result +/** + * A Foo object stored in Azure. + */ +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Set / remove a parameter's javadoc on a method + +A class `Foo` + +```java readme-sample-change-javadoc-param-initial +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-param-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setParam("active", "if the foo object is in active state"); +} +``` + +will generate + +```java readme-sample-change-javadoc-param-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Set the return javadoc on a method + +A `Foo` class + +```java readme-sample-change-javadoc-return-initial +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-return-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setReturn("the current foo object"); +} +``` + +will generate + +```java readme-sample-change-javadoc-return-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + * @return the current foo object + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Add / remove an exception's javadoc on a method + +A `FooClient` class + +```java readme-sample-change-javadoc-throws-initial +public class FooClient { + /** + * Create a Foo object. + * + * @param foo the foo object to create in Azure + * @return the response for creating the foo object + */ + public CreateFooResponse createFoo(Foo foo) { + /* REST call to create foo */ + return null; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-throws-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.addThrows("RuntimeException", "An unsuccessful response is received"); +} +``` + +will generate + +```java readme-sample-change-javadoc-throws-result +/** + * Create a Foo object. + * + * @param foo the foo object to create in Azure + * @return the response for creating the foo object + * @throws RuntimeException An unsuccessful response is received + */ +public CreateFooResponse createFoo(Foo foo) { + /* REST call to create foo */ + return null; +} +``` + +# Troubleshooting + +## AutoRest fails with "Unable to format output file" + +The cause is that the customized Java code has syntax error. + +Possible root cause: +* Bug in customization code. +* Bug in the `customization-base` package. + +Steps to diagnose and fix: +1. Add `skip-formatting` flag to skip Java code formatting, and hence not checking the syntax error. +2. Compile or inspect the generated code, find the error. +3. Determine the root cause. If it is caused by bug in customization code, fix it. If it is caused by bug in `customization-base` package, report it in GitHub issues. +4. Remove `skip-formatting` flag. + +# Developer note + +`azure-autorest-customization` passes all generated code files to an Eclipse language server process to enable richer, +IDE-like functionality. For this to work correctly all required dependencies must be passed to the language server using +a dummy `pom.xml`, which can be found in `src/main/resources`. If you make changes to code generation and begin seeing +code customizations failing it may be that the `pom.xml` is missing required dependencies and is causing the language +server to change processing from IDE-like to a regex, or find and replace, style. diff --git a/fluentgen/src/test/java/com/azure/autorest/fluent/template/ModelTemplateTests.java b/fluentgen/src/test/java/com/azure/autorest/fluent/template/ModelTemplateTests.java index d60fe4d69f..05dfa96461 100644 --- a/fluentgen/src/test/java/com/azure/autorest/fluent/template/ModelTemplateTests.java +++ b/fluentgen/src/test/java/com/azure/autorest/fluent/template/ModelTemplateTests.java @@ -34,7 +34,7 @@ public static void init(){ /** * Issue: https://github.com/Azure/autorest.java/issues/1320 * Remove duplicate setter methods from child schema when parent schema contains same property - * mainly to test {@link com.azure.autorest.template.ModelTemplate#getParentSettersToOverride(ClientModel, JavaSettings, List)} + * mainly to test {@link com.azure.autorest.template.ModelTemplate#getSuperSetters(ClientModel, JavaSettings, List)} */ @Test public void deduplicateTest(){ @@ -47,7 +47,7 @@ public void deduplicateTest(){ propertyReferences.addAll(model.getPropertyReferences()); } // real test here - List toOverride = templateAccessor.getParentSettersToOverride(model, settings, propertyReferences); + List toOverride = templateAccessor.getSuperSetters(model, settings, propertyReferences); Assertions.assertEquals(toOverride.size(), 1); } @@ -57,8 +57,8 @@ public List getClientModelPropertyReferences0(Clie return super.getClientModelPropertyReferences(model); } - public List getParentSettersToOverride(ClientModel model, JavaSettings settings, List propertyReferences) { - return super.getParentSettersToOverride(model, settings, propertyReferences); + public List getSuperSetters(ClientModel model, JavaSettings settings, List propertyReferences) { + return super.getSuperSetters(model, settings, propertyReferences); } } 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 8a0d1dab39..78713b88fe 100644 --- a/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/ModelTemplate.java @@ -176,7 +176,7 @@ public final void write(ClientModel model, JavaFile javaFile) { TemplateUtil.addJsonGetter(classBlock, settings, property.getSerializedName()); } - boolean overridesParentGetter = isOverrideParentGetter(model, property, settings); + boolean overridesParentGetter = overridesParentGetter(model, property, settings); if (overridesParentGetter) { classBlock.annotation("Override"); } @@ -185,7 +185,7 @@ public final void write(ClientModel model, JavaFile javaFile) { methodBlock -> addGetterMethod(propertyWireType, propertyClientType, property, treatAsXml, methodBlock, settings)); - if (ClientModelUtil.hasSetter(property, settings) && !immutableModel) { + if (ClientModelUtil.needsPublicSetter(property, settings) && !immutableModel) { generateSetterJavadoc(classBlock, model, property); addGeneratedAnnotation(classBlock); TemplateUtil.addJsonSetter(classBlock, settings, property.getSerializedName()); @@ -244,7 +244,7 @@ public final void write(ClientModel model, JavaFile javaFile) { // add setters to override parent setters if (!immutableModel) { - List settersToOverride = getParentSettersToOverride(model, settings, + List settersToOverride = getSuperSetters(model, settings, propertyReferences); for (ClientModelPropertyAccess parentProperty : settersToOverride) { classBlock.javadocComment(JavaJavadocComment::inheritDoc); @@ -345,7 +345,7 @@ protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference(C * @param settings {@link JavaSettings} instance * @return whether the property's getter overrides parent getter */ - protected boolean isOverrideParentGetter(ClientModel model, ClientModelProperty property, JavaSettings settings) { + protected boolean overridesParentGetter(ClientModel model, ClientModelProperty property, JavaSettings settings) { // getter method of discriminator property in subclass is handled differently return property.isPolymorphicDiscriminator() && !modelDefinesProperty(model, property); } @@ -428,30 +428,29 @@ protected void addSerializationImports(Set imports, ClientModel model, J } /** - * Override parent setters if: + * We generate super setters in child class if all of below conditions are met: * 1. parent property has setter - * 2. child does not contain property that shadow this parent property, otherwise overridden parent setter methods - * will collide with child setter methods - * 3. the propertyReference isn't flattening property or we don't generate local getter/setter + * 2. child does not contain property that shadow this parent property, otherwise super setters + * will collide with child setters * * @see Issue 1320 */ - protected List getParentSettersToOverride(ClientModel model, JavaSettings settings, - List propertyReferences) { + protected List getSuperSetters(ClientModel model, JavaSettings settings, + List propertyReferences) { Set modelPropertyNames = getFieldProperties(model, settings).stream().map(ClientModelProperty::getName) .collect(Collectors.toSet()); return propertyReferences.stream() - .filter(ClientModelPropertyReference::isFromParentModel) - .map(ClientModelPropertyReference::getReferenceProperty) - .filter(parentProperty -> { + .filter(ClientModelPropertyReference::isFromParentModel) + .map(ClientModelPropertyReference::getReferenceProperty) + .filter(parentProperty -> { // parent property doesn't have setter - if (!ClientModelUtil.hasSetter(parentProperty, settings)) { + if (!ClientModelUtil.needsPublicSetter(parentProperty, settings)) { return false; } // child does not contain property that shadow this parent property return !modelPropertyNames.contains(parentProperty.getName()); - }) - .collect(Collectors.toList()); + } + ).collect(Collectors.toList()); } /** @@ -532,7 +531,7 @@ private void addFluentOrImmutableAnnotation(ClientModel model, boolean immutable List propertyReferences, JavaFile javaFile, JavaSettings settings) { boolean fluent = !immutableOutputModel && Stream .concat(model.getProperties().stream(), propertyReferences.stream()) - .anyMatch(p -> ClientModelUtil.hasSetter(p, settings)); + .anyMatch(p -> ClientModelUtil.needsPublicSetter(p, settings)); if (JavaSettings.getInstance().isBranded()) { if (fluent) { 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 631cc7d663..6cfdf82aa9 100644 --- a/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java +++ b/javagen/src/main/java/com/azure/autorest/template/StreamSerializationModelTemplate.java @@ -263,7 +263,7 @@ && readOnlyNotInCtor(model, parentProperty, settings) // we shadow parent read-o * @return whether the property's getter overrides parent getter */ @Override - protected boolean isOverrideParentGetter(ClientModel model, ClientModelProperty property, JavaSettings settings) { + protected boolean overridesParentGetter(ClientModel model, ClientModelProperty property, JavaSettings settings) { return !modelDefinesProperty(model, property) && (property.isPolymorphicDiscriminator() || readOnlyNotInCtor(model, property, settings)); } @@ -311,14 +311,14 @@ protected ClientModelPropertyReference getLocalFlattenedModelPropertyReference(C } @Override - protected List getParentSettersToOverride(ClientModel model, JavaSettings settings, List propertyReferences) { - return super.getParentSettersToOverride(model, settings, propertyReferences) + protected List getSuperSetters(ClientModel model, JavaSettings settings, List propertyReferences) { + return super.getSuperSetters(model, settings, propertyReferences) .stream() - // If the propertyReference is flattening property, and we generate local getter/setter - // for it, then we don't need to override its parent setter. + // 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) - || getLocalFlattenedModelPropertyReference((ClientModelPropertyReference) propertyReference) == null) + !((propertyReference instanceof ClientModelPropertyReference) + && ((ClientModelPropertyReference) propertyReference).isFromFlattenedProperty())) .collect(Collectors.toList()); } diff --git a/javagen/src/main/java/com/azure/autorest/util/ClientModelUtil.java b/javagen/src/main/java/com/azure/autorest/util/ClientModelUtil.java index d786dfe4cc..055d35abbb 100644 --- a/javagen/src/main/java/com/azure/autorest/util/ClientModelUtil.java +++ b/javagen/src/main/java/com/azure/autorest/util/ClientModelUtil.java @@ -550,33 +550,24 @@ public static List getParentConstructorProperties(ClientMod } /** - * Indicates whether the property will have a setter method generated for it. + * Whether the property needs public setter. * * @param property The client model property, or a reference. * @param settings Autorest generation settings. - * @return Whether the property will have a setter method. + * @return whether the property will have a setter method. */ - public static boolean hasSetter(ClientModelPropertyAccess property, JavaSettings settings) { - // If the property isn't read-only or required and part of the constructor, and it isn't private, - // add a setter. - return !isReadOnlyOrInConstructor(property, settings) && !isPrivateAccess(property); - } - - // A property has private access when it is to be flattened. - // Only applies to mgmt, no effect on vanilla or DPG. - private static boolean isPrivateAccess(ClientModelPropertyAccess property) { - boolean privateAccess = false; - // ClientModelPropertyReference never refers to a private access property, so only check ClientModelProperty here. - if (property instanceof ClientModelProperty) { - privateAccess = ((ClientModelProperty) property).getClientFlatten(); - } - return privateAccess; + public static boolean needsPublicSetter(ClientModelPropertyAccess property, JavaSettings settings) { + return !isReadOnlyOrInConstructor(property, settings) && !isFlattenedProperty(property); } private static boolean isReadOnlyOrInConstructor(ClientModelPropertyAccess property, JavaSettings settings) { return property.isReadOnly() || (settings.isRequiredFieldsAsConstructorArgs() && property.isRequired()); } + private static boolean isFlattenedProperty(ClientModelPropertyAccess property) { + return (property instanceof ClientModelProperty) && ((ClientModelProperty) property).getClientFlatten(); + } + /** * Determines whether the {@link ClientModelProperty} should be included in the model's constructor. *

diff --git a/typespec-tests/tsp/arm-stream-style-serialization.tsp b/typespec-tests/tsp/arm-stream-style-serialization.tsp index 78f41b7a03..029039ea26 100644 --- a/typespec-tests/tsp/arm-stream-style-serialization.tsp +++ b/typespec-tests/tsp/arm-stream-style-serialization.tsp @@ -34,7 +34,7 @@ enum Versions { model Fish { age: int32; - @visibility("create", "read") + @visibility("read") dna: string; properties: FishProperties; diff --git a/typespec-tests/tspconfig.yaml b/typespec-tests/tspconfig.yaml index 105c9595c9..f38c42a954 100644 --- a/typespec-tests/tspconfig.yaml +++ b/typespec-tests/tspconfig.yaml @@ -8,7 +8,6 @@ options: generate-tests: true examples-directory: "{project-root}/tsp/examples" flavor: "Azure" - stream-style-serialization: true dev-options: generate-code-model: true loglevel: info From dfaef35b45daf13af4e4166d74a82ccebe797318 Mon Sep 17 00:00:00 2001 From: XiaofeiCao Date: Mon, 17 Jun 2024 16:44:49 +0800 Subject: [PATCH 8/9] revert unnecessary change --- customization-base/README.md | 1440 +++++++++++++++++----------------- 1 file changed, 720 insertions(+), 720 deletions(-) diff --git a/customization-base/README.md b/customization-base/README.md index 747c906709..b44cc8e503 100644 --- a/customization-base/README.md +++ b/customization-base/README.md @@ -1,720 +1,720 @@ -# Overview - -The `azure-autorest-customization` package provides APIs for customizing Autorest code generation safely and -programmatically to support special cases not supported by Autorest code generation directly using Eclipse language -server to ensure valid Java code. - -To set up customizations, create a Maven project with dependency: - -```xml - - com.azure.tools - azure-autorest-customization - 1.0.0-beta.8 - -``` - -Create a customization class extending from `com.azure.autorest.customization.Customization` and override the -`void customize(LibraryCustomization, Logger)` method. You will have access to a `LibraryCustomization` class where you -will be able to customize the generated Java code before it's written to the disk. Currently, the following -customizations are supported: - -- [Change class modifier](#change-class-modifier) -- [Change method modifier](#change-method-modifier) -- [Change method return type](#change-method-return-type) -- [Add an annotation to a class](#add-an-annotation-to-a-class) -- [Add an annotation to a method](#add-an-annotation-to-a-method) -- [Remove an annotation from a class](#remove-an-annotation-from-a-class) -- [Refactor: Rename a class](#refactor-rename-a-class) -- [Refactor: Rename a method](#refactor-rename-a-method) -- [Refactor: Generate the getter and setter methods for a property](#refactor-generate-the-getter-and-setter-methods-for-a-property) -- [Refactor: Rename a property and its corresponding getter and setter methods](#refactor-rename-a-property-and-its-corresponding-getter-and-setter-methods) -- [Refactor: Rename an enum member name](#refactor-rename-an-enum-member-name) -- [Javadoc: Set the description for a class / method](#javadoc-set-the-description-for-a-class--method) -- [Javadoc: Set / remove a parameter's javadoc on a method](#javadoc-set--remove-a-parameters-javadoc-on-a-method) -- [Javadoc: Set the return javadoc on a method](#javadoc-set-the-return-javadoc-on-a-method) -- [Javadoc: Set / remove an exception's javadoc on a method ](#javadoc-add--remove-an-exceptions-javadoc-on-a-method) - -## Navigate through the packages and classes - -There are five primary customization classes currently available, `LibraryCustomization`, `PackageCustomization`, -`ClassCustomization`, `MethodCustomization` and `JavadocCustomization`. From a given `LibraryCustomization`, you can -navigate through the packages, classes, and methods intuitively with the following methods: - -```java readme-sample-implementation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - /* code to customize on the package level */ - ClassCustomization foo = models.getClass("Foo"); - /* code to customize the Foo class */ - MethodCustomization getBar = foo.getMethod("getBar"); - /* code to customize the getBar method */ - JavadocCustomization getBarJavadoc = getBar.getJavadoc(); - /* code to customize javadoc for getBar() method */ -} -``` - -## Change class modifier - -A class `Foo` - -```java readme-sample-change-class-modifier-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-change-class-modifier-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.setModifier(0); // 0 is a special modifier that sets package private -} -``` - -will generate - -```java readme-sample-change-class-modifier-result -class Foo { -} -``` - -## Change method modifier - -A method `getBar` in the `Foo` class - -```java readme-sample-change-method-modifier-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-change-method-modifier-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getBar = foo.getMethod("getBar"); - getBar.setModifier(Modifier.PRIVATE); // change to private -} -``` - -will generate - -```java readme-sample-change-method-modifier-result -public class Foo { - private Bar bar; - - private Bar getBar() { - return this.bar; - } -} -``` - -## Change method return type - -You can change a method's return type, and pass a String formatter to transform the original return value statement. -If the original return type is `void`, simply pass the full return value String expression in place of the String -formatter; if the new return type is `void`, simply pass `null`. - -A method `getId` in the `Foo` class - -```java readme-sample-change-method-return-type-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-change-method-return-type-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getId = foo.getMethod("getId"); - getId.setReturnType("UUID", "UUID.fromString(%s)"); // change return type to UUID -} -``` - -will generate - -```java readme-sample-change-method-return-type-result -public class Foo { - private String id; - - public UUID getId() { - String returnValue = this.id; - return UUID.fromString(returnValue); - } -} -``` - -The `UUID` class will be automatically imported. - -## Add an annotation to a class - -A class `Foo` - -```java readme-sample-add-class-annotation-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-add-class-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.addAnnotation("JsonClassDescription(\"Foo class\")"); -} -``` - -will generate - -```java readme-sample-add-class-annotation-result -@JsonClassDescription("Foo class") -public class Foo { -} -``` - -The `JsonClassDescription` class will be automatically imported. - -## Add an annotation to a method - -A method `getBar` in the `Foo` class - -```java readme-sample-add-method-annotation-initial -public class Foo { - private Bar bar; - - public Bar getBar() { - return this.bar; - } -} -``` - -with customization - -```java readme-sample-add-method-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization getBar = foo.getMethod("getBar"); - getBar.addAnnotation("Deprecated"); -} -``` - -will generate - -```java readme-sample-add-method-annotation-result -public class Foo { - private Bar bar; - - @Deprecated - public Bar getBar() { - return this.bar; - } -} -``` - -The `Deprecated` class will be automatically imported. - -## Remove an annotation from a class - -A class `Foo` - -```java readme-sample-remove-class-annotation-initial -@JsonClassDescription("Foo class") -public class Foo { -} -``` - -with customization - -```java readme-sample-remove-class-annotation-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.removeAnnotation("JsonClassDescription"); -} -``` - -will generate - -```java readme-sample-remove-class-annotation-result -public class Foo { -} -``` - -## Refactor: Rename a class - -A class `Foo` - -```java readme-sample-rename-class-initial -public class Foo { -} -``` - -with customization - -```java readme-sample-rename-class-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.rename("FooInfo"); -} -``` - -will generate - -```java readme-sample-rename-class-result -public class FooInfo { -} -``` - -All references of `Foo` will be modified to `FooInfo`. When a valid value is provided, this customization is guaranteed -to not break the build. - -## Refactor: Rename a method - -A method `isSupportsUnicode` in the `Foo` class - -```java readme-sample-rename-method-initial -public class Foo { - private boolean supportsUnicode; - - public boolean isSupportsUnicode() { - return this.supportsUnicode; - } -} -``` - -with customization - -```java readme-sample-rename-method-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - MethodCustomization isSupportsUnicode = foo.getMethod("isSupportsUnicode"); - isSupportsUnicode.rename("isUnicodeSupported"); -} -``` - -will generate - -```java readme-sample-rename-method-result -public class Foo { - private boolean supportsUnicode; - - public boolean isUnicodeSupported() { - return this.supportsUnicode; - } -} -``` - -All references of `isSupportsUnicode()` will be modified to `isUnicodeSupported()`. When a valid value is provided, this -customization is guaranteed to not break the build. - -## Refactor: Generate the getter and setter methods for a property - -A property `active` in the `Foo` class - -```java readme-sample-generate-getter-and-setter-initial -public class Foo { - private boolean active; -} -``` - -with customization - -```java readme-sample-generate-getter-and-setter-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - PropertyCustomization active = foo.getProperty("active"); - active.generateGetterAndSetter(); -} -``` - -will generate - -```java readme-sample-generate-getter-and-setter-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -If the class already contains a getter or a setter method, the current method will be kept. This customization is -guaranteed to not break the build. - -## Refactor: Rename a property and its corresponding getter and setter methods - -A property `whitelist` in the `Foo` class - -```java readme-sample-rename-property-initial -public class Foo { - private List whiteList; - - public List getWhiteList() { - return this.whiteList; - } - - public Foo setWhiteList(List whiteList) { - this.whiteList = whiteList; - return this; - } -} -``` - -with customization - -```java readme-sample-rename-property-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - PropertyCustomization active = foo.getProperty("active"); - active.rename("allowList"); -} -``` - -will generate - -```java readme-sample-rename-property-result -public class Foo { - private List allowList; - - public List getAllowList() { - return this.allowList; - } - - public Foo setAllowList(List allowList) { - this.allowList = allowList; - return this; - } -} -``` - -This customization is guaranteed to not break the build. - -## Refactor: Rename an enum member name - -An enum member `JPG` in an enum class `ImageFileType`: - -```java readme-sample-rename-enum-member-initial -public enum ImageFileType { - GIF("gif"), - JPG("jpg"), - TIFF("tiff"), - PNG("png"); - - private final String value; - - ImageFileType(String value) { - this.value = value; - } -} -``` - -with customization - -```java readme-sample-rename-enum-member-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - foo.renameEnumMember("JPG", "JPEG"); -} -``` - -will generate - -```java readme-sample-rename-enum-member-result -public enum ImageFileType { - GIF("gif"), - JPEG("jpg"), - TIFF("tiff"), - PNG("png"); - - private final String value; - - ImageFileType(String value) { - this.value = value; - } -} -``` - -This customization is guaranteed to not break the build. - -## Javadoc: Set the description for a class / method - -A class `Foo` - -```java readme-sample-change-javadoc-description-initial -/** Class Foo. */ -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-description-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization fooJavadoc = foo.getJavadoc(); - fooJavadoc.setDescription("A Foo object stored in Azure."); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setDescription("Set the active value."); -} -``` - -will generate - -```java readme-sample-change-javadoc-description-result -/** - * A Foo object stored in Azure. - */ -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Set / remove a parameter's javadoc on a method - -A class `Foo` - -```java readme-sample-change-javadoc-param-initial -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-param-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setParam("active", "if the foo object is in active state"); -} -``` - -will generate - -```java readme-sample-change-javadoc-param-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Set the return javadoc on a method - -A `Foo` class - -```java readme-sample-change-javadoc-return-initial -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-return-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.setReturn("the current foo object"); -} -``` - -will generate - -```java readme-sample-change-javadoc-return-result -public class Foo { - private boolean active; - - public boolean isActive() { - return this.active; - } - - /** - * Set the active value. - * - * @param active if the foo object is in active state - * @return the current foo object - */ - public Foo setActive(boolean active) { - this.active = active; - return this; - } -} -``` - -## Javadoc: Add / remove an exception's javadoc on a method - -A `FooClient` class - -```java readme-sample-change-javadoc-throws-initial -public class FooClient { - /** - * Create a Foo object. - * - * @param foo the foo object to create in Azure - * @return the response for creating the foo object - */ - public CreateFooResponse createFoo(Foo foo) { - /* REST call to create foo */ - return null; - } -} -``` - -with customization - -```java readme-sample-change-javadoc-throws-customization -@Override -public void customize(LibraryCustomization customization, Logger logger) { - PackageCustomization models = customization.getPackage("com.azure.myservice.models"); - ClassCustomization foo = models.getClass("Foo"); - JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); - setActiveJavadoc.addThrows("RuntimeException", "An unsuccessful response is received"); -} -``` - -will generate - -```java readme-sample-change-javadoc-throws-result -/** - * Create a Foo object. - * - * @param foo the foo object to create in Azure - * @return the response for creating the foo object - * @throws RuntimeException An unsuccessful response is received - */ -public CreateFooResponse createFoo(Foo foo) { - /* REST call to create foo */ - return null; -} -``` - -# Troubleshooting - -## AutoRest fails with "Unable to format output file" - -The cause is that the customized Java code has syntax error. - -Possible root cause: -* Bug in customization code. -* Bug in the `customization-base` package. - -Steps to diagnose and fix: -1. Add `skip-formatting` flag to skip Java code formatting, and hence not checking the syntax error. -2. Compile or inspect the generated code, find the error. -3. Determine the root cause. If it is caused by bug in customization code, fix it. If it is caused by bug in `customization-base` package, report it in GitHub issues. -4. Remove `skip-formatting` flag. - -# Developer note - -`azure-autorest-customization` passes all generated code files to an Eclipse language server process to enable richer, -IDE-like functionality. For this to work correctly all required dependencies must be passed to the language server using -a dummy `pom.xml`, which can be found in `src/main/resources`. If you make changes to code generation and begin seeing -code customizations failing it may be that the `pom.xml` is missing required dependencies and is causing the language -server to change processing from IDE-like to a regex, or find and replace, style. +# Overview + +The `azure-autorest-customization` package provides APIs for customizing Autorest code generation safely and +programmatically to support special cases not supported by Autorest code generation directly using Eclipse language +server to ensure valid Java code. + +To set up customizations, create a Maven project with dependency: + +```xml + + com.azure.tools + azure-autorest-customization + 1.0.0-beta.8 + +``` + +Create a customization class extending from `com.azure.autorest.customization.Customization` and override the +`void customize(LibraryCustomization, Logger)` method. You will have access to a `LibraryCustomization` class where you +will be able to customize the generated Java code before it's written to the disk. Currently, the following +customizations are supported: + +- [Change class modifier](#change-class-modifier) +- [Change method modifier](#change-method-modifier) +- [Change method return type](#change-method-return-type) +- [Add an annotation to a class](#add-an-annotation-to-a-class) +- [Add an annotation to a method](#add-an-annotation-to-a-method) +- [Remove an annotation from a class](#remove-an-annotation-from-a-class) +- [Refactor: Rename a class](#refactor-rename-a-class) +- [Refactor: Rename a method](#refactor-rename-a-method) +- [Refactor: Generate the getter and setter methods for a property](#refactor-generate-the-getter-and-setter-methods-for-a-property) +- [Refactor: Rename a property and its corresponding getter and setter methods](#refactor-rename-a-property-and-its-corresponding-getter-and-setter-methods) +- [Refactor: Rename an enum member name](#refactor-rename-an-enum-member-name) +- [Javadoc: Set the description for a class / method](#javadoc-set-the-description-for-a-class--method) +- [Javadoc: Set / remove a parameter's javadoc on a method](#javadoc-set--remove-a-parameters-javadoc-on-a-method) +- [Javadoc: Set the return javadoc on a method](#javadoc-set-the-return-javadoc-on-a-method) +- [Javadoc: Set / remove an exception's javadoc on a method ](#javadoc-add--remove-an-exceptions-javadoc-on-a-method) + +## Navigate through the packages and classes + +There are five primary customization classes currently available, `LibraryCustomization`, `PackageCustomization`, +`ClassCustomization`, `MethodCustomization` and `JavadocCustomization`. From a given `LibraryCustomization`, you can +navigate through the packages, classes, and methods intuitively with the following methods: + +```java readme-sample-implementation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + /* code to customize on the package level */ + ClassCustomization foo = models.getClass("Foo"); + /* code to customize the Foo class */ + MethodCustomization getBar = foo.getMethod("getBar"); + /* code to customize the getBar method */ + JavadocCustomization getBarJavadoc = getBar.getJavadoc(); + /* code to customize javadoc for getBar() method */ +} +``` + +## Change class modifier + +A class `Foo` + +```java readme-sample-change-class-modifier-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-change-class-modifier-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.setModifier(0); // 0 is a special modifier that sets package private +} +``` + +will generate + +```java readme-sample-change-class-modifier-result +class Foo { +} +``` + +## Change method modifier + +A method `getBar` in the `Foo` class + +```java readme-sample-change-method-modifier-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-change-method-modifier-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getBar = foo.getMethod("getBar"); + getBar.setModifier(Modifier.PRIVATE); // change to private +} +``` + +will generate + +```java readme-sample-change-method-modifier-result +public class Foo { + private Bar bar; + + private Bar getBar() { + return this.bar; + } +} +``` + +## Change method return type + +You can change a method's return type, and pass a String formatter to transform the original return value statement. +If the original return type is `void`, simply pass the full return value String expression in place of the String +formatter; if the new return type is `void`, simply pass `null`. + +A method `getId` in the `Foo` class + +```java readme-sample-change-method-return-type-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-change-method-return-type-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getId = foo.getMethod("getId"); + getId.setReturnType("UUID", "UUID.fromString(%s)"); // change return type to UUID +} +``` + +will generate + +```java readme-sample-change-method-return-type-result +public class Foo { + private String id; + + public UUID getId() { + String returnValue = this.id; + return UUID.fromString(returnValue); + } +} +``` + +The `UUID` class will be automatically imported. + +## Add an annotation to a class + +A class `Foo` + +```java readme-sample-add-class-annotation-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-add-class-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.addAnnotation("JsonClassDescription(\"Foo class\")"); +} +``` + +will generate + +```java readme-sample-add-class-annotation-result +@JsonClassDescription("Foo class") +public class Foo { +} +``` + +The `JsonClassDescription` class will be automatically imported. + +## Add an annotation to a method + +A method `getBar` in the `Foo` class + +```java readme-sample-add-method-annotation-initial +public class Foo { + private Bar bar; + + public Bar getBar() { + return this.bar; + } +} +``` + +with customization + +```java readme-sample-add-method-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization getBar = foo.getMethod("getBar"); + getBar.addAnnotation("Deprecated"); +} +``` + +will generate + +```java readme-sample-add-method-annotation-result +public class Foo { + private Bar bar; + + @Deprecated + public Bar getBar() { + return this.bar; + } +} +``` + +The `Deprecated` class will be automatically imported. + +## Remove an annotation from a class + +A class `Foo` + +```java readme-sample-remove-class-annotation-initial +@JsonClassDescription("Foo class") +public class Foo { +} +``` + +with customization + +```java readme-sample-remove-class-annotation-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.removeAnnotation("JsonClassDescription"); +} +``` + +will generate + +```java readme-sample-remove-class-annotation-result +public class Foo { +} +``` + +## Refactor: Rename a class + +A class `Foo` + +```java readme-sample-rename-class-initial +public class Foo { +} +``` + +with customization + +```java readme-sample-rename-class-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.rename("FooInfo"); +} +``` + +will generate + +```java readme-sample-rename-class-result +public class FooInfo { +} +``` + +All references of `Foo` will be modified to `FooInfo`. When a valid value is provided, this customization is guaranteed +to not break the build. + +## Refactor: Rename a method + +A method `isSupportsUnicode` in the `Foo` class + +```java readme-sample-rename-method-initial +public class Foo { + private boolean supportsUnicode; + + public boolean isSupportsUnicode() { + return this.supportsUnicode; + } +} +``` + +with customization + +```java readme-sample-rename-method-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + MethodCustomization isSupportsUnicode = foo.getMethod("isSupportsUnicode"); + isSupportsUnicode.rename("isUnicodeSupported"); +} +``` + +will generate + +```java readme-sample-rename-method-result +public class Foo { + private boolean supportsUnicode; + + public boolean isUnicodeSupported() { + return this.supportsUnicode; + } +} +``` + +All references of `isSupportsUnicode()` will be modified to `isUnicodeSupported()`. When a valid value is provided, this +customization is guaranteed to not break the build. + +## Refactor: Generate the getter and setter methods for a property + +A property `active` in the `Foo` class + +```java readme-sample-generate-getter-and-setter-initial +public class Foo { + private boolean active; +} +``` + +with customization + +```java readme-sample-generate-getter-and-setter-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + PropertyCustomization active = foo.getProperty("active"); + active.generateGetterAndSetter(); +} +``` + +will generate + +```java readme-sample-generate-getter-and-setter-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +If the class already contains a getter or a setter method, the current method will be kept. This customization is +guaranteed to not break the build. + +## Refactor: Rename a property and its corresponding getter and setter methods + +A property `whitelist` in the `Foo` class + +```java readme-sample-rename-property-initial +public class Foo { + private List whiteList; + + public List getWhiteList() { + return this.whiteList; + } + + public Foo setWhiteList(List whiteList) { + this.whiteList = whiteList; + return this; + } +} +``` + +with customization + +```java readme-sample-rename-property-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + PropertyCustomization active = foo.getProperty("active"); + active.rename("allowList"); +} +``` + +will generate + +```java readme-sample-rename-property-result +public class Foo { + private List allowList; + + public List getAllowList() { + return this.allowList; + } + + public Foo setAllowList(List allowList) { + this.allowList = allowList; + return this; + } +} +``` + +This customization is guaranteed to not break the build. + +## Refactor: Rename an enum member name + +An enum member `JPG` in an enum class `ImageFileType`: + +```java readme-sample-rename-enum-member-initial +public enum ImageFileType { + GIF("gif"), + JPG("jpg"), + TIFF("tiff"), + PNG("png"); + + private final String value; + + ImageFileType(String value) { + this.value = value; + } +} +``` + +with customization + +```java readme-sample-rename-enum-member-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + foo.renameEnumMember("JPG", "JPEG"); +} +``` + +will generate + +```java readme-sample-rename-enum-member-result +public enum ImageFileType { + GIF("gif"), + JPEG("jpg"), + TIFF("tiff"), + PNG("png"); + + private final String value; + + ImageFileType(String value) { + this.value = value; + } +} +``` + +This customization is guaranteed to not break the build. + +## Javadoc: Set the description for a class / method + +A class `Foo` + +```java readme-sample-change-javadoc-description-initial +/** Class Foo. */ +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-description-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization fooJavadoc = foo.getJavadoc(); + fooJavadoc.setDescription("A Foo object stored in Azure."); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setDescription("Set the active value."); +} +``` + +will generate + +```java readme-sample-change-javadoc-description-result +/** + * A Foo object stored in Azure. + */ +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Set / remove a parameter's javadoc on a method + +A class `Foo` + +```java readme-sample-change-javadoc-param-initial +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-param-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setParam("active", "if the foo object is in active state"); +} +``` + +will generate + +```java readme-sample-change-javadoc-param-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Set the return javadoc on a method + +A `Foo` class + +```java readme-sample-change-javadoc-return-initial +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-return-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.setReturn("the current foo object"); +} +``` + +will generate + +```java readme-sample-change-javadoc-return-result +public class Foo { + private boolean active; + + public boolean isActive() { + return this.active; + } + + /** + * Set the active value. + * + * @param active if the foo object is in active state + * @return the current foo object + */ + public Foo setActive(boolean active) { + this.active = active; + return this; + } +} +``` + +## Javadoc: Add / remove an exception's javadoc on a method + +A `FooClient` class + +```java readme-sample-change-javadoc-throws-initial +public class FooClient { + /** + * Create a Foo object. + * + * @param foo the foo object to create in Azure + * @return the response for creating the foo object + */ + public CreateFooResponse createFoo(Foo foo) { + /* REST call to create foo */ + return null; + } +} +``` + +with customization + +```java readme-sample-change-javadoc-throws-customization +@Override +public void customize(LibraryCustomization customization, Logger logger) { + PackageCustomization models = customization.getPackage("com.azure.myservice.models"); + ClassCustomization foo = models.getClass("Foo"); + JavadocCustomization setActiveJavadoc = foo.getMethod("setActive").getJavadoc(); + setActiveJavadoc.addThrows("RuntimeException", "An unsuccessful response is received"); +} +``` + +will generate + +```java readme-sample-change-javadoc-throws-result +/** + * Create a Foo object. + * + * @param foo the foo object to create in Azure + * @return the response for creating the foo object + * @throws RuntimeException An unsuccessful response is received + */ +public CreateFooResponse createFoo(Foo foo) { + /* REST call to create foo */ + return null; +} +``` + +# Troubleshooting + +## AutoRest fails with "Unable to format output file" + +The cause is that the customized Java code has syntax error. + +Possible root cause: +* Bug in customization code. +* Bug in the `customization-base` package. + +Steps to diagnose and fix: +1. Add `skip-formatting` flag to skip Java code formatting, and hence not checking the syntax error. +2. Compile or inspect the generated code, find the error. +3. Determine the root cause. If it is caused by bug in customization code, fix it. If it is caused by bug in `customization-base` package, report it in GitHub issues. +4. Remove `skip-formatting` flag. + +# Developer note + +`azure-autorest-customization` passes all generated code files to an Eclipse language server process to enable richer, +IDE-like functionality. For this to work correctly all required dependencies must be passed to the language server using +a dummy `pom.xml`, which can be found in `src/main/resources`. If you make changes to code generation and begin seeing +code customizations failing it may be that the `pom.xml` is missing required dependencies and is causing the language +server to change processing from IDE-like to a regex, or find and replace, style. From e106dbc9c65ff4e83cae7d20cd905daba9fe04cd Mon Sep 17 00:00:00 2001 From: actions-user Date: Mon, 17 Jun 2024 09:30:05 +0000 Subject: [PATCH 9/9] re-generate test code --- .../fluent/models/FishInner.java | 7 +---- .../fluent/models/SalmonInner.java | 27 +++++++++++-------- .../models/GoblinShark.java | 27 +++++++++++-------- .../models/SawShark.java | 27 +++++++++++-------- .../models/Shark.java | 27 +++++++++++-------- 5 files changed, 65 insertions(+), 50 deletions(-) diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java index 3f0137b403..3c374d7d34 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/FishInner.java @@ -93,7 +93,7 @@ public String dna() { * @param dna the dna value to set. * @return the FishInner object itself. */ - public FishInner withDna(String dna) { + FishInner withDna(String dna) { this.dna = dna; return this; } @@ -208,10 +208,6 @@ public String pattenAnotherPropertiesPatten() { * @throws IllegalArgumentException thrown if the instance is not valid. */ public void validate() { - if (dna() == null) { - throw LOGGER.atError() - .log(new IllegalArgumentException("Missing required property dna in model FishInner")); - } if (innerProperties() == null) { throw LOGGER.atError() .log(new IllegalArgumentException("Missing required property innerProperties in model FishInner")); @@ -236,7 +232,6 @@ public void validate() { public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeIntField("age", this.age); - jsonWriter.writeStringField("dna", this.dna); jsonWriter.writeJsonField("properties", this.innerProperties); jsonWriter.writeJsonField("anotherProperties", this.innerAnotherProperties); jsonWriter.writeStringField("kind", this.kind); diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java index 212b5981c9..8d0392b488 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/fluent/models/SalmonInner.java @@ -38,6 +38,11 @@ public final class SalmonInner extends FishInner { */ private FishInner partner; + /* + * The dna property. + */ + private String dna; + /* * The properties property. */ @@ -124,6 +129,16 @@ public SalmonInner withPartner(FishInner partner) { return this; } + /** + * Get the dna property: The dna property. + * + * @return the dna value. + */ + @Override + public String dna() { + return this.dna; + } + /** * Get the innerProperties property: The properties property. * @@ -151,15 +166,6 @@ public SalmonInner withAge(int age) { return this; } - /** - * {@inheritDoc} - */ - @Override - public SalmonInner withDna(String dna) { - super.withDna(dna); - return this; - } - /** * Get the length property: The length property. * @@ -254,7 +260,6 @@ public void validate() { public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeIntField("age", age()); - jsonWriter.writeStringField("dna", dna()); jsonWriter.writeJsonField("properties", innerProperties()); jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("kind", this.kind); @@ -283,7 +288,7 @@ public static SalmonInner fromJson(JsonReader jsonReader) throws IOException { if ("age".equals(fieldName)) { deserializedSalmonInner.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedSalmonInner.withDna(reader.getString()); + deserializedSalmonInner.dna = reader.getString(); } else if ("properties".equals(fieldName)) { deserializedSalmonInner.innerProperties = FishProperties.fromJson(reader); } else if ("anotherProperties".equals(fieldName)) { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java index a918838e52..6ac41e8984 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/GoblinShark.java @@ -27,6 +27,11 @@ public final class GoblinShark extends Shark { */ private String sharktype = "goblin"; + /* + * The dna property. + */ + private String dna; + /* * The properties property. */ @@ -63,6 +68,16 @@ public String sharktype() { return this.sharktype; } + /** + * Get the dna property: The dna property. + * + * @return the dna value. + */ + @Override + public String dna() { + return this.dna; + } + /** * Get the innerProperties property: The properties property. * @@ -90,15 +105,6 @@ public GoblinShark withAge(int age) { return this; } - /** - * {@inheritDoc} - */ - @Override - public GoblinShark withDna(String dna) { - super.withDna(dna); - return this; - } - /** * Get the length property: The length property. * @@ -181,7 +187,6 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); - jsonWriter.writeStringField("dna", dna()); jsonWriter.writeJsonField("properties", innerProperties()); jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); @@ -207,7 +212,7 @@ public static GoblinShark fromJson(JsonReader jsonReader) throws IOException { if ("age".equals(fieldName)) { deserializedGoblinShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedGoblinShark.withDna(reader.getString()); + deserializedGoblinShark.dna = reader.getString(); } else if ("properties".equals(fieldName)) { deserializedGoblinShark.innerProperties = FishProperties.fromJson(reader); } else if ("anotherProperties".equals(fieldName)) { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java index 9fda2f385f..47561c3f15 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/SawShark.java @@ -27,6 +27,11 @@ public final class SawShark extends Shark { */ private String sharktype = "saw"; + /* + * The dna property. + */ + private String dna; + /* * The properties property. */ @@ -63,6 +68,16 @@ public String sharktype() { return this.sharktype; } + /** + * Get the dna property: The dna property. + * + * @return the dna value. + */ + @Override + public String dna() { + return this.dna; + } + /** * Get the innerProperties property: The properties property. * @@ -90,15 +105,6 @@ public SawShark withAge(int age) { return this; } - /** - * {@inheritDoc} - */ - @Override - public SawShark withDna(String dna) { - super.withDna(dna); - return this; - } - /** * Get the length property: The length property. * @@ -181,7 +187,6 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); - jsonWriter.writeStringField("dna", dna()); jsonWriter.writeJsonField("properties", innerProperties()); jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); @@ -207,7 +212,7 @@ public static SawShark fromJson(JsonReader jsonReader) throws IOException { if ("age".equals(fieldName)) { deserializedSawShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedSawShark.withDna(reader.getString()); + deserializedSawShark.dna = reader.getString(); } else if ("properties".equals(fieldName)) { deserializedSawShark.innerProperties = FishProperties.fromJson(reader); } else if ("anotherProperties".equals(fieldName)) { diff --git a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java index 24a59bb21d..b084bdda48 100644 --- a/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java +++ b/typespec-tests/src/main/java/com/cadl/armstreamstyleserialization/models/Shark.java @@ -28,6 +28,11 @@ public class Shark extends FishInner { */ private String sharktype = "shark"; + /* + * The dna property. + */ + private String dna; + /* * The properties property. */ @@ -63,6 +68,16 @@ public String sharktype() { return this.sharktype; } + /** + * Get the dna property: The dna property. + * + * @return the dna value. + */ + @Override + public String dna() { + return this.dna; + } + /** * Get the innerProperties property: The properties property. * @@ -90,15 +105,6 @@ public Shark withAge(int age) { return this; } - /** - * {@inheritDoc} - */ - @Override - public Shark withDna(String dna) { - super.withDna(dna); - return this; - } - /** * Get the length property: The length property. * @@ -181,7 +187,6 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { jsonWriter.writeStartObject(); jsonWriter.writeStringField("kind", this.kind); jsonWriter.writeIntField("age", age()); - jsonWriter.writeStringField("dna", dna()); jsonWriter.writeJsonField("properties", innerProperties()); jsonWriter.writeJsonField("anotherProperties", innerAnotherProperties()); jsonWriter.writeStringField("sharktype", this.sharktype); @@ -234,7 +239,7 @@ static Shark fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOExceptio if ("age".equals(fieldName)) { deserializedShark.withAge(reader.getInt()); } else if ("dna".equals(fieldName)) { - deserializedShark.withDna(reader.getString()); + deserializedShark.dna = reader.getString(); } else if ("properties".equals(fieldName)) { deserializedShark.innerProperties = FishProperties.fromJson(reader); } else if ("anotherProperties".equals(fieldName)) {