From 8464593662c51c557e522e9c30912742900f3f95 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 12:07:16 +0800 Subject: [PATCH 1/8] test for ConvertToJsonTypeTrait --- .../core/model/clientmodel/ClassType.java | 15 ++++++++-- .../clientmodel/ConvertFromJsonTypeTrait.java | 18 ++++++++++++ .../clientmodel/ConvertToJsonTypeTrait.java | 4 +-- .../core/model/clientmodel/EnumType.java | 7 ++++- .../core/model/clientmodel/PrimitiveType.java | 17 +++++++++-- .../ConvertToJsonTypeTraitTests.java | 28 +++++++++++++++++++ 6 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTrait.java create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java index 7f107571fc0..47ccc351fff 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java @@ -26,7 +26,7 @@ /** * The details of a class type that is used by a client. */ -public class ClassType implements IType, ConvertToJsonTypeTrait { +public class ClassType implements IType, ConvertToJsonTypeTrait, ConvertFromJsonTypeTrait { private static ClassType withClientCoreReplacement(String azureClass, String clientCoreClass) { return withClientCoreAndVNextReplacement(azureClass, clientCoreClass, clientCoreClass); } @@ -282,6 +282,7 @@ private static Builder withVNextReplacementBuilder(String azureClass, String azu public static final ClassType POLLER_FLUX = new ClassType("com.azure.core.util.polling", "PollerFlux"); // Complex mapped types + // JSON type is STRING, wire type is Base64Url/Base64Uri, client type is byte[] public static final ClassType BASE_64_URL = withClientCoreReplacementBuilder("com.azure.core.util.Base64Url", "io.clientcore.core.utils.Base64Uri", false) .serializationValueGetterModifier(valueGetter -> "Objects.toString(" + valueGetter + ", null)") @@ -310,6 +311,7 @@ private static Builder withVNextReplacementBuilder(String azureClass, String azu .xmlAttributeDeserializationTemplate("%s.getNullableAttribute(%s, %s, BinaryData::fromObject)") .build(); + // JSON type is STRING, wire type is DateTimeRfc1123, client type is OffsetDateTime public static final ClassType DATE_TIME_RFC_1123 = withClientCoreReplacementBuilder("com.azure.core.util.DateTimeRfc1123", "io.clientcore.core.utils.DateTimeRfc1123", false) @@ -497,8 +499,11 @@ private static Builder withVNextReplacementBuilder(String azureClass, String azu .xmlAttributeDeserializationTemplate("%s.getNullableAttribute(%s, %s, OffsetDateTime::parse)") .build(); + // JSON type is NUMERIC, client type is OffsetDateTime public static final ClassType UNIX_TIME_LONG = new ClassType.Builder(false).prototypeAsLong().build(); + // JSON type is NUMERIC, client type is Duration public static final ClassType DURATION_LONG = new ClassType.Builder(false).prototypeAsLong().build(); + // JSON type is NUMERIC, client type is Duration public static final ClassType DURATION_DOUBLE = new ClassType.Builder(false).prototypeAsDouble().build(); public static final ClassType URL = new Builder(false) @@ -786,11 +791,17 @@ public boolean isUsedInXml() { @Override public String convertToJsonType(String variableName) { + String expression = convertFromClientType(variableName); return serializationValueGetterModifier != null - ? serializationValueGetterModifier.apply(variableName) + ? serializationValueGetterModifier.apply(expression) : variableName; } + @Override + public String convertFromJsonType(String variableName) { + return ""; + } + public static class Builder { /* * Used to indicate if the class type is generated based on a Swagger definition and isn't a pre-defined, diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTrait.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTrait.java new file mode 100644 index 00000000000..7f3958cc716 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTrait.java @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.typespec.http.client.generator.core.model.clientmodel; + +/** + * Trait for types that can convert a JSON wire value back into the client type. + */ +public interface ConvertFromJsonTypeTrait { + + /** + * Gets the expression that converts the JSON wire value into this type. + * + * @param variableName The variable to convert. + * @return The expression that converts the variable to this type. + */ + String convertFromJsonType(String variableName); +} diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTrait.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTrait.java index bb53010f70f..d4211d13a9b 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTrait.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTrait.java @@ -6,10 +6,10 @@ public interface ConvertToJsonTypeTrait { /** - * Gets the expression that convert the variable of this type to the wire type. + * Gets the expression that convert the variable of this type to the JSON wire type. * * @param variableName The variable to convert. - * @return The expression that convert the variable to the wire type. + * @return The expression that convert the variable to the JSON wire type. */ String convertToJsonType(String variableName); } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/EnumType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/EnumType.java index 02aa14e2d5d..1fe427e7d1f 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/EnumType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/EnumType.java @@ -11,7 +11,7 @@ /** * The details of an enumerated type that is used by a service. */ -public class EnumType implements IType, ConvertToJsonTypeTrait { +public class EnumType implements IType, ConvertToJsonTypeTrait, ConvertFromJsonTypeTrait { /** * The name of the new Enum. */ @@ -233,6 +233,11 @@ public String convertToJsonType(String variableName) { return variableName + " == null ? null : " + variableName + "." + getToMethodName() + "()"; } + @Override + public String convertFromJsonType(String variableName) { + return variableName + " == null ? null : " + getName() + "." + getFromMethodName() + "(" + variableName + ")"; + } + public static class Builder { private String name; private String description; diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java index 8c641f9108e..3bc73d3348b 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java @@ -12,7 +12,7 @@ /** * A basic type used by a client. */ -public class PrimitiveType implements IType, ConvertToJsonTypeTrait { +public class PrimitiveType implements IType, ConvertToJsonTypeTrait, ConvertFromJsonTypeTrait { public static final PrimitiveType VOID = new Builder().name("void").nullableType(ClassType.VOID).build(); public static final PrimitiveType BOOLEAN = new Builder().name("boolean") @@ -50,6 +50,7 @@ public class PrimitiveType implements IType, ConvertToJsonTypeTrait { public static final PrimitiveType LONG = new Builder().prototypeAsLong().build(); + // JSON type is STRING public static final PrimitiveType INT_AS_STRING = new Builder().name("int") .nullableType(ClassType.INTEGER_AS_STRING) .defaultValueExpressionConverter( @@ -63,6 +64,7 @@ public class PrimitiveType implements IType, ConvertToJsonTypeTrait { .xmlAttributeDeserializationTemplate("%s.getNullableAttribute(%s, %s, Integer::valueOf)") .build(); + // JSON type is STRING public static final PrimitiveType LONG_AS_STRING = new Builder().prototypeAsLong() .nullableType(ClassType.LONG_AS_STRING) .defaultValueExpressionConverter(defaultValueExpression -> "Long.parseLong(\"" + defaultValueExpression + "\")") @@ -99,12 +101,15 @@ public class PrimitiveType implements IType, ConvertToJsonTypeTrait { .xmlElementDeserializationMethod("getStringElement().charAt(0)") .build(); + // JSON type is NUMERIC, client type is OffsetDateTime public static final PrimitiveType UNIX_TIME_LONG = new Builder().prototypeAsLong().nullableType(ClassType.UNIX_TIME_LONG).build(); + // JSON type is NUMERIC, client type is Duration public static final PrimitiveType DURATION_LONG = new Builder().prototypeAsLong().nullableType(ClassType.DURATION_LONG).build(); + // JSON type is NUMERIC, client type is Duration public static final PrimitiveType DURATION_DOUBLE = new Builder().prototypeAsDouble().nullableType(ClassType.DURATION_DOUBLE).build(); @@ -305,13 +310,19 @@ public String toString() { @Override public String convertToJsonType(String variableName) { + String expression = convertFromClientType(variableName); if (wrapSerializationWithObjectsToString) { - return "Objects.toString(" + variableName + ", null)"; + return "Objects.toString(" + expression + ", null)"; } else { - return variableName; + return expression; } } + @Override + public String convertFromJsonType(String variableName) { + return ""; + } + private static class Builder { private String name; diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java new file mode 100644 index 00000000000..e4d2c71976e --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.typespec.http.client.generator.core.model.clientmodel; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ConvertToJsonTypeTraitTests { + + @Test + public void testPrimitiveTypeConversion() { + Assertions.assertEquals("var", PrimitiveType.INT.convertToJsonType("var")); + Assertions.assertEquals("Objects.toString(var, null)", PrimitiveType.INT_AS_STRING.convertToJsonType("var")); + Assertions.assertEquals("(double) var.toNanos() / 1000_000_000L", + PrimitiveType.DURATION_DOUBLE.convertToJsonType("var")); + } + + @Test + public void testClassTypeConversion() { + Assertions.assertEquals("var", ClassType.LONG.convertToJsonType("var")); + Assertions.assertEquals("Objects.toString(new DateTimeRfc1123(var), null)", + ClassType.DATE_TIME_RFC_1123.convertToJsonType("var")); + Assertions.assertEquals("var == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(var)", + ClassType.DATE_TIME.convertToJsonType("var")); + Assertions.assertEquals("CoreUtils.durationToStringWithDays(var)", ClassType.DURATION.convertToJsonType("var")); + } +} From 3ed9b189abbe5f4e2e1b63cea199042111d451dc Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 13:16:12 +0800 Subject: [PATCH 2/8] handle convertFromJsonType --- .../core/model/clientmodel/ClassType.java | 18 +++++++++- .../core/model/clientmodel/PrimitiveType.java | 8 ++++- .../ConvertFromJsonTypeTraitTests.java | 33 +++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java index 47ccc351fff..1851803ccaa 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java @@ -799,7 +799,23 @@ public String convertToJsonType(String variableName) { @Override public String convertFromJsonType(String variableName) { - return ""; + // TODO (weidxu): it may be better to refactor it to type initialization, similar as + // defaultValueExpressionConverter + if (this == ClassType.INTEGER_AS_STRING) { + return variableName + " == null ? null : Integer.parseInt(" + variableName + ")"; + } else if (this == ClassType.LONG_AS_STRING) { + return variableName + " == null ? null : Long.parseInt(" + variableName + ")"; + } else if (this == ClassType.DATE_TIME) { + return variableName + " == null ? null : OffsetDateTime.parse(" + variableName + ")"; + } else if (this == ClassType.DATE_TIME_RFC_1123) { + return variableName + " == null ? null : new DateTimeRfc1123(" + variableName + ")"; + } else if (this == ClassType.DURATION) { + return variableName + " == null ? null : Duration.parse(" + variableName + ")"; + } else if (this == ClassType.URL) { + return variableName + " == null ? null : new URL(" + variableName + ")"; + } else { + return convertToClientType(variableName); + } } public static class Builder { diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java index 3bc73d3348b..11bd59c47c2 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java @@ -320,7 +320,13 @@ public String convertToJsonType(String variableName) { @Override public String convertFromJsonType(String variableName) { - return ""; + if (this == PrimitiveType.INT_AS_STRING) { + return variableName + " == null ? null : Integer.parseInt(" + variableName + ")"; + } else if (this == PrimitiveType.LONG_AS_STRING) { + return variableName + " == null ? null : Long.parseInt(" + variableName + ")"; + } else { + return convertToClientType(variableName); + } } private static class Builder { diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java new file mode 100644 index 00000000000..dafdfae247b --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.typespec.http.client.generator.core.model.clientmodel; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ConvertFromJsonTypeTraitTests { + + @Test + public void testPrimitiveTypeConversion() { + Assertions.assertEquals("var", PrimitiveType.INT.convertFromJsonType("var")); + Assertions.assertEquals("var == null ? null : Integer.parseInt(var)", + PrimitiveType.INT_AS_STRING.convertFromJsonType("var")); + Assertions.assertEquals("Duration.ofNanos((long) (var * 1000_000_000L))", + PrimitiveType.DURATION_DOUBLE.convertFromJsonType("var")); + Assertions.assertEquals("OffsetDateTime.ofInstant(Instant.ofEpochSecond(var), ZoneOffset.UTC)", + PrimitiveType.UNIX_TIME_LONG.convertFromJsonType("var")); + } + + @Test + public void testClassTypeConversion() { + Assertions.assertEquals("var", ClassType.LONG.convertFromJsonType("var")); + Assertions.assertEquals("var == null ? null : new DateTimeRfc1123(var)", + ClassType.DATE_TIME_RFC_1123.convertFromJsonType("var")); + Assertions.assertEquals("var == null ? null : OffsetDateTime.parse(var)", + ClassType.DATE_TIME.convertFromJsonType("var")); + Assertions.assertEquals("var == null ? null : Duration.parse(var)", + ClassType.DURATION.convertFromJsonType("var")); + Assertions.assertEquals("Duration.ofSeconds(var)", ClassType.DURATION_LONG.convertFromJsonType("var")); + } +} From 8e7b15b9cdfeb5fa022c4e8e8f80fca52e50b134 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 13:20:49 +0800 Subject: [PATCH 3/8] logic in StreamSerializationModelTemplate --- .../StreamSerializationModelTemplate.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java index eb5589ce83a..db0d55b3270 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java @@ -15,6 +15,7 @@ import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ClientModelProperty; import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ClientModelPropertyAccess; import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ClientModelPropertyReference; +import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ConvertFromJsonTypeTrait; import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ConvertToJsonTypeTrait; import com.microsoft.typespec.http.client.generator.core.model.clientmodel.IType; import com.microsoft.typespec.http.client.generator.core.model.clientmodel.IterableType; @@ -1648,13 +1649,17 @@ private void generateJsonDeserializationLogic(JavaBlock deserializationBlock, Cl propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter()); } else { // wireType need to be converted from String - String conversionExpress = wireElementType.defaultValueExpression("valueAsString") - .replace("\"valueAsString\"", "valueAsString"); - deserializationBlock.line( - "%1$s == null ? null : %1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.stream(%1$s.split(\"%2$s\", -1)).map(valueAsString -> %3$s).collect(Collectors.toList()));", - propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter(), - conversionExpress); - + if (wireElementType instanceof ConvertFromJsonTypeTrait) { + String conversionExpress + = ((ConvertFromJsonTypeTrait) wireElementType).convertFromJsonType("valueAsString"); + deserializationBlock.line( + "%1$s == null ? null : %1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.stream(%1$s.split(\"%2$s\", -1)).map(valueAsString -> %3$s).collect(Collectors.toList()));", + propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter(), + conversionExpress); + } else { + throw new RuntimeException("Unable to convert type " + wireElementType + + " from String for ArrayEncoding serialization."); + } } } From 4a82a9730d71034b777ffe756d0d5177dc113a50 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 17:08:36 +0800 Subject: [PATCH 4/8] Update packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../http/client/generator/core/model/clientmodel/ClassType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java index 1851803ccaa..c31b0666683 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ClassType.java @@ -794,7 +794,7 @@ public String convertToJsonType(String variableName) { String expression = convertFromClientType(variableName); return serializationValueGetterModifier != null ? serializationValueGetterModifier.apply(expression) - : variableName; + : expression; } @Override From 56b3a563e51a66c2ed63e18dc178fa2a34ee49d0 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 17:20:30 +0800 Subject: [PATCH 5/8] add UT for EnumType --- .../ConvertFromJsonTypeTraitTests.java | 22 +++++++++++++++++++ .../ConvertToJsonTypeTraitTests.java | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java index dafdfae247b..3460b89031f 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertFromJsonTypeTraitTests.java @@ -3,6 +3,7 @@ package com.microsoft.typespec.http.client.generator.core.model.clientmodel; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -30,4 +31,25 @@ public void testClassTypeConversion() { ClassType.DURATION.convertFromJsonType("var")); Assertions.assertEquals("Duration.ofSeconds(var)", ClassType.DURATION_LONG.convertFromJsonType("var")); } + + @Test + public void testEnumConversion() { + ClientEnumValue enumValue = new ClientEnumValue("VALUE_ONE", "1", "ValueOne"); + + EnumType.Builder enumTypeBuilder = new EnumType.Builder().name("SampleEnum") + .elementType(ClassType.STRING) + .values(List.of(enumValue)) + .expandable(true); + + Assertions.assertEquals("var == null ? null : SampleEnum.fromString(var)", + enumTypeBuilder.build().convertFromJsonType("var")); + + enumTypeBuilder.expandable(false); + Assertions.assertEquals("var == null ? null : SampleEnum.fromString(var)", + enumTypeBuilder.build().convertFromJsonType("var")); + + enumTypeBuilder.elementType(ClassType.INTEGER); + Assertions.assertEquals("var == null ? null : SampleEnum.fromInteger(var)", + enumTypeBuilder.build().convertFromJsonType("var")); + } } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java index e4d2c71976e..a4311bc225d 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/ConvertToJsonTypeTraitTests.java @@ -3,6 +3,7 @@ package com.microsoft.typespec.http.client.generator.core.model.clientmodel; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -25,4 +26,25 @@ public void testClassTypeConversion() { ClassType.DATE_TIME.convertToJsonType("var")); Assertions.assertEquals("CoreUtils.durationToStringWithDays(var)", ClassType.DURATION.convertToJsonType("var")); } + + @Test + public void testEnumConversion() { + ClientEnumValue enumValue = new ClientEnumValue("VALUE_ONE", "ValueOne", "ValueOne"); + + EnumType.Builder enumTypeBuilder = new EnumType.Builder().name("SampleEnum") + .elementType(ClassType.STRING) + .values(List.of(enumValue)) + .expandable(true); + + Assertions.assertEquals("var == null ? null : var.toString()", + enumTypeBuilder.build().convertToJsonType("var")); + + enumTypeBuilder.expandable(false); + Assertions.assertEquals("var == null ? null : var.toString()", + enumTypeBuilder.build().convertToJsonType("var")); + + enumTypeBuilder.elementType(ClassType.INTEGER); + Assertions.assertEquals("var == null ? null : var.toInteger()", + enumTypeBuilder.build().convertToJsonType("var")); + } } From d12f548c96b4aace025a3fdff9e41b186b5b95e4 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 21:14:32 +0800 Subject: [PATCH 6/8] generate more concise code with getNullable --- .../StreamSerializationModelTemplate.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java index db0d55b3270..e720d66dbb4 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/StreamSerializationModelTemplate.java @@ -1624,13 +1624,7 @@ private void generateJsonDeserializationLogic(JavaBlock deserializationBlock, Cl deserializationBlock.line(property.getName() + " = reader.readUntyped();"); } } else if (wireType instanceof IterableType) { - final String propertyStringVariableName = property.getName() + "EncodedAsString"; IType wireElementType = ((IterableType) wireType).getElementType(); - if (property.getArrayEncoding() != null) { - // need to prepare the expression for propertyStringVariableName, - // to be used in "if (property.getArrayEncoding() == null)" block - deserializationBlock.line("String " + propertyStringVariableName + " = reader.getString();"); - } if (!propertiesManager.hasConstructorArguments()) { deserializationBlock.text(property.getClientType() + " "); @@ -1641,21 +1635,34 @@ private void generateJsonDeserializationLogic(JavaBlock deserializationBlock, Cl deserializeJsonContainerProperty(deserializationBlock, "readArray", wireType, wireElementType, ((IterableType) clientType).getElementType(), 0); } else { + final String propertyStringVariableName = property.getName() + "EncodedAsString"; // LinkedList is used to be consistent with internal code of core, e.g. "readArray" API if (wireElementType == ClassType.STRING) { // wireType is String - deserializationBlock.line( - "%1$s == null ? null : %1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(%1$s.split(\"%2$s\", -1)));", - propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter()); + deserializationBlock.line("reader.getNullable(nonNullReader -> {"); + deserializationBlock.indent(() -> { + deserializationBlock.line("String %1$s = nonNullReader.getString();", + propertyStringVariableName); + deserializationBlock.line( + "return %1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(%1$s.split(\"%2$s\", -1)));", + propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter()); + }); + deserializationBlock.line("});"); } else { // wireType need to be converted from String if (wireElementType instanceof ConvertFromJsonTypeTrait) { String conversionExpress = ((ConvertFromJsonTypeTrait) wireElementType).convertFromJsonType("valueAsString"); - deserializationBlock.line( - "%1$s == null ? null : %1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.stream(%1$s.split(\"%2$s\", -1)).map(valueAsString -> %3$s).collect(Collectors.toList()));", - propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter(), - conversionExpress); + deserializationBlock.line("reader.getNullable(nonNullReader -> {"); + deserializationBlock.indent(() -> { + deserializationBlock.line("String %1$s = nonNullReader.getString();", + propertyStringVariableName); + deserializationBlock.line( + "%1$s.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.stream(%1$s.split(\"%2$s\", -1)).map(valueAsString -> %3$s).collect(Collectors.toList()));", + propertyStringVariableName, property.getArrayEncoding().getEscapedDelimiter(), + conversionExpress); + }); + deserializationBlock.line("});"); } else { throw new RuntimeException("Unable to convert type " + wireElementType + " from String for ArrayEncoding serialization."); From 6d463e406aac09a110552f1685ece1d4aaf9c45e Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Tue, 20 Jan 2026 21:38:39 +0800 Subject: [PATCH 7/8] regen --- .../encode/array/models/CommaDelimitedArrayProperty.java | 8 ++++---- .../array/models/NewlineDelimitedArrayProperty.java | 8 ++++---- .../encode/array/models/PipeDelimitedArrayProperty.java | 8 ++++---- .../encode/array/models/SpaceDelimitedArrayProperty.java | 8 ++++---- .../src/main/java/tsptest/builtin/models/Encoded.java | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java index 25747bc7fe0..16a0bd6623b 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java @@ -79,12 +79,12 @@ public static CommaDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split(",", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java index 03acae4ccd1..d79f801ad17 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java @@ -79,12 +79,12 @@ public static NewlineDelimitedArrayProperty fromJson(JsonReader jsonReader) thro reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split("\n", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java index 37a143a7016..cac0dc3759b 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java @@ -79,12 +79,12 @@ public static PipeDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split("\\|", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java index 1c270faa5b9..6fa3d1345ca 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java @@ -79,12 +79,12 @@ public static SpaceDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split(" ", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/builtin/models/Encoded.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/builtin/models/Encoded.java index 47297757eac..926f2d3e7c1 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/builtin/models/Encoded.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/builtin/models/Encoded.java @@ -447,12 +447,12 @@ public static Encoded fromJson(JsonReader jsonReader) throws IOException { } else if ("unknownBytes".equals(fieldName)) { deserializedEncoded.unknownBytes = reader.getString(); } else if ("commaDeliminatedArray".equals(fieldName)) { - String commaDeliminatedArrayEncodedAsString = reader.getString(); - List commaDeliminatedArray = commaDeliminatedArrayEncodedAsString == null - ? null - : commaDeliminatedArrayEncodedAsString.isEmpty() + List commaDeliminatedArray = reader.getNullable(nonNullReader -> { + String commaDeliminatedArrayEncodedAsString = nonNullReader.getString(); + return commaDeliminatedArrayEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(commaDeliminatedArrayEncodedAsString.split(",", -1))); + }); deserializedEncoded.commaDeliminatedArray = commaDeliminatedArray; } else { reader.skipChildren(); From 4b8e51d181cb112972e7b64a1d02c08609ab9fe1 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Wed, 21 Jan 2026 09:54:09 +0800 Subject: [PATCH 8/8] regen for clientcore --- .../java/encode/array/CommaDelimitedArrayProperty.java | 8 ++++---- .../java/encode/array/NewlineDelimitedArrayProperty.java | 8 ++++---- .../java/encode/array/PipeDelimitedArrayProperty.java | 8 ++++---- .../java/encode/array/SpaceDelimitedArrayProperty.java | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java index 77176e44514..b5baed8a1c9 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java @@ -75,12 +75,12 @@ public static CommaDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split(",", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java index a5f6d1d0b4a..0b1ac3a3abb 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java @@ -75,12 +75,12 @@ public static NewlineDelimitedArrayProperty fromJson(JsonReader jsonReader) thro reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split("\n", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java index e5cc35a4960..3d69541e26e 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java @@ -75,12 +75,12 @@ public static PipeDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split("\\|", -1))); + }); } else { reader.skipChildren(); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java index 4e514f16ecf..f657bee244a 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java @@ -75,12 +75,12 @@ public static SpaceDelimitedArrayProperty fromJson(JsonReader jsonReader) throws reader.nextToken(); if ("value".equals(fieldName)) { - String valueEncodedAsString = reader.getString(); - value = valueEncodedAsString == null - ? null - : valueEncodedAsString.isEmpty() + value = reader.getNullable(nonNullReader -> { + String valueEncodedAsString = nonNullReader.getString(); + return valueEncodedAsString.isEmpty() ? new LinkedList<>() : new LinkedList<>(Arrays.asList(valueEncodedAsString.split(" ", -1))); + }); } else { reader.skipChildren(); }