From 8f37063beb2d4b92890c4f0f0aa8030605dedd47 Mon Sep 17 00:00:00 2001 From: Weidong Xu <weidxu@microsoft.com> Date: Fri, 3 Jan 2025 16:04:23 +0800 Subject: [PATCH] http-client-java, generate mock Long number for BigDecimal (#5433) - mock test data in mgmt was not able to handle `BigDecimal` type https://github.com/Azure/azure-sdk-for-java/pull/43569 - try break the string if too long https://github.com/Azure/azure-sdk-for-java/pull/43574 (but still have "code too large" error, as byte code for a method need to be under 64K) --- .../core/model/javamodel/JavaPackage.java | 4 ++++ .../core/template/ModelTestTemplate.java | 23 ++++++++++++++++++- .../util/ConstantStringTooLongException.java | 11 +++++++++ .../core/util/ModelTestCaseUtil.java | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ConstantStringTooLongException.java diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/javamodel/JavaPackage.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/javamodel/JavaPackage.java index 349f24462e4..c88a72f7c6e 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/javamodel/JavaPackage.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/model/javamodel/JavaPackage.java @@ -39,6 +39,7 @@ import com.microsoft.typespec.http.client.generator.core.template.Templates; import com.microsoft.typespec.http.client.generator.core.template.TestProxyAssetsTemplate; import com.microsoft.typespec.http.client.generator.core.util.ClientModelUtil; +import com.microsoft.typespec.http.client.generator.core.util.ConstantStringTooLongException; import com.microsoft.typespec.http.client.generator.core.util.PossibleCredentialException; import java.io.BufferedReader; import java.io.IOException; @@ -299,6 +300,9 @@ public void addModelUnitTest(ClientModel model) { } catch (PossibleCredentialException e) { // skip this test file logger.warn("Skip unit test for model '{}', caused by key '{}'", model.getName(), e.getKeyName()); + } catch (ConstantStringTooLongException e) { + // skip this test file + logger.warn("Skip unit test for model '{}', JSON string is too long.", model.getName()); } } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTestTemplate.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTestTemplate.java index d7cd6e74f3e..f932d5e8304 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTestTemplate.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/template/ModelTestTemplate.java @@ -12,6 +12,7 @@ import com.microsoft.typespec.http.client.generator.core.model.clientmodel.examplemodel.ExampleNode; import com.microsoft.typespec.http.client.generator.core.model.javamodel.JavaFile; import com.microsoft.typespec.http.client.generator.core.template.example.ModelExampleWriter; +import com.microsoft.typespec.http.client.generator.core.util.ConstantStringTooLongException; import com.microsoft.typespec.http.client.generator.core.util.ModelExampleUtil; import com.microsoft.typespec.http.client.generator.core.util.ModelTestCaseUtil; import java.io.ByteArrayOutputStream; @@ -32,6 +33,18 @@ public static ModelTestTemplate getInstance() { return INSTANCE; } + /** + * Write the JSON serialization / de-serialization unit test for the model. + * + * @param model the client model to test. + * @param javaFile the java file. + * @throws com.microsoft.typespec.http.client.generator.core.util.PossibleCredentialException + * thrown when there is possible mock value to a secret property. + * Even when the value is mocked, it could be flagged by CI as issue. Therefore, the case is skipped. + * @throws com.microsoft.typespec.http.client.generator.core.util.ConstantStringTooLongException + * thrown when the String representation of the JSON is too long (>= 2^16). + * Constant string of that size would cause compiler "constant string too long" error. + */ @Override public void write(ClientModel model, JavaFile javaFile) { @@ -61,12 +74,20 @@ public void write(ClientModel model, JavaFile javaFile) { javaFile.declareImport(imports); + String jsonStringExpression = ClassType.STRING.defaultValueExpression(jsonStr); + if (jsonStringExpression.length() >= 65536) { + // Java compiler would give "constant string too long" error on the generated file. + // The length of a string constant in a class file is limited to 2^16 bytes in UTF-8 encoding. + // There is also a related "code too large" error, for limit on Java method size in bytecode. + throw new ConstantStringTooLongException(); + } + javaFile.publicFinalClass(model.getName() + "Tests", classBlock -> { // testDeserialize classBlock.annotation("org.junit.jupiter.api.Test"); classBlock.publicMethod("void testDeserialize() throws Exception", methodBlock -> { methodBlock.line(String.format("%1$s model = BinaryData.fromString(%2$s).toObject(%1$s.class);", - model.getName(), ClassType.STRING.defaultValueExpression(jsonStr))); + model.getName(), jsonStringExpression)); writer.writeAssertion(methodBlock); }); diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ConstantStringTooLongException.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ConstantStringTooLongException.java new file mode 100644 index 00000000000..998553b83df --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ConstantStringTooLongException.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.typespec.http.client.generator.core.util; + +public class ConstantStringTooLongException extends RuntimeException { + + public ConstantStringTooLongException() { + super("Constant string too long."); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtil.java b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtil.java index 02edce96138..5928f6cd53a 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtil.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/main/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtil.java @@ -98,6 +98,8 @@ public static Object jsonFromType(int depth, IType type) { return RANDOM.nextInt() & Integer.MAX_VALUE; } else if (type.asNullable() == ClassType.LONG) { return RANDOM.nextLong() & Long.MAX_VALUE; + } else if (type.asNullable() == ClassType.BIG_DECIMAL) { + return RANDOM.nextLong() & Long.MAX_VALUE; } else if (type.asNullable() == ClassType.FLOAT) { return RANDOM.nextFloat() * 100; } else if (type.asNullable() == ClassType.DOUBLE) {