Skip to content

Commit dd644f1

Browse files
authored
Fix Java's handling of mime type text when type is primitive (#9007)
Fixes an edge case in Java's generator when handling `BinaryData` -> primitive type conversion where it would default to `BinaryData.toString()`. This failed for primitive types as a `String` doesn't implicitly cast to `boolean`, `byte`, `int`, `long`, `float`, `double`, or `char`. This is fixed by checking the raw return type for being `!isNullable()` (only primitives return true for this) and wrapping the `BinaryData.toString()` logic with `String` -> primitive conversion calls (`Long.parseLong(String)`, `Byte.parseByte(String)`, etc). Updated `response.tsp` to include new routes to test this change.
1 parent 7c6c412 commit dd644f1

File tree

9 files changed

+1171
-23
lines changed

9 files changed

+1171
-23
lines changed

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ConvenienceAsyncMethodTemplate.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.EnumType;
1616
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.GenericType;
1717
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.IType;
18+
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType;
1819
import com.microsoft.typespec.http.client.generator.core.model.javamodel.JavaBlock;
1920
import com.microsoft.typespec.http.client.generator.core.util.TemplateUtil;
2021
import java.util.List;
@@ -148,33 +149,35 @@ private String expressionConvertFromBinaryData(IType responseBodyType, IType raw
148149

149150
private String expressionMapFromBinaryData(IType responseBodyType, IType rawType, Set<String> mediaTypes,
150151
Set<GenericType> typeReferenceStaticClasses) {
151-
String mapExpression = null;
152152
SupportedMimeType mimeType = SupportedMimeType.getResponseKnownMimeType(mediaTypes);
153153
// TODO (weidxu): support XML etc.
154154
switch (mimeType) {
155155
case TEXT:
156-
mapExpression = "protocolMethodData -> protocolMethodData.toString()";
157-
break;
156+
String baseHandling = "protocolMethodData.toString()";
157+
if (!rawType.isNullable()) {
158+
// Dealing with a primitive type that needs to be converted.
159+
return "protocolMethodData -> " + wrapPrimitiveMimeTypeText(baseHandling, (PrimitiveType) rawType);
160+
} else {
161+
return "protocolMethodData -> " + baseHandling;
162+
}
158163

159164
case BINARY:
160-
mapExpression = null;
161-
break;
165+
return null;
162166

163167
default:
164168
// JSON etc.
165169
if (responseBodyType instanceof EnumType) {
166170
// enum
167-
mapExpression
168-
= String.format("protocolMethodData -> %1$s.from%2$s(protocolMethodData.toObject(%2$s.class))",
169-
responseBodyType, ((EnumType) responseBodyType).getElementType());
171+
return String.format("protocolMethodData -> %1$s.from%2$s(protocolMethodData.toObject(%2$s.class))",
172+
responseBodyType, ((EnumType) responseBodyType).getElementType());
170173
} else if (responseBodyType instanceof GenericType) {
171174
// generic, e.g. list, map
172175
typeReferenceStaticClasses.add((GenericType) responseBodyType);
173-
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s)",
176+
return String.format("protocolMethodData -> protocolMethodData.toObject(%1$s)",
174177
TemplateUtil.getTypeReferenceCreation(responseBodyType));
175178
} else if (responseBodyType == ClassType.BINARY_DATA) {
176179
// BinaryData, no need to do the map in expressionConvertFromBinaryData
177-
mapExpression = null;
180+
return null;
178181
} else if (responseBodyType == ArrayType.BYTE_ARRAY) {
179182
// byte[]
180183
if (rawType == ClassType.BASE_64_URL) {
@@ -185,11 +188,9 @@ private String expressionMapFromBinaryData(IType responseBodyType, IType rawType
185188
}
186189
} else {
187190
// default, treat as class
188-
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s.class)",
189-
responseBodyType.asNullable());
191+
return "protocolMethodData -> protocolMethodData.toObject(" + responseBodyType.asNullable()
192+
+ ".class)";
190193
}
191-
break;
192194
}
193-
return mapExpression;
194195
}
195196
}

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ConvenienceMethodTemplateBase.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33

44
package com.microsoft.typespec.http.client.generator.core.template;
55

6+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.BOOLEAN;
7+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.BYTE;
8+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.CHAR;
9+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.DOUBLE;
10+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.FLOAT;
11+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.INT;
12+
import static com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType.LONG;
13+
614
import com.azure.core.util.FluxUtil;
715
import com.azure.core.util.serializer.CollectionFormat;
816
import com.azure.core.util.serializer.JacksonAdapter;
@@ -337,9 +345,7 @@ private static ClientMethodParameter writeParameterTransformation(ParameterTrans
337345
String targetParameterName = targetParameter.getName();
338346
String targetParameterObjectName = targetParameterName + "Obj";
339347
for (ParameterMapping mapping : transformation.getMappings()) {
340-
String parameterName = mapping.getInParameter().getName();
341-
342-
String inputPath = parameterName;
348+
String inputPath = mapping.getInParameter().getName();
343349
boolean propertyRequired = mapping.getInParameter().isRequired();
344350
if (mapping.getInParameterProperty() != null) {
345351
inputPath = String.format("%s.%s()", mapping.getInParameter().getName(),
@@ -923,4 +929,32 @@ public String getSerializedName() {
923929
}
924930
}
925931
}
932+
933+
/**
934+
* Helper method to wrap handling of mime type text for primitive types.
935+
*
936+
* @param baseHandling The base handling for mime type text.
937+
* @param type The primitive type.
938+
* @return The wrapped handling for primitive type using mime type text.
939+
* @throws IllegalStateException If the primitive type doesn't have a conversion.
940+
*/
941+
static String wrapPrimitiveMimeTypeText(String baseHandling, PrimitiveType type) {
942+
// Dealing with a primitive type that needs to be converted.
943+
if (type == BOOLEAN) {
944+
return "Boolean.parseBoolean(" + baseHandling + ")";
945+
} else if (type == BYTE) {
946+
return "Byte.parseByte(" + baseHandling + ")";
947+
} else if (type == INT) {
948+
return "Integer.parseInt(" + baseHandling + ")";
949+
} else if (type == LONG) {
950+
return "Long.parseLong(" + baseHandling + ")";
951+
} else if (type == FLOAT) {
952+
return "Float.parseFloat(" + baseHandling + ")";
953+
} else if (type == DOUBLE) {
954+
return "Double.parseDouble(" + baseHandling + ")";
955+
} else if (type == CHAR) {
956+
return baseHandling + ".charAt(0)";
957+
}
958+
throw new IllegalStateException("Unexpected primitive type " + type);
959+
}
926960
}

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ConvenienceSyncMethodTemplate.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.EnumType;
1717
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.GenericType;
1818
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.IType;
19+
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType;
1920
import com.microsoft.typespec.http.client.generator.core.model.javamodel.JavaBlock;
2021
import com.microsoft.typespec.http.client.generator.core.util.TemplateUtil;
2122
import java.util.List;
@@ -209,7 +210,12 @@ private String expressionConvertFromBinaryData(IType responseBodyType, IType raw
209210
// TODO (weidxu): support XML etc.
210211
switch (mimeType) {
211212
case TEXT:
212-
return String.format("%s.toString()", invocationExpression);
213+
String basicText = invocationExpression + ".toString()";
214+
if (!rawType.isNullable()) {
215+
// Dealing with a primitive type that needs to be converted.
216+
return wrapPrimitiveMimeTypeText(basicText, (PrimitiveType) rawType);
217+
}
218+
return basicText;
213219

214220
case BINARY:
215221
return invocationExpression;
@@ -232,11 +238,10 @@ private String expressionConvertFromBinaryData(IType responseBodyType, IType raw
232238
} else if (responseBodyType == ArrayType.BYTE_ARRAY) {
233239
// byte[]
234240
if (rawType == ClassType.BASE_64_URL) {
235-
return String.format(
236-
"%1$s.toObject(" + ClassType.BASE_64_URL.getName() + ".class).decodedBytes()",
237-
invocationExpression);
241+
return invocationExpression + ".toObject(" + ClassType.BASE_64_URL.getName()
242+
+ ".class).decodedBytes()";
238243
} else {
239-
return String.format("%1$s.toObject(byte[].class)", invocationExpression);
244+
return invocationExpression + ".toObject(byte[].class)";
240245
}
241246
} else {
242247
// default, treat as class

0 commit comments

Comments
 (0)