Skip to content

Commit bc30a9f

Browse files
authored
[http-client-java]mgmt, fix instant max value (#9123)
Root cause: `return RANDOM.nextInt() & Long.MAX_VALUE;` `RANDOM.nextInt()` sometimes will return negative integer. With `& Long.MAX_VALUE`, it'll be promoted to long, with negative sign removed. The promoted number will exceed Integer.MAX_VALUE. - bug fix in 65fa31c - (improvement)Group primitive logic in `WireTypeClientTypeConverter`. - (improvement)Added test case for primitive types. - regen & test validation in Azure/autorest.java#3233
1 parent 58dfc62 commit bc30a9f

File tree

6 files changed

+139
-27
lines changed

6 files changed

+139
-27
lines changed

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/clientmodel/PrimitiveType.java

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

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

6+
import com.microsoft.typespec.http.client.generator.core.util.WireTypeClientTypeConverter;
67
import java.time.Instant;
78
import java.time.ZoneOffset;
89
import java.util.Set;
@@ -224,35 +225,12 @@ public final IType getClientType() {
224225

225226
@Override
226227
public final String convertToClientType(String expression) {
227-
if (getClientType() == this) {
228-
return expression;
229-
}
230-
231-
if (this == PrimitiveType.UNIX_TIME_LONG) {
232-
expression
233-
= String.format("OffsetDateTime.ofInstant(Instant.ofEpochSecond(%1$s), ZoneOffset.UTC)", expression);
234-
} else if (this == PrimitiveType.DURATION_LONG) {
235-
expression = String.format("Duration.ofSeconds(%s)", expression);
236-
} else if (this == PrimitiveType.DURATION_DOUBLE) {
237-
expression = String.format("Duration.ofNanos((long) (%s * 1000_000_000L))", expression);
238-
}
239-
return expression;
228+
return WireTypeClientTypeConverter.convertToClientTypeExpression(this, expression);
240229
}
241230

242231
@Override
243232
public final String convertFromClientType(String expression) {
244-
if (getClientType() == this) {
245-
return expression;
246-
}
247-
248-
if (this == PrimitiveType.UNIX_TIME_LONG) {
249-
expression = String.format("%1$s.toEpochSecond()", expression);
250-
} else if (this == PrimitiveType.DURATION_LONG) {
251-
expression = String.format("%s.getSeconds()", expression);
252-
} else if (this == PrimitiveType.DURATION_DOUBLE) {
253-
expression = String.format("(double) %s.toNanos() / 1000_000_000L", expression);
254-
}
255-
return expression;
233+
return WireTypeClientTypeConverter.convertToWireTypeExpression(this, expression);
256234
}
257235

258236
@Override

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public static Object jsonFromType(int depth, IType type) {
110110
return randomString();
111111
} else if (type.asNullable() == ClassType.UNIX_TIME_LONG) {
112112
// use nextInt to avoid exceeding unixTime limit
113-
return RANDOM.nextInt() & Long.MAX_VALUE;
113+
return RANDOM.nextInt() & Integer.MAX_VALUE;
114114
} else if (type == ClassType.DATE_TIME) {
115115
return randomDateTime().toString();
116116
} else if (type == ClassType.DATE_TIME_RFC_1123) {

packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/WireTypeClientTypeConverter.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.ClassType;
66
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.IType;
7+
import com.microsoft.typespec.http.client.generator.core.model.clientmodel.PrimitiveType;
78
import io.clientcore.core.utils.Base64Uri;
89
import io.clientcore.core.utils.DateTimeRfc1123;
910
import java.time.Duration;
@@ -76,6 +77,57 @@ public static String convertToWireTypeExpression(ClassType clientType, String ex
7677
return expression;
7778
}
7879

80+
/**
81+
* Convert client type expression to wire type expression.
82+
* Any change to this method should also be reflected in {@link #convertLiteralToClientValue(IType, String)}, and
83+
* {@link #convertToWireTypeExpression(PrimitiveType, String)} if necessary.
84+
*
85+
* @param wireType the wire type
86+
* @param expression value expression
87+
* @return value expression in wire type form
88+
* @see #convertLiteralToClientValue(IType, String) {@link #convertToWireTypeExpression(PrimitiveType, String)}
89+
*/
90+
public static String convertToClientTypeExpression(PrimitiveType wireType, String expression) {
91+
if (wireType.getClientType() == wireType) {
92+
return expression;
93+
}
94+
95+
if (wireType == PrimitiveType.UNIX_TIME_LONG) {
96+
expression
97+
= String.format("OffsetDateTime.ofInstant(Instant.ofEpochSecond(%1$s), ZoneOffset.UTC)", expression);
98+
} else if (wireType == PrimitiveType.DURATION_LONG) {
99+
expression = String.format("Duration.ofSeconds(%s)", expression);
100+
} else if (wireType == PrimitiveType.DURATION_DOUBLE) {
101+
expression = String.format("Duration.ofNanos((long) (%s * 1000_000_000L))", expression);
102+
}
103+
return expression;
104+
}
105+
106+
/**
107+
* Convert client type expression to wire type expression.
108+
* Any change to this method should also be reflected in {@link #convertLiteralToClientValue(IType, String)}, and
109+
* {@link #convertToClientTypeExpression(PrimitiveType, String)} if necessary.
110+
*
111+
* @param clientType the client type
112+
* @param expression value expression
113+
* @return value expression in wire type form
114+
* @see #convertLiteralToClientValue(IType, String) {@link #convertToClientTypeExpression(PrimitiveType, String)}
115+
*/
116+
public static String convertToWireTypeExpression(PrimitiveType clientType, String expression) {
117+
if (clientType.getClientType() == clientType) {
118+
return expression;
119+
}
120+
121+
if (clientType == PrimitiveType.UNIX_TIME_LONG) {
122+
expression = String.format("%1$s.toEpochSecond()", expression);
123+
} else if (clientType == PrimitiveType.DURATION_LONG) {
124+
expression = String.format("%s.getSeconds()", expression);
125+
} else if (clientType == PrimitiveType.DURATION_DOUBLE) {
126+
expression = String.format("(double) %s.toNanos() / 1000_000_000L", expression);
127+
}
128+
return expression;
129+
}
130+
79131
/**
80132
* Convert example literal value in wire type, to literal value in client type.
81133
* <p>

packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armstreamstyleserialization/models/Encoded.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.azure.core.util.Base64Url;
99
import com.azure.core.util.CoreUtils;
1010
import com.azure.core.util.DateTimeRfc1123;
11+
import com.azure.core.util.logging.ClientLogger;
1112
import com.azure.json.JsonReader;
1213
import com.azure.json.JsonSerializable;
1314
import com.azure.json.JsonToken;
@@ -32,11 +33,21 @@ public final class Encoded implements JsonSerializable<Encoded> {
3233
*/
3334
private Long timeInSeconds;
3435

36+
/*
37+
* The timeInSecondsPrimitive property.
38+
*/
39+
private long timeInSecondsPrimitive;
40+
3541
/*
3642
* The timeInSecondsFraction property.
3743
*/
3844
private Double timeInSecondsFraction;
3945

46+
/*
47+
* The timeInSecondsFractionPrimitive property.
48+
*/
49+
private double timeInSecondsFractionPrimitive;
50+
4051
/*
4152
* The dateTime property.
4253
*/
@@ -52,6 +63,11 @@ public final class Encoded implements JsonSerializable<Encoded> {
5263
*/
5364
private Long unixTimestamp;
5465

66+
/*
67+
* The unixTimestampPrimitive property.
68+
*/
69+
private long unixTimestampPrimitive;
70+
5571
/*
5672
* The base64 property.
5773
*/
@@ -95,6 +111,15 @@ public Duration timeInSeconds() {
95111
return Duration.ofSeconds(this.timeInSeconds);
96112
}
97113

114+
/**
115+
* Get the timeInSecondsPrimitive property: The timeInSecondsPrimitive property.
116+
*
117+
* @return the timeInSecondsPrimitive value.
118+
*/
119+
public Duration timeInSecondsPrimitive() {
120+
return Duration.ofSeconds(this.timeInSecondsPrimitive);
121+
}
122+
98123
/**
99124
* Get the timeInSecondsFraction property: The timeInSecondsFraction property.
100125
*
@@ -107,6 +132,15 @@ public Duration timeInSecondsFraction() {
107132
return Duration.ofNanos((long) (this.timeInSecondsFraction * 1000_000_000L));
108133
}
109134

135+
/**
136+
* Get the timeInSecondsFractionPrimitive property: The timeInSecondsFractionPrimitive property.
137+
*
138+
* @return the timeInSecondsFractionPrimitive value.
139+
*/
140+
public Duration timeInSecondsFractionPrimitive() {
141+
return Duration.ofNanos((long) (this.timeInSecondsFractionPrimitive * 1000_000_000L));
142+
}
143+
110144
/**
111145
* Get the dateTime property: The dateTime property.
112146
*
@@ -140,6 +174,15 @@ public OffsetDateTime unixTimestamp() {
140174
return OffsetDateTime.ofInstant(Instant.ofEpochSecond(this.unixTimestamp), ZoneOffset.UTC);
141175
}
142176

177+
/**
178+
* Get the unixTimestampPrimitive property: The unixTimestampPrimitive property.
179+
*
180+
* @return the unixTimestampPrimitive value.
181+
*/
182+
public OffsetDateTime unixTimestampPrimitive() {
183+
return OffsetDateTime.ofInstant(Instant.ofEpochSecond(this.unixTimestampPrimitive), ZoneOffset.UTC);
184+
}
185+
143186
/**
144187
* Get the base64 property: The base64 property.
145188
*
@@ -194,14 +237,32 @@ public String unknownBytes() {
194237
* @throws IllegalArgumentException thrown if the instance is not valid.
195238
*/
196239
public void validate() {
240+
if (timeInSecondsPrimitive() == null) {
241+
throw LOGGER.atError()
242+
.log(new IllegalArgumentException("Missing required property timeInSecondsPrimitive in model Encoded"));
243+
}
244+
if (timeInSecondsFractionPrimitive() == null) {
245+
throw LOGGER.atError()
246+
.log(new IllegalArgumentException(
247+
"Missing required property timeInSecondsFractionPrimitive in model Encoded"));
248+
}
249+
if (unixTimestampPrimitive() == null) {
250+
throw LOGGER.atError()
251+
.log(new IllegalArgumentException("Missing required property unixTimestampPrimitive in model Encoded"));
252+
}
197253
}
198254

255+
private static final ClientLogger LOGGER = new ClientLogger(Encoded.class);
256+
199257
/**
200258
* {@inheritDoc}
201259
*/
202260
@Override
203261
public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
204262
jsonWriter.writeStartObject();
263+
jsonWriter.writeLongField("timeInSecondsPrimitive", this.timeInSecondsPrimitive);
264+
jsonWriter.writeDoubleField("timeInSecondsFractionPrimitive", this.timeInSecondsFractionPrimitive);
265+
jsonWriter.writeLongField("unixTimestampPrimitive", this.unixTimestampPrimitive);
205266
jsonWriter.writeNumberField("timeInSeconds", this.timeInSeconds);
206267
jsonWriter.writeNumberField("timeInSecondsFraction", this.timeInSecondsFraction);
207268
jsonWriter.writeStringField("dateTime",
@@ -222,6 +283,7 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
222283
* @param jsonReader The JsonReader being read.
223284
* @return An instance of Encoded if the JsonReader was pointing to an instance of it, or null if it was pointing to
224285
* JSON null.
286+
* @throws IllegalStateException If the deserialized JSON object was missing any required properties.
225287
* @throws IOException If an error occurs while reading the Encoded.
226288
*/
227289
public static Encoded fromJson(JsonReader jsonReader) throws IOException {
@@ -231,7 +293,13 @@ public static Encoded fromJson(JsonReader jsonReader) throws IOException {
231293
String fieldName = reader.getFieldName();
232294
reader.nextToken();
233295

234-
if ("timeInSeconds".equals(fieldName)) {
296+
if ("timeInSecondsPrimitive".equals(fieldName)) {
297+
deserializedEncoded.timeInSecondsPrimitive = reader.getLong();
298+
} else if ("timeInSecondsFractionPrimitive".equals(fieldName)) {
299+
deserializedEncoded.timeInSecondsFractionPrimitive = reader.getDouble();
300+
} else if ("unixTimestampPrimitive".equals(fieldName)) {
301+
deserializedEncoded.unixTimestampPrimitive = reader.getLong();
302+
} else if ("timeInSeconds".equals(fieldName)) {
235303
deserializedEncoded.timeInSeconds = reader.getNullable(JsonReader::getLong);
236304
} else if ("timeInSecondsFraction".equals(fieldName)) {
237305
deserializedEncoded.timeInSecondsFraction = reader.getNullable(JsonReader::getDouble);

packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/armstreamstyleserialization/StreamStyleSerializationTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.IOException;
1313
import java.io.StringWriter;
1414
import java.nio.charset.StandardCharsets;
15+
import java.time.Instant;
1516
import java.util.Map;
1617
import java.util.concurrent.atomic.AtomicInteger;
1718
import org.junit.jupiter.api.Assertions;
@@ -103,6 +104,12 @@ public void testPropertyWithNullValue() {
103104
Assertions.assertEquals("input", jsonDict.get("input"));
104105
}
105106

107+
@Test
108+
public void ensureInstantMaxValue() {
109+
// ensure Integer.MAX_VALUE doesn't exceeds Instant.MAX
110+
Instant.ofEpochSecond(Integer.MAX_VALUE);
111+
}
112+
106113
private static HttpClient createExpandableEnumHttpClient() {
107114
AtomicInteger callCount = new AtomicInteger();
108115
HttpClient httpClient = request -> {

packages/http-client-java/generator/http-client-generator-test/tsp/arm-stream-style-serialization.tsp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,11 @@ model Encoded {
315315
@encode(DurationKnownEncoding.seconds, int32)
316316
timeInSeconds?: duration;
317317

318+
@encode(DurationKnownEncoding.seconds, int32)
319+
timeInSecondsPrimitive: duration;
320+
318321
timeInSecondsFraction?: myDuration;
322+
timeInSecondsFractionPrimitive: myDuration;
319323

320324
@encode(DateTimeKnownEncoding.rfc3339)
321325
dateTime?: utcDateTime;
@@ -326,6 +330,9 @@ model Encoded {
326330
@encode(DateTimeKnownEncoding.unixTimestamp, int64)
327331
unixTimestamp?: utcDateTime;
328332

333+
@encode(DateTimeKnownEncoding.unixTimestamp, int64)
334+
unixTimestampPrimitive: utcDateTime;
335+
329336
@encode(BytesKnownEncoding.base64)
330337
base64?: bytes;
331338

0 commit comments

Comments
 (0)