From 030cba07ca1be8081da6c3d22b2d0745d68410e9 Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Fri, 24 Jan 2025 17:26:55 +0800 Subject: [PATCH] http-client-java, improve diagnostic (#5702) link https://github.com/microsoft/typespec/issues/5511 1. bump tcgc to 0.50.2 2. adopt part of the `serializationOptions` (not a full adoption due to bug https://github.com/Azure/typespec-azure/issues/2118) 3. refactor entry, now it is `index.ts`, which exposes the few types needed by compiler 4. migrate to the standard diagnostic in typespec compiler 5. some refactor on error/warning code and message, group some to same code, etc. 6. add `target` to diagnostic, when we can find it --- .../emitter/src/code-model-builder.ts | 165 ++++++++++------- .../http-client-java/emitter/src/emitter.ts | 162 ++++------------ .../http-client-java/emitter/src/index.ts | 5 +- packages/http-client-java/emitter/src/lib.ts | 173 ++++++++++++++++++ .../http-client-java/emitter/src/utils.ts | 29 +-- .../http-client-java/emitter/src/validate.ts | 59 +++--- .../package.json | 2 +- .../payload/multipart/FormDataClient.java | 28 +-- .../multipart/FormDataHttpPartsClient.java | 4 +- .../FormDataHttpPartsContentTypeClient.java | 12 +- .../FormDataHttpPartsNonStringClient.java | 4 +- .../http-client-generator-core/pom.xml | 6 + ...ientMethodSerializeItemValueCodeTests.java | 151 +++++++++++++++ .../http-client-generator-test/package.json | 2 +- .../multipart/FormDataAsyncClient.java | 28 +-- .../payload/multipart/FormDataClient.java | 28 +-- .../FormDataHttpPartsAsyncClient.java | 4 +- .../multipart/FormDataHttpPartsClient.java | 4 +- ...rmDataHttpPartsContentTypeAsyncClient.java | 12 +- .../FormDataHttpPartsContentTypeClient.java | 12 +- ...FormDataHttpPartsNonStringAsyncClient.java | 4 +- .../FormDataHttpPartsNonStringClient.java | 4 +- .../tsptest/flatten/FlattenAsyncClient.java | 8 +- .../java/tsptest/flatten/FlattenClient.java | 8 +- .../MultiContentTypesAsyncClient.java | 3 +- .../MultiContentTypesClient.java | 3 +- ...tipleContentTypesOnRequestAsyncClient.java | 15 +- .../MultipleContentTypesOnRequestClient.java | 15 +- .../multipart/MultipartAsyncClient.java | 8 +- .../tsptest/multipart/MultipartClient.java | 8 +- .../typespec/http/client/generator/Main.java | 2 +- packages/http-client-java/package-lock.json | 14 +- packages/http-client-java/package.json | 8 +- 33 files changed, 646 insertions(+), 344 deletions(-) create mode 100644 packages/http-client-java/emitter/src/lib.ts create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java diff --git a/packages/http-client-java/emitter/src/code-model-builder.ts b/packages/http-client-java/emitter/src/code-model-builder.ts index 6b91e02c22..2bfd89326d 100644 --- a/packages/http-client-java/emitter/src/code-model-builder.ts +++ b/packages/http-client-java/emitter/src/code-model-builder.ts @@ -68,16 +68,17 @@ import { SdkUnionType, createSdkContext, getAllModels, - getWireName, isApiVersion, isSdkBuiltInKind, isSdkIntKind, } from "@azure-tools/typespec-client-generator-core"; import { EmitContext, + Interface, Model, ModelProperty, Namespace, + NoTarget, Operation, Program, Type, @@ -99,13 +100,7 @@ import { HttpStatusCodesEntry, Visibility, getAuthentication, - getHeaderFieldName, - getPathParamName, - getQueryParamName, isCookieParam, - isHeader, - isPathParam, - isQueryParam, } from "@typespec/http"; import { getSegment } from "@typespec/rest"; import { getAddedOnVersions } from "@typespec/versioning"; @@ -120,8 +115,8 @@ import { ConstantSchema, ConstantValue } from "./common/schemas/constant.js"; import { OrSchema } from "./common/schemas/relationship.js"; import { DurationSchema } from "./common/schemas/time.js"; import { SchemaContext, SchemaUsage } from "./common/schemas/usage.js"; -import { EmitterOptions } from "./emitter.js"; import { createPollOperationDetailsSchema, getFileDetailsSchema } from "./external-schemas.js"; +import { EmitterOptions, createDiagnostic, reportDiagnostic } from "./lib.js"; import { ClientContext } from "./models.js"; import { CONTENT_TYPE_KEY, @@ -148,9 +143,8 @@ import { pushDistinct, } from "./type-utils.js"; import { + DiagnosticError, getNamespace, - logError, - logWarning, pascalCase, removeClientSuffix, stringArrayContainsIgnoreCase, @@ -193,7 +187,10 @@ export class CodeModelBuilder { const service = listServices(this.program)[0]; if (!service) { - this.logWarning("TypeSpec for HTTP client should define a service."); + reportDiagnostic(this.program, { + code: "no-service", + target: NoTarget, + }); } this.serviceNamespace = service?.type ?? this.program.getGlobalNamespaceType(); @@ -259,7 +256,7 @@ export class CodeModelBuilder { // TODO: it is not very likely, but different client could have different auth const auth = getAuthentication(this.program, this.serviceNamespace); if (auth) { - this.processAuth(auth); + this.processAuth(auth, this.serviceNamespace); } if (this.sdkContext.arm) { @@ -315,7 +312,7 @@ export class CodeModelBuilder { return hostParameters; } - private processAuth(auth: Authentication) { + private processAuth(auth: Authentication, serviceNamespace: Namespace | Interface | Operation) { const securitySchemes: SecurityScheme[] = []; for (const option of auth.options) { for (const scheme of option.schemes) { @@ -332,7 +329,11 @@ export class CodeModelBuilder { securitySchemes.push(oauth2Scheme); } else { // there is no TokenCredential in clientcore, hence use Bearer Authentication directly - this.logWarning(`OAuth2 auth scheme is generated as KeyCredential.`); + reportDiagnostic(this.program, { + code: "auth-scheme-not-supported", + messageId: "oauth2Unbranded", + target: serviceNamespace, + }); const keyScheme = new KeySecurityScheme({ name: "authorization", @@ -351,9 +352,11 @@ export class CodeModelBuilder { }); securitySchemes.push(keyScheme); } else { - this.logWarning( - `ApiKey auth is currently only supported for ApiKeyLocation.header.`, - ); + reportDiagnostic(this.program, { + code: "auth-scheme-not-supported", + messageId: "apiKeyLocation", + target: serviceNamespace, + }); } } break; @@ -367,9 +370,12 @@ export class CodeModelBuilder { if (this.isBranded()) { // Azure would not allow BasicAuth or BearerAuth - this.logWarning( - `HTTP auth with ${scheme.scheme} scheme is not supported for Azure.`, - ); + reportDiagnostic(this.program, { + code: "auth-scheme-not-supported", + messageId: "basicAuthBranded", + format: { scheme: scheme.scheme }, + target: serviceNamespace, + }); continue; } } @@ -561,7 +567,11 @@ export class CodeModelBuilder { } else { this.apiVersion = versions.find((it: string) => it === this.sdkContext.apiVersion); if (!this.apiVersion) { - this.logError("Unrecognized api-version: " + this.sdkContext.apiVersion); + reportDiagnostic(this.program, { + code: "invalid-api-version", + format: { apiVersion: this.sdkContext.apiVersion }, + target: NoTarget, + }); } } @@ -593,7 +603,10 @@ export class CodeModelBuilder { } } } else if (initializationProperty.type.variantTypes.length > 2) { - this.logError("Multiple server URL defined for one client is not supported yet."); + reportDiagnostic(this.program, { + code: "multiple-server-not-supported", + target: initializationProperty.type.__raw ?? NoTarget, + }); } } else if (initializationProperty.type.kind === "endpoint") { sdkPathParameters = initializationProperty.type.templateArguments; @@ -830,36 +843,51 @@ export class CodeModelBuilder { let generateConvenienceApi: boolean = sdkMethod.generateConvenient; let generateProtocolApi: boolean = sdkMethod.generateProtocol; - let apiComment: string | undefined = undefined; + let diagnostic = undefined; if (generateConvenienceApi) { // check if the convenience API need to be disabled for some special cases if (operationIsMultipart(httpOperation)) { // do not generate protocol method for multipart/form-data, as it be very hard for user to prepare the request body as BinaryData generateProtocolApi = false; - apiComment = `Protocol API requires serialization of parts with content-disposition and data, as operation '${operationName}' is 'multipart/form-data'`; - this.logWarning(apiComment); + diagnostic = createDiagnostic({ + code: "protocol-api-not-generated", + messageId: "multipartFormData", + format: { operationName: operationName }, + target: sdkMethod.__raw ?? NoTarget, + }); + this.program.reportDiagnostic(diagnostic); } else if (operationIsMultipleContentTypes(httpOperation)) { // and multiple content types // issue link: https://github.com/Azure/autorest.java/issues/1958#issuecomment-1562558219 generateConvenienceApi = false; - apiComment = `Convenience API is not generated, as operation '${operationName}' is multiple content-type`; - this.logWarning(apiComment); + diagnostic = createDiagnostic({ + code: "convenience-api-not-generated", + messageId: "multipleContentType", + format: { operationName: operationName }, + target: sdkMethod.__raw ?? NoTarget, + }); + this.program.reportDiagnostic(diagnostic); } else if ( operationIsJsonMergePatch(httpOperation) && this.options["stream-style-serialization"] === false ) { // do not generate convenient method for json merge patch operation if stream-style-serialization is not enabled generateConvenienceApi = false; - apiComment = `Convenience API is not generated, as operation '${operationName}' is 'application/merge-patch+json' and stream-style-serialization is not enabled`; - this.logWarning(apiComment); + diagnostic = createDiagnostic({ + code: "convenience-api-not-generated", + messageId: "jsonMergePatch", + format: { operationName: operationName }, + target: sdkMethod.__raw ?? NoTarget, + }); + this.program.reportDiagnostic(diagnostic); } } if (generateConvenienceApi && convenienceApiName) { codeModelOperation.convenienceApi = new ConvenienceApi(convenienceApiName); } - if (apiComment) { + if (diagnostic) { codeModelOperation.language.java = new Language(); - codeModelOperation.language.java.comment = apiComment; + codeModelOperation.language.java.comment = diagnostic.message; } // check for generating protocol api or not @@ -1081,11 +1109,12 @@ export class CodeModelBuilder { lroMetadata.finalResponse.envelopeResult.properties?.forEach((p) => { // TODO: "p.__raw?.name" should be "p.name", after TCGC fix https://github.com/Azure/typespec-azure/issues/2072 if ( + !finalResultPropertySerializedName && p.kind === "property" && - p.serializedName && + p.serializationOptions.json?.name && p.__raw?.name === finalResultPropertyClientName ) { - finalResultPropertySerializedName = p.serializedName; + finalResultPropertySerializedName = p.serializationOptions.json?.name; } }); } @@ -1247,7 +1276,11 @@ export class CodeModelBuilder { default: if (format) { - this.logWarning(`Unrecognized header parameter format: '${format}'.`); + reportDiagnostic(this.program, { + code: "header-parameter-format-not-supported", + format: { format: format }, + target: param.__raw ?? NoTarget, + }); } break; } @@ -1879,9 +1912,12 @@ export class CodeModelBuilder { } } } - const errorMsg = `Unrecognized type: '${type.kind}'.`; - this.logError(errorMsg); - throw new Error(errorMsg); + const diagnostic = createDiagnostic({ + code: "unrecognized-type", + format: { typeKind: type.kind }, + target: type.__raw ?? NoTarget, + }); + throw new DiagnosticError(diagnostic); } private processBuiltInType(type: SdkBuiltInType, nameHint: string): Schema { @@ -2295,24 +2331,38 @@ export class CodeModelBuilder { schema = this.processSchema(nonNullType, ""); } + const getPropertySerializedName = (property: SdkBodyModelPropertyType) => { + // TODO: remove the "property.serializedName" after bug https://github.com/microsoft/typespec/pull/5702 is fixed + return ( + property.serializationOptions.json?.name ?? + property.serializationOptions.multipart?.name ?? + property.serializedName + ); + }; + return new Property(prop.name, prop.doc ?? "", schema, { summary: prop.summary, required: !prop.optional, nullable: nullable, readOnly: this.isReadOnly(prop), - serializedName: prop.kind === "property" ? prop.serializedName : undefined, + serializedName: prop.kind === "property" ? getPropertySerializedName(prop) : undefined, extensions: extensions, }); } private processUnionSchema(type: SdkUnionType, name: string): Schema { if (!(type.__raw && type.__raw.kind === "Union")) { - this.logError(`Invalid type for union: '${type.kind}'.`); + reportDiagnostic(this.program, { + code: "unrecognized-type", + messageId: "unionType", + format: { typeKind: type.kind }, + target: type.__raw ?? NoTarget, + }); } const rawUnionType: Union = type.__raw as Union; const namespace = getNamespace(rawUnionType); const baseName = type.name ?? pascalCase(name) + "Model"; - this.logWarning( + this.trace( `Convert TypeSpec Union '${getUnionDescription(rawUnionType, this.typeNameOptions)}' to Class '${baseName}'`, ); const unionSchema = new OrSchema(baseName + "Base", type.doc ?? "", { @@ -2360,7 +2410,7 @@ export class CodeModelBuilder { private getUnionVariantName(type: Type | undefined, option: any): string { if (type === undefined) { - this.logWarning("Union variant type is undefined."); + this.trace("Union variant type is undefined."); return "UnionVariant"; } switch (type.kind) { @@ -2413,7 +2463,7 @@ export class CodeModelBuilder { case "UnionVariant": return (typeof type.name === "string" ? type.name : undefined) ?? "UnionVariant"; default: - this.logWarning(`Unrecognized type for union variable: '${type.kind}'.`); + this.trace(`Unrecognized type for union variable: '${type.kind}'.`); return "UnionVariant"; } } @@ -2461,9 +2511,13 @@ export class CodeModelBuilder { }, ); } else { - const errorMsg = `Invalid type for multipart form data: '${property.type.kind}'.`; - this.logError(errorMsg); - throw new Error(errorMsg); + const diagnostic = createDiagnostic({ + code: "unrecognized-type", + messageId: "multipartFormData", + format: { typeKind: property.type.kind }, + target: property.type.__raw ?? NoTarget, + }); + throw new DiagnosticError(diagnostic); } } @@ -2475,19 +2529,6 @@ export class CodeModelBuilder { return target ? getSummary(this.program, target) : undefined; } - private getSerializedName(target: ModelProperty): string { - if (isHeader(this.program, target)) { - return getHeaderFieldName(this.program, target); - } else if (isQueryParam(this.program, target)) { - return getQueryParamName(this.program, target); - } else if (isPathParam(this.program, target)) { - return getPathParamName(this.program, target); - } else { - // TODO: currently this is only for JSON - return getWireName(this.sdkContext, target); - } - } - private isReadOnly(target: SdkModelPropertyType): boolean { const segment = target.__raw ? getSegment(this.program, target.__raw) !== undefined : false; if (segment) { @@ -2618,14 +2659,6 @@ export class CodeModelBuilder { } } - private logError(msg: string) { - logError(this.program, msg); - } - - private logWarning(msg: string) { - logWarning(this.program, msg); - } - private trace(msg: string) { trace(this.program, msg); } diff --git a/packages/http-client-java/emitter/src/emitter.ts b/packages/http-client-java/emitter/src/emitter.ts index 8c8929bc97..fb47cc4cb1 100644 --- a/packages/http-client-java/emitter/src/emitter.ts +++ b/packages/http-client-java/emitter/src/emitter.ts @@ -1,124 +1,19 @@ -import { - createTypeSpecLibrary, - EmitContext, - getNormalizedAbsolutePath, - JSONSchemaType, - resolvePath, -} from "@typespec/compiler"; +import { EmitContext, getNormalizedAbsolutePath, NoTarget, resolvePath } from "@typespec/compiler"; import { promises } from "fs"; import { dump } from "js-yaml"; import { dirname } from "path"; import { fileURLToPath } from "url"; import { CodeModelBuilder } from "./code-model-builder.js"; import { CodeModel } from "./common/code-model.js"; -import { logError, spawnAsync, SpawnError } from "./utils.js"; -import { - CODE_JAVA_SDK_DEPENDENCY, - JDK_NOT_FOUND_MESSAGE, - validateDependencies, -} from "./validate.js"; - -export interface EmitterOptions { - namespace?: string; - "package-dir"?: string; - - flavor?: string; - - "service-name"?: string; - "service-versions"?: string[]; - - "skip-special-headers"?: string[]; - - "generate-samples"?: boolean; - "generate-tests"?: boolean; - - "enable-sync-stack"?: boolean; - "stream-style-serialization"?: boolean; - "use-object-for-unknown"?: boolean; - - "partial-update"?: boolean; - "models-subpackage"?: string; - "custom-types"?: string; - "custom-types-subpackage"?: string; - "customization-class"?: string; - polling?: any; - - "group-etag-headers"?: boolean; - - "enable-subclient"?: boolean; - - "advanced-versioning"?: boolean; - "api-version"?: string; - "service-version-exclude-preview"?: boolean; - - "dev-options"?: DevOptions; -} - -export interface DevOptions { - "generate-code-model"?: boolean; - debug?: boolean; - loglevel?: "off" | "debug" | "info" | "warn" | "error"; - "java-temp-dir"?: string; // working directory for java codegen, e.g. transformed code-model file -} +import { EmitterOptions, LibName, reportDiagnostic } from "./lib.js"; +import { DiagnosticError, spawnAsync, SpawnError, trace } from "./utils.js"; +import { validateDependencies } from "./validate.js"; type CodeModelEmitterOptions = EmitterOptions & { "output-dir": string; arm?: boolean; }; -const EmitterOptionsSchema: JSONSchemaType = { - type: "object", - additionalProperties: true, - properties: { - namespace: { type: "string", nullable: true }, - "package-dir": { type: "string", nullable: true }, - - flavor: { type: "string", nullable: true }, - - // service - "service-name": { type: "string", nullable: true }, - "service-versions": { type: "array", items: { type: "string" }, nullable: true }, - - // header - "skip-special-headers": { type: "array", items: { type: "string" }, nullable: true }, - - // sample and test - "generate-samples": { type: "boolean", nullable: true, default: true }, - "generate-tests": { type: "boolean", nullable: true, default: true }, - - "enable-sync-stack": { type: "boolean", nullable: true, default: true }, - "stream-style-serialization": { type: "boolean", nullable: true, default: true }, - "use-object-for-unknown": { type: "boolean", nullable: true, default: false }, - - // customization - "partial-update": { type: "boolean", nullable: true, default: false }, - "models-subpackage": { type: "string", nullable: true }, - "custom-types": { type: "string", nullable: true }, - "custom-types-subpackage": { type: "string", nullable: true }, - "customization-class": { type: "string", nullable: true }, - polling: { type: "object", additionalProperties: true, nullable: true }, - - "group-etag-headers": { type: "boolean", nullable: true }, - - "enable-subclient": { type: "boolean", nullable: true, default: false }, - - "advanced-versioning": { type: "boolean", nullable: true, default: false }, - "api-version": { type: "string", nullable: true }, - "service-version-exclude-preview": { type: "boolean", nullable: true, default: false }, - - "dev-options": { type: "object", additionalProperties: true, nullable: true }, - }, - required: [], -}; - -export const $lib = createTypeSpecLibrary({ - name: "@typespec/http-client-java", - diagnostics: {}, - emitter: { - options: EmitterOptionsSchema, - }, -}); - export async function $onEmit(context: EmitContext) { const program = context.program; if (!program.compilerOptions.noEmit) { @@ -128,7 +23,7 @@ export async function $onEmit(context: EmitContext) { if (!program.hasError()) { const options = context.options; if (!options["flavor"]) { - if ($lib.name === "@azure-tools/typespec-java") { + if (LibName === "@azure-tools/typespec-java") { options["flavor"] = "azure"; } } @@ -138,7 +33,18 @@ export async function $onEmit(context: EmitContext) { const builder = new CodeModelBuilder(program, context); codeModel = await builder.build(); } catch (error: any) { - logError(program, error.message); + if (error instanceof DiagnosticError) { + // diagnostic thrown as error + program.reportDiagnostic(error.diagnostic); + } else { + // unknown error + reportDiagnostic(program, { + code: "unknown-error", + format: { errorMessage: error.message }, + target: NoTarget, + }); + trace(program, error.stack); + } } if (codeModel && !program.hasError() && !program.compilerOptions.noEmit) { @@ -157,24 +63,28 @@ export async function $onEmit(context: EmitContext) { await promises.mkdir(outputPath, { recursive: true }).catch((err) => { if (err.code !== "EISDIR" && err.code !== "EEXIST") { - logError(program, `Failed to create output directory: ${outputPath}`); + reportDiagnostic(program, { + code: "unknown-error", + format: { errorMessage: `Failed to create output directory: ${outputPath}.` }, + target: NoTarget, + }); return; } }); await program.host.writeFile(codeModelFileName, dump(codeModel)); - program.trace("http-client-java", `Code model file written to ${codeModelFileName}`); + trace(program, `Code model file written to ${codeModelFileName}`); const emitterOptions = JSON.stringify(options); - program.trace("http-client-java", `Emitter options ${emitterOptions}`); + trace(program, `Emitter options ${emitterOptions}`); const jarFileName = resolvePath( moduleRoot, "generator/http-client-generator/target", "emitter.jar", ); - program.trace("http-client-java", `Exec JAR ${jarFileName}`); + trace(program, `Exec JAR ${jarFileName}`); const javaArgs: string[] = []; javaArgs.push(`-DemitterOptions=${emitterOptions}`); @@ -194,17 +104,25 @@ export async function $onEmit(context: EmitContext) { javaArgs.push(codeModelFileName); try { const result = await spawnAsync("java", javaArgs, { stdio: "pipe" }); - program.trace("http-client-java", `Code generation log: ${result.stdout}`); + trace(program, `Code generation log: ${result.stdout}`); } catch (error: any) { if (error && "code" in error && error["code"] === "ENOENT") { - logError(program, JDK_NOT_FOUND_MESSAGE, CODE_JAVA_SDK_DEPENDENCY); + reportDiagnostic(program, { + code: "invalid-java-sdk-dependency", + target: NoTarget, + }); } else { - logError( - program, - 'The emitter was unable to generate client code from this TypeSpec, please run this command again with "--trace http-client-java" to get diagnostic information, and open an issue on https://github.com/microsoft/typespec', - ); + // error in Java codegen, report as unknown error + reportDiagnostic(program, { + code: "unknown-error", + format: { + errorMessage: + 'The emitter was unable to generate client code from this TypeSpec, please run this command again with "--trace http-client-java" to get diagnostic information, and open an issue on https://github.com/microsoft/typespec', + }, + target: NoTarget, + }); if (error instanceof SpawnError) { - program.trace("http-client-java", `Code generation error: ${error.stdout}`); + trace(program, `Code generation error: ${error.stdout}`); } } } diff --git a/packages/http-client-java/emitter/src/index.ts b/packages/http-client-java/emitter/src/index.ts index cd5bcc0701..82206f8725 100644 --- a/packages/http-client-java/emitter/src/index.ts +++ b/packages/http-client-java/emitter/src/index.ts @@ -1 +1,4 @@ -export * from "./emitter.js"; +// $onEmit is the entry of the emitter +export { $onEmit } from "./emitter.js"; +// emit options interface is required to be exported +export { $lib, DevOptions, EmitterOptions } from "./lib.js"; diff --git a/packages/http-client-java/emitter/src/lib.ts b/packages/http-client-java/emitter/src/lib.ts new file mode 100644 index 0000000000..05cf2d29fc --- /dev/null +++ b/packages/http-client-java/emitter/src/lib.ts @@ -0,0 +1,173 @@ +import { createTypeSpecLibrary, JSONSchemaType, paramMessage } from "@typespec/compiler"; + +export interface DevOptions { + "generate-code-model"?: boolean; + debug?: boolean; + loglevel?: "off" | "debug" | "info" | "warn" | "error"; + "java-temp-dir"?: string; // working directory for java codegen, e.g. transformed code-model file +} + +export interface EmitterOptions { + namespace?: string; + "package-dir"?: string; + + flavor?: string; + + "service-name"?: string; + "service-versions"?: string[]; + + "skip-special-headers"?: string[]; + + "generate-samples"?: boolean; + "generate-tests"?: boolean; + + "enable-sync-stack"?: boolean; + "stream-style-serialization"?: boolean; + "use-object-for-unknown"?: boolean; + + "partial-update"?: boolean; + "models-subpackage"?: string; + "custom-types"?: string; + "custom-types-subpackage"?: string; + "customization-class"?: string; + polling?: any; + + "group-etag-headers"?: boolean; + + "enable-subclient"?: boolean; + + "advanced-versioning"?: boolean; + "api-version"?: string; + "service-version-exclude-preview"?: boolean; + + "dev-options"?: DevOptions; +} + +const EmitterOptionsSchema: JSONSchemaType = { + type: "object", + additionalProperties: true, + properties: { + namespace: { type: "string", nullable: true }, + "package-dir": { type: "string", nullable: true }, + + flavor: { type: "string", nullable: true }, + + // service + "service-name": { type: "string", nullable: true }, + "service-versions": { type: "array", items: { type: "string" }, nullable: true }, + + // header + "skip-special-headers": { type: "array", items: { type: "string" }, nullable: true }, + + // sample and test + "generate-samples": { type: "boolean", nullable: true, default: true }, + "generate-tests": { type: "boolean", nullable: true, default: true }, + + "enable-sync-stack": { type: "boolean", nullable: true, default: true }, + "stream-style-serialization": { type: "boolean", nullable: true, default: true }, + "use-object-for-unknown": { type: "boolean", nullable: true, default: false }, + + // customization + "partial-update": { type: "boolean", nullable: true, default: false }, + "models-subpackage": { type: "string", nullable: true }, + "custom-types": { type: "string", nullable: true }, + "custom-types-subpackage": { type: "string", nullable: true }, + "customization-class": { type: "string", nullable: true }, + polling: { type: "object", additionalProperties: true, nullable: true }, + + "group-etag-headers": { type: "boolean", nullable: true }, + + "enable-subclient": { type: "boolean", nullable: true, default: false }, + + "advanced-versioning": { type: "boolean", nullable: true, default: false }, + "api-version": { type: "string", nullable: true }, + "service-version-exclude-preview": { type: "boolean", nullable: true, default: false }, + + "dev-options": { type: "object", additionalProperties: true, nullable: true }, + }, + required: [], +}; + +export const $lib = createTypeSpecLibrary({ + name: "@typespec/http-client-java", + diagnostics: { + // error + "unknown-error": { + severity: "error", + messages: { + default: paramMessage`An unknown error occurred. '${"errorMessage"}'`, + }, + }, + "invalid-java-sdk-dependency": { + severity: "error", + messages: { + default: + "Java Development Kit (JDK) is not found in PATH. Please install JDK 17 or above. Microsoft Build of OpenJDK can be downloaded from https://learn.microsoft.com/java/openjdk/download", + jdkVersion: paramMessage`Java Development Kit (JDK) in PATH is version '${"javaVersion"}'. Please install JDK 17 or above. Microsoft Build of OpenJDK can be downloaded from https://learn.microsoft.com/java/openjdk/download`, + maven: + "Apache Maven is not found in PATH. Apache Maven can be downloaded from https://maven.apache.org/download.cgi", + }, + }, + "multiple-server-not-supported": { + severity: "error", + messages: { + default: "Multiple server on client is not supported.", + }, + }, + "invalid-api-version": { + severity: "error", + messages: { + default: paramMessage`Invalid api-version option: '${"apiVersion"}'. The value should be an api-version, 'latest', or 'all'.`, + }, + }, + "unrecognized-type": { + severity: "error", + messages: { + default: paramMessage`Unrecognized type, kind '${"typeKind"}'. Updating the version of the emitter may resolve this issue.`, + unionType: paramMessage`Unrecognized type for Union, kind '${"typeKind"}'.`, + multipartFormData: paramMessage`Unrecognized type for multipart form data, kind '${"typeKind"}'.`, + }, + }, + + // warning + "no-service": { + severity: "warning", + messages: { + default: "No service found in this TypeSpec. Client will not be generated.", + }, + }, + "auth-scheme-not-supported": { + severity: "warning", + messages: { + oauth2Unbranded: + "OAuth2 auth scheme is not supported in unbranded. Client builder will fallback to use KeyCredential.", + apiKeyLocation: "ApiKey auth is currently only supported for ApiKeyLocation.header.", + basicAuthBranded: paramMessage`HTTP auth with '${"scheme"}' scheme is not supported for Azure. Azure service should use Oauth2Auth or ApiKeyAuth.`, + }, + }, + "protocol-api-not-generated": { + severity: "warning", + messages: { + multipartFormData: paramMessage`Operation '${"operationName"}' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not generated.`, + }, + }, + "convenience-api-not-generated": { + severity: "warning", + messages: { + multipleContentType: paramMessage`Operation '${"operationName"}' can be invoked with multiple content-type. It is difficult to form a correct method signature for convenience API, and hence the convenience API is not generated.`, + jsonMergePatch: paramMessage`Operation '${"operationName"}' is of content-type 'application/merge-patch+json'. Enable 'stream-style-serialization' in emitter options.`, + }, + }, + "header-parameter-format-not-supported": { + severity: "warning", + messages: { + default: paramMessage`Header parameter format '${"format"}' is not supported.`, + }, + }, + }, + emitter: { + options: EmitterOptionsSchema as JSONSchemaType, + }, +} as const); + +export const { name: LibName, reportDiagnostic, createDiagnostic, getTracer } = $lib; diff --git a/packages/http-client-java/emitter/src/utils.ts b/packages/http-client-java/emitter/src/utils.ts index b70ace8bc7..62ced52e78 100644 --- a/packages/http-client-java/emitter/src/utils.ts +++ b/packages/http-client-java/emitter/src/utils.ts @@ -1,24 +1,6 @@ -import { NoTarget, Program, Type } from "@typespec/compiler"; +import { Diagnostic, Program, Type } from "@typespec/compiler"; import { spawn, SpawnOptions } from "child_process"; -export function logError(program: Program, msg: string, code: string = "http-client-java") { - program.reportDiagnostic({ - code: code, - severity: "error", - message: msg, - target: NoTarget, - }); -} - -export function logWarning(program: Program, msg: string, code: string = "http-client-java") { - program.reportDiagnostic({ - code: code, - severity: "warning", - message: msg, - target: NoTarget, - }); -} - export function trace(program: Program, msg: string) { program.trace("http-client-java", msg); } @@ -79,6 +61,15 @@ export class SpawnError extends Error { } } +export class DiagnosticError extends Error { + diagnostic: Diagnostic; + + constructor(diagnostic: Diagnostic) { + super(diagnostic.message); + this.diagnostic = diagnostic; + } +} + export async function spawnAsync( command: string, args: readonly string[], diff --git a/packages/http-client-java/emitter/src/validate.ts b/packages/http-client-java/emitter/src/validate.ts index a624b8bd21..ab9e7e0d9e 100644 --- a/packages/http-client-java/emitter/src/validate.ts +++ b/packages/http-client-java/emitter/src/validate.ts @@ -1,5 +1,6 @@ -import { Program } from "@typespec/compiler"; -import { logError, spawnAsync, trace } from "./utils.js"; +import { NoTarget, Program } from "@typespec/compiler"; +import { reportDiagnostic } from "./lib.js"; +import { spawnAsync, trace } from "./utils.js"; export const JDK_NOT_FOUND_MESSAGE = "Java Development Kit (JDK) is not found in PATH. Please install JDK 17 or above. Microsoft Build of OpenJDK can be downloaded from https://learn.microsoft.com/java/openjdk/download"; @@ -21,23 +22,32 @@ export async function validateDependencies( if (javaMajorVersion < 11) { // the message is JDK 17, because clientcore depends on JDK 17 // emitter only require JDK 11 - const message = `Java Development Kit (JDK) in PATH is version ${javaVersion}. Please install JDK 17 or above. Microsoft Build of OpenJDK can be downloaded from https://learn.microsoft.com/java/openjdk/download`; - // // eslint-disable-next-line no-console - // console.log("[ERROR] " + message); if (program && logDiagnostic) { - logError(program, message, CODE_JAVA_SDK_DEPENDENCY); + reportDiagnostic(program, { + code: "invalid-java-sdk-dependency", + messageId: "jdkVersion", + format: { javaVersion: javaVersion }, + target: NoTarget, + }); } } } } catch (error: any) { - let message = error.message; if (error && "code" in error && error["code"] === "ENOENT") { - message = JDK_NOT_FOUND_MESSAGE; - } - // // eslint-disable-next-line no-console - // console.log("[ERROR] " + message); - if (program && logDiagnostic) { - logError(program, message, CODE_JAVA_SDK_DEPENDENCY); + if (program && logDiagnostic) { + reportDiagnostic(program, { + code: "invalid-java-sdk-dependency", + target: NoTarget, + }); + } + } else { + if (program && logDiagnostic) { + reportDiagnostic(program, { + code: "unknown-error", + format: { errorMessage: error.message }, + target: NoTarget, + }); + } } } @@ -53,15 +63,22 @@ export async function validateDependencies( } } } catch (error: any) { - let message = error.message; if (shell || (error && "code" in error && error["code"] === "ENOENT")) { - message = - "Apache Maven is not found in PATH. Apache Maven can be downloaded from https://maven.apache.org/download.cgi"; - } - // // eslint-disable-next-line no-console - // console.log("[ERROR] " + message); - if (program && logDiagnostic) { - logError(program, message, CODE_JAVA_SDK_DEPENDENCY); + if (program && logDiagnostic) { + reportDiagnostic(program, { + code: "invalid-java-sdk-dependency", + messageId: "maven", + target: NoTarget, + }); + } + } else { + if (program && logDiagnostic) { + reportDiagnostic(program, { + code: "unknown-error", + format: { errorMessage: error.message }, + target: NoTarget, + }); + } } } } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json index a2f53b6041..c84a413913 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json @@ -24,7 +24,7 @@ "@typespec/openapi": "~0.64.0", "@typespec/xml": "~0.64.0", "@azure-tools/typespec-azure-core": "~0.50.0", - "@azure-tools/typespec-client-generator-core": "~0.50.0", + "@azure-tools/typespec-client-generator-core": "~0.50.2", "@azure-tools/typespec-azure-resource-manager": "~0.50.0", "@azure-tools/typespec-autorest": "~0.50.0" }, diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataClient.java index ca0d882cbd..a6cc97be4d 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataClient.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataClient.java @@ -41,8 +41,8 @@ public final class FormDataClient { */ @Metadata(generated = true) Response basicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'basic' is - // 'multipart/form-data' + // Operation 'basic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.basicWithResponse(body, requestOptions); } @@ -56,8 +56,8 @@ Response basicWithResponse(BinaryData body, RequestOptions requestOptions) */ @Metadata(generated = true) Response fileArrayAndBasicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'fileArrayAndBasic' is 'multipart/form-data' + // Operation 'fileArrayAndBasic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.fileArrayAndBasicWithResponse(body, requestOptions); } @@ -71,8 +71,8 @@ Response fileArrayAndBasicWithResponse(BinaryData body, RequestOptions req */ @Metadata(generated = true) Response jsonPartWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'jsonPart' is - // 'multipart/form-data' + // Operation 'jsonPart' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.jsonPartWithResponse(body, requestOptions); } @@ -86,8 +86,8 @@ Response jsonPartWithResponse(BinaryData body, RequestOptions requestOptio */ @Metadata(generated = true) Response binaryArrayPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'binaryArrayParts' is 'multipart/form-data' + // Operation 'binaryArrayParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.binaryArrayPartsWithResponse(body, requestOptions); } @@ -101,8 +101,8 @@ Response binaryArrayPartsWithResponse(BinaryData body, RequestOptions requ */ @Metadata(generated = true) Response multiBinaryPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'multiBinaryParts' is 'multipart/form-data' + // Operation 'multiBinaryParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.multiBinaryPartsWithResponse(body, requestOptions); } @@ -116,8 +116,8 @@ Response multiBinaryPartsWithResponse(BinaryData body, RequestOptions requ */ @Metadata(generated = true) Response checkFileNameAndContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'checkFileNameAndContentType' is 'multipart/form-data' + // Operation 'checkFileNameAndContentType' is of content-type 'multipart/form-data'. Protocol API is not usable + // and hence not generated. return this.serviceClient.checkFileNameAndContentTypeWithResponse(body, requestOptions); } @@ -131,8 +131,8 @@ Response checkFileNameAndContentTypeWithResponse(BinaryData body, RequestO */ @Metadata(generated = true) Response anonymousModelWithResponse(BinaryData anonymousModelRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'anonymousModel' - // is 'multipart/form-data' + // Operation 'anonymousModel' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.anonymousModelWithResponse(anonymousModelRequest, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java index fa3b2c53cd..fb3ee97c58 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java @@ -40,8 +40,8 @@ public final class FormDataHttpPartsClient { */ @Metadata(generated = true) Response jsonArrayAndFileArrayWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'jsonArrayAndFileArray' is 'multipart/form-data' + // Operation 'jsonArrayAndFileArray' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.jsonArrayAndFileArrayWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java index d95396ad70..36abcaee8a 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java @@ -39,8 +39,8 @@ public final class FormDataHttpPartsContentTypeClient { */ @Metadata(generated = true) Response imageJpegContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'imageJpegContentType' is 'multipart/form-data' + // Operation 'imageJpegContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.imageJpegContentTypeWithResponse(body, requestOptions); } @@ -54,8 +54,8 @@ Response imageJpegContentTypeWithResponse(BinaryData body, RequestOptions */ @Metadata(generated = true) Response requiredContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'requiredContentType' is 'multipart/form-data' + // Operation 'requiredContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.requiredContentTypeWithResponse(body, requestOptions); } @@ -69,8 +69,8 @@ Response requiredContentTypeWithResponse(BinaryData body, RequestOptions r */ @Metadata(generated = true) Response optionalContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'optionalContentType' is 'multipart/form-data' + // Operation 'optionalContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.optionalContentTypeWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java index ba5c106c2a..16bff5bdbc 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java @@ -40,8 +40,8 @@ public final class FormDataHttpPartsNonStringClient { */ @Metadata(generated = true) Response floatMethodWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'float' is - // 'multipart/form-data' + // Operation 'float' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.floatMethodWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-core/pom.xml b/packages/http-client-java/generator/http-client-generator-core/pom.xml index b65210b561..a883b2f816 100644 --- a/packages/http-client-java/generator/http-client-generator-core/pom.xml +++ b/packages/http-client-java/generator/http-client-generator-core/pom.xml @@ -95,6 +95,12 @@ 5.11.2 test + + io.clientcore + core + 1.0.0-beta.2 + test + org.junit.jupiter junit-jupiter-engine diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java new file mode 100644 index 0000000000..d040660ce5 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.typespec.http.client.generator.core.template; + +import com.azure.core.annotation.Generated; +import com.azure.core.util.ExpandableEnum; +import io.clientcore.core.util.binarydata.BinaryData; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ClientMethodSerializeItemValueCodeTests { + + @Test + public void testClientMethodSerializeItemValueCode() { + // code from resources/ClientMethodSerializeItemValue.java + Function testCode = paramItemValue -> { + if (paramItemValue == null) { + return ""; + } else { + String itemValueString = BinaryData.fromObject(paramItemValue).toString(); + int strLength = itemValueString.length(); + int startOffset = 0; + while (startOffset < strLength) { + if (itemValueString.charAt(startOffset) != '"') { + break; + } + startOffset++; + } + if (startOffset == strLength) { + return ""; + } + int endOffset = strLength - 1; + while (endOffset >= 0) { + if (itemValueString.charAt(endOffset) != '"') { + break; + } + + endOffset--; + } + return itemValueString.substring(startOffset, endOffset + 1); + } + }; + + Function, String> serializeCsvCode + = paramItems -> paramItems.stream().map(testCode).collect(Collectors.joining(",")); + + // Long + Assertions.assertEquals("1,2,3", serializeCsvCode.apply(List.of(1L, 2L, 3L))); + + // String + Assertions.assertEquals("a,b,c", serializeCsvCode.apply(List.of("a", "b", "c"))); + + // Enum + Assertions.assertEquals("0,100", serializeCsvCode.apply(List.of(PriorityModel.LOW, PriorityModel.HIGH))); + + // date-time + Assertions.assertEquals("2025-01-24T07:34:05Z,2024-05-20T00:00:01Z", serializeCsvCode.apply( + List.of(OffsetDateTime.parse("2025-01-24T07:34:05Z"), OffsetDateTime.parse("2024-05-20T00:00:01Z")))); + } + + /** + * Defines values for PriorityModel. + */ + public static final class PriorityModel implements ExpandableEnum { + private static final Map VALUES = new ConcurrentHashMap<>(); + + private static final Function NEW_INSTANCE = PriorityModel::new; + + /** + * Static value 100 for PriorityModel. + */ + @Generated + public static final PriorityModel HIGH = fromValue(100); + + /** + * Static value 0 for PriorityModel. + */ + @Generated + public static final PriorityModel LOW = fromValue(0); + + private final Integer value; + + private PriorityModel(Integer value) { + this.value = value; + } + + /** + * Creates or finds a PriorityModel. + * + * @param value a value to look for. + * @return the corresponding PriorityModel. + * @throws IllegalArgumentException if value is null. + */ + @Generated + public static PriorityModel fromValue(Integer value) { + if (value == null) { + throw new IllegalArgumentException("'value' cannot be null."); + } + return VALUES.computeIfAbsent(value, NEW_INSTANCE); + } + + /** + * Gets known PriorityModel values. + * + * @return Known PriorityModel values. + */ + @Generated + public static Collection values() { + return new ArrayList<>(VALUES.values()); + } + + /** + * Gets the value of the PriorityModel instance. + * + * @return the value of the PriorityModel instance. + */ + @Generated + @Override + public Integer getValue() { + return this.value; + } + + @Generated + @Override + public String toString() { + return Objects.toString(this.value); + } + + @Generated + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Generated + @Override + public int hashCode() { + return Objects.hashCode(this.value); + } + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/package.json b/packages/http-client-java/generator/http-client-generator-test/package.json index 47542ab2ed..b080f744ca 100644 --- a/packages/http-client-java/generator/http-client-generator-test/package.json +++ b/packages/http-client-java/generator/http-client-generator-test/package.json @@ -25,7 +25,7 @@ "@typespec/openapi": "~0.64.0", "@typespec/xml": "~0.64.0", "@azure-tools/typespec-azure-core": "~0.50.0", - "@azure-tools/typespec-client-generator-core": "~0.50.0", + "@azure-tools/typespec-client-generator-core": "~0.50.2", "@azure-tools/typespec-azure-resource-manager": "~0.50.0", "@azure-tools/typespec-autorest": "~0.50.0" }, diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataAsyncClient.java index 0e7f229a0d..693fe07551 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataAsyncClient.java @@ -61,8 +61,8 @@ public final class FormDataAsyncClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> basicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'basic' is - // 'multipart/form-data' + // Operation 'basic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.basicWithResponseAsync(body, requestOptions); } @@ -80,8 +80,8 @@ Mono> basicWithResponse(BinaryData body, RequestOptions requestOp @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> fileArrayAndBasicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'fileArrayAndBasic' is 'multipart/form-data' + // Operation 'fileArrayAndBasic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.fileArrayAndBasicWithResponseAsync(body, requestOptions); } @@ -99,8 +99,8 @@ Mono> fileArrayAndBasicWithResponse(BinaryData body, RequestOptio @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> jsonPartWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'jsonPart' is - // 'multipart/form-data' + // Operation 'jsonPart' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.jsonPartWithResponseAsync(body, requestOptions); } @@ -118,8 +118,8 @@ Mono> jsonPartWithResponse(BinaryData body, RequestOptions reques @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> binaryArrayPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'binaryArrayParts' is 'multipart/form-data' + // Operation 'binaryArrayParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.binaryArrayPartsWithResponseAsync(body, requestOptions); } @@ -137,8 +137,8 @@ Mono> binaryArrayPartsWithResponse(BinaryData body, RequestOption @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> multiBinaryPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'multiBinaryParts' is 'multipart/form-data' + // Operation 'multiBinaryParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.multiBinaryPartsWithResponseAsync(body, requestOptions); } @@ -156,8 +156,8 @@ Mono> multiBinaryPartsWithResponse(BinaryData body, RequestOption @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> checkFileNameAndContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'checkFileNameAndContentType' is 'multipart/form-data' + // Operation 'checkFileNameAndContentType' is of content-type 'multipart/form-data'. Protocol API is not usable + // and hence not generated. return this.serviceClient.checkFileNameAndContentTypeWithResponseAsync(body, requestOptions); } @@ -175,8 +175,8 @@ Mono> checkFileNameAndContentTypeWithResponse(BinaryData body, Re @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> anonymousModelWithResponse(BinaryData anonymousModelRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'anonymousModel' - // is 'multipart/form-data' + // Operation 'anonymousModel' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.anonymousModelWithResponseAsync(anonymousModelRequest, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataClient.java index 72605756fb..2adade27b5 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataClient.java @@ -59,8 +59,8 @@ public final class FormDataClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response basicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'basic' is - // 'multipart/form-data' + // Operation 'basic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.basicWithResponse(body, requestOptions); } @@ -78,8 +78,8 @@ Response basicWithResponse(BinaryData body, RequestOptions requestOptions) @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response fileArrayAndBasicWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'fileArrayAndBasic' is 'multipart/form-data' + // Operation 'fileArrayAndBasic' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.fileArrayAndBasicWithResponse(body, requestOptions); } @@ -97,8 +97,8 @@ Response fileArrayAndBasicWithResponse(BinaryData body, RequestOptions req @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response jsonPartWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'jsonPart' is - // 'multipart/form-data' + // Operation 'jsonPart' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.jsonPartWithResponse(body, requestOptions); } @@ -116,8 +116,8 @@ Response jsonPartWithResponse(BinaryData body, RequestOptions requestOptio @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response binaryArrayPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'binaryArrayParts' is 'multipart/form-data' + // Operation 'binaryArrayParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.binaryArrayPartsWithResponse(body, requestOptions); } @@ -135,8 +135,8 @@ Response binaryArrayPartsWithResponse(BinaryData body, RequestOptions requ @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response multiBinaryPartsWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'multiBinaryParts' is 'multipart/form-data' + // Operation 'multiBinaryParts' is of content-type 'multipart/form-data'. Protocol API is not usable and hence + // not generated. return this.serviceClient.multiBinaryPartsWithResponse(body, requestOptions); } @@ -154,8 +154,8 @@ Response multiBinaryPartsWithResponse(BinaryData body, RequestOptions requ @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response checkFileNameAndContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'checkFileNameAndContentType' is 'multipart/form-data' + // Operation 'checkFileNameAndContentType' is of content-type 'multipart/form-data'. Protocol API is not usable + // and hence not generated. return this.serviceClient.checkFileNameAndContentTypeWithResponse(body, requestOptions); } @@ -173,8 +173,8 @@ Response checkFileNameAndContentTypeWithResponse(BinaryData body, RequestO @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response anonymousModelWithResponse(BinaryData anonymousModelRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'anonymousModel' - // is 'multipart/form-data' + // Operation 'anonymousModel' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.anonymousModelWithResponse(anonymousModelRequest, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsAsyncClient.java index 5f53b61a16..ac78bac81a 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsAsyncClient.java @@ -55,8 +55,8 @@ public final class FormDataHttpPartsAsyncClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> jsonArrayAndFileArrayWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'jsonArrayAndFileArray' is 'multipart/form-data' + // Operation 'jsonArrayAndFileArray' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.jsonArrayAndFileArrayWithResponseAsync(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java index cc6f8dbe3c..2a1059fe70 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsClient.java @@ -53,8 +53,8 @@ public final class FormDataHttpPartsClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response jsonArrayAndFileArrayWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'jsonArrayAndFileArray' is 'multipart/form-data' + // Operation 'jsonArrayAndFileArray' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.jsonArrayAndFileArrayWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeAsyncClient.java index 463c8ff86a..6a7ae8ceec 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeAsyncClient.java @@ -55,8 +55,8 @@ public final class FormDataHttpPartsContentTypeAsyncClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> imageJpegContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'imageJpegContentType' is 'multipart/form-data' + // Operation 'imageJpegContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.imageJpegContentTypeWithResponseAsync(body, requestOptions); } @@ -74,8 +74,8 @@ Mono> imageJpegContentTypeWithResponse(BinaryData body, RequestOp @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> requiredContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'requiredContentType' is 'multipart/form-data' + // Operation 'requiredContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.requiredContentTypeWithResponseAsync(body, requestOptions); } @@ -93,8 +93,8 @@ Mono> requiredContentTypeWithResponse(BinaryData body, RequestOpt @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> optionalContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'optionalContentType' is 'multipart/form-data' + // Operation 'optionalContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.optionalContentTypeWithResponseAsync(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java index e29f7c4f86..ba6a6786b9 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsContentTypeClient.java @@ -53,8 +53,8 @@ public final class FormDataHttpPartsContentTypeClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response imageJpegContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'imageJpegContentType' is 'multipart/form-data' + // Operation 'imageJpegContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.imageJpegContentTypeWithResponse(body, requestOptions); } @@ -72,8 +72,8 @@ Response imageJpegContentTypeWithResponse(BinaryData body, RequestOptions @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response requiredContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'requiredContentType' is 'multipart/form-data' + // Operation 'requiredContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.requiredContentTypeWithResponse(body, requestOptions); } @@ -91,8 +91,8 @@ Response requiredContentTypeWithResponse(BinaryData body, RequestOptions r @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response optionalContentTypeWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation - // 'optionalContentType' is 'multipart/form-data' + // Operation 'optionalContentType' is of content-type 'multipart/form-data'. Protocol API is not usable and + // hence not generated. return this.serviceClient.optionalContentTypeWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringAsyncClient.java index 554bba640d..3bde6e4119 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringAsyncClient.java @@ -53,8 +53,8 @@ public final class FormDataHttpPartsNonStringAsyncClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> floatMethodWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'float' is - // 'multipart/form-data' + // Operation 'float' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.floatMethodWithResponseAsync(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java index a1a88a5bde..a31ef62543 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/payload/multipart/FormDataHttpPartsNonStringClient.java @@ -51,8 +51,8 @@ public final class FormDataHttpPartsNonStringClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response floatMethodWithResponse(BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'float' is - // 'multipart/form-data' + // Operation 'float' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.floatMethodWithResponse(body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenAsyncClient.java index 57c7541eb5..881c2b0431 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenAsyncClient.java @@ -225,8 +225,8 @@ public Mono> updateWithResponse(long id, BinaryData updateR @ServiceMethod(returns = ReturnType.SINGLE) Mono> uploadFileWithResponse(String name, BinaryData uploadFileRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadFile' is - // 'multipart/form-data' + // Operation 'uploadFile' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadFileWithResponseAsync(name, uploadFileRequest, requestOptions); } @@ -244,8 +244,8 @@ Mono> uploadFileWithResponse(String name, BinaryData uploadFileRe @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> uploadTodoWithResponse(BinaryData uploadTodoRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadTodo' is - // 'multipart/form-data' + // Operation 'uploadTodo' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadTodoWithResponseAsync(uploadTodoRequest, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenClient.java index abcd998aac..53d3797c3f 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/flatten/FlattenClient.java @@ -220,8 +220,8 @@ public Response updateWithResponse(long id, BinaryData updateRequest @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response uploadFileWithResponse(String name, BinaryData uploadFileRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadFile' is - // 'multipart/form-data' + // Operation 'uploadFile' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadFileWithResponse(name, uploadFileRequest, requestOptions); } @@ -239,8 +239,8 @@ Response uploadFileWithResponse(String name, BinaryData uploadFileRequest, @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response uploadTodoWithResponse(BinaryData uploadTodoRequest, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadTodo' is - // 'multipart/form-data' + // Operation 'uploadTodo' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadTodoWithResponse(uploadTodoRequest, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesAsyncClient.java index e6797a78d5..5cd3c7365d 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesAsyncClient.java @@ -60,7 +60,8 @@ public final class MultiContentTypesAsyncClient { @ServiceMethod(returns = ReturnType.SINGLE) public Mono> uploadWithOverloadWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadWithOverload' is multiple content-type + // Operation 'uploadWithOverload' can be invoked with multiple content-type. It is difficult to form a correct + // method signature for convenience API, and hence the convenience API is not generated. return this.serviceClient.uploadWithOverloadWithResponseAsync(contentType, data, requestOptions); } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesClient.java index 0d180e1264..9648124a0c 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultiContentTypesClient.java @@ -59,7 +59,8 @@ public final class MultiContentTypesClient { @ServiceMethod(returns = ReturnType.SINGLE) public Response uploadWithOverloadWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadWithOverload' is multiple content-type + // Operation 'uploadWithOverload' can be invoked with multiple content-type. It is difficult to form a correct + // method signature for convenience API, and hence the convenience API is not generated. return this.serviceClient.uploadWithOverloadWithResponse(contentType, data, requestOptions); } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestAsyncClient.java index 4e95de7133..61c77a150a 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestAsyncClient.java @@ -62,8 +62,9 @@ public final class MultipleContentTypesOnRequestAsyncClient { @ServiceMethod(returns = ReturnType.SINGLE) public Mono> uploadBytesWithSingleBodyTypeForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadBytesWithSingleBodyTypeForMultiContentTypes' is - // multiple content-type + // Operation 'uploadBytesWithSingleBodyTypeForMultiContentTypes' can be invoked with multiple content-type. It + // is difficult to form a correct method signature for convenience API, and hence the convenience API is not + // generated. return this.serviceClient.uploadBytesWithSingleBodyTypeForMultiContentTypesWithResponseAsync(contentType, data, requestOptions); } @@ -92,8 +93,9 @@ public Mono> uploadBytesWithSingleBodyTypeForMultiContentTypesWit @ServiceMethod(returns = ReturnType.SINGLE) public Mono> uploadBytesWithMultiBodyTypesForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadBytesWithMultiBodyTypesForMultiContentTypes' is - // multiple content-type + // Operation 'uploadBytesWithMultiBodyTypesForMultiContentTypes' can be invoked with multiple content-type. It + // is difficult to form a correct method signature for convenience API, and hence the convenience API is not + // generated. return this.serviceClient.uploadBytesWithMultiBodyTypesForMultiContentTypesWithResponseAsync(contentType, data, requestOptions); } @@ -151,8 +153,9 @@ public Mono> uploadJsonWithMultiBodyTypesForMultiContentTypesWith @ServiceMethod(returns = ReturnType.SINGLE) public Mono> uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypes' is - // multiple content-type + // Operation 'uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypes' can be invoked with multiple + // content-type. It is difficult to form a correct method signature for convenience API, and hence the + // convenience API is not generated. return this.serviceClient.uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypesWithResponseAsync(contentType, data, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestClient.java index 897df58acb..4756ef09f1 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multicontenttypes/MultipleContentTypesOnRequestClient.java @@ -60,8 +60,9 @@ public final class MultipleContentTypesOnRequestClient { @ServiceMethod(returns = ReturnType.SINGLE) public Response uploadBytesWithSingleBodyTypeForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadBytesWithSingleBodyTypeForMultiContentTypes' is - // multiple content-type + // Operation 'uploadBytesWithSingleBodyTypeForMultiContentTypes' can be invoked with multiple content-type. It + // is difficult to form a correct method signature for convenience API, and hence the convenience API is not + // generated. return this.serviceClient.uploadBytesWithSingleBodyTypeForMultiContentTypesWithResponse(contentType, data, requestOptions); } @@ -90,8 +91,9 @@ public Response uploadBytesWithSingleBodyTypeForMultiContentTypesWithRespo @ServiceMethod(returns = ReturnType.SINGLE) public Response uploadBytesWithMultiBodyTypesForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadBytesWithMultiBodyTypesForMultiContentTypes' is - // multiple content-type + // Operation 'uploadBytesWithMultiBodyTypesForMultiContentTypes' can be invoked with multiple content-type. It + // is difficult to form a correct method signature for convenience API, and hence the convenience API is not + // generated. return this.serviceClient.uploadBytesWithMultiBodyTypesForMultiContentTypesWithResponse(contentType, data, requestOptions); } @@ -148,8 +150,9 @@ public Response uploadJsonWithMultiBodyTypesForMultiContentTypesWithRespon @ServiceMethod(returns = ReturnType.SINGLE) public Response uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypesWithResponse(String contentType, BinaryData data, RequestOptions requestOptions) { - // Convenience API is not generated, as operation 'uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypes' is - // multiple content-type + // Operation 'uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypes' can be invoked with multiple + // content-type. It is difficult to form a correct method signature for convenience API, and hence the + // convenience API is not generated. return this.serviceClient.uploadJsonOrBytesWithMultiBodyTypesForMultiContentTypesWithResponse(contentType, data, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartAsyncClient.java index 8932e3602d..e1809c50ac 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartAsyncClient.java @@ -65,8 +65,8 @@ public final class MultipartAsyncClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> uploadWithResponse(String name, BinaryData data, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'upload' is - // 'multipart/form-data' + // Operation 'upload' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadWithResponseAsync(name, data, requestOptions); } @@ -92,8 +92,8 @@ Mono> uploadWithResponse(String name, BinaryData data, RequestOpt @Generated @ServiceMethod(returns = ReturnType.SINGLE) Mono> uploadHttpPartWithResponse(String name, BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadHttpPart' - // is 'multipart/form-data' + // Operation 'uploadHttpPart' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadHttpPartWithResponseAsync(name, body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartClient.java index 36bc7a83d1..35578997a4 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/multipart/MultipartClient.java @@ -63,8 +63,8 @@ public final class MultipartClient { @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response uploadWithResponse(String name, BinaryData data, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'upload' is - // 'multipart/form-data' + // Operation 'upload' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadWithResponse(name, data, requestOptions); } @@ -90,8 +90,8 @@ Response uploadWithResponse(String name, BinaryData data, RequestOptions r @Generated @ServiceMethod(returns = ReturnType.SINGLE) Response uploadHttpPartWithResponse(String name, BinaryData body, RequestOptions requestOptions) { - // Protocol API requires serialization of parts with content-disposition and data, as operation 'uploadHttpPart' - // is 'multipart/form-data' + // Operation 'uploadHttpPart' is of content-type 'multipart/form-data'. Protocol API is not usable and hence not + // generated. return this.serviceClient.uploadHttpPartWithResponse(name, body, requestOptions); } diff --git a/packages/http-client-java/generator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/Main.java b/packages/http-client-java/generator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/Main.java index 4d65d994de..2c933710e6 100644 --- a/packages/http-client-java/generator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/Main.java +++ b/packages/http-client-java/generator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/Main.java @@ -212,7 +212,7 @@ private static EmitterOptions loadEmitterOptions(CodeModel codeModel) { options.setOutputDir(options.getOutputDir() + "/"); } } catch (IOException e) { - LOGGER.info("Read emitter options failed, emitter options json: {}", emitterOptionsJson); + LOGGER.warn("Read emitter options failed, emitter options json: {}", emitterOptionsJson); } } diff --git a/packages/http-client-java/package-lock.json b/packages/http-client-java/package-lock.json index 44c94bf700..2e33139114 100644 --- a/packages/http-client-java/package-lock.json +++ b/packages/http-client-java/package-lock.json @@ -19,7 +19,7 @@ "@azure-tools/typespec-azure-core": "0.50.0", "@azure-tools/typespec-azure-resource-manager": "0.50.0", "@azure-tools/typespec-azure-rulesets": "0.50.0", - "@azure-tools/typespec-client-generator-core": "0.50.0", + "@azure-tools/typespec-client-generator-core": "0.50.2", "@microsoft/api-extractor": "^7.49.1", "@microsoft/api-extractor-model": "^7.30.2", "@types/js-yaml": "~4.0.9", @@ -44,7 +44,7 @@ "peerDependencies": { "@azure-tools/typespec-autorest": ">=0.50.0 <1.0.0", "@azure-tools/typespec-azure-core": ">=0.50.0 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.50.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.50.2 <1.0.0", "@typespec/compiler": ">=0.64.0 <1.0.0", "@typespec/http": ">=0.64.0 <1.0.0", "@typespec/openapi": ">=0.64.0 <1.0.0", @@ -181,10 +181,11 @@ } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.50.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.50.0.tgz", - "integrity": "sha512-Zk62SZb6W5neTtajcQAKll4zYSf3aKaMEDLymMTajXTsWxAlrb7sqnc8vTZWSIymaRI0A9olEL2luw9OLywUYA==", + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.50.2.tgz", + "integrity": "sha512-xSyJ5OWqu9BToUoQrmoN6a9pxHpTUqDEyc5pmhRwzeuz3zOIvFs2DFKimE2wqVmhFTYg6LTVqle/UU4sr/vdyQ==", "dev": true, + "license": "MIT", "dependencies": { "change-case": "~5.4.4", "pluralize": "^8.0.0", @@ -199,7 +200,8 @@ "@typespec/http": "~0.64.0", "@typespec/openapi": "~0.64.0", "@typespec/rest": "~0.64.0", - "@typespec/versioning": "~0.64.0" + "@typespec/versioning": "~0.64.0", + "@typespec/xml": "~0.64.0" } }, "node_modules/@azure/abort-controller": { diff --git a/packages/http-client-java/package.json b/packages/http-client-java/package.json index 661da1941c..234ddd5c75 100644 --- a/packages/http-client-java/package.json +++ b/packages/http-client-java/package.json @@ -17,9 +17,9 @@ }, "license": "MIT", "type": "module", - "main": "dist/emitter/emitter.js", + "main": "dist/emitter/index.js", "exports": { - ".": "./dist/emitter/emitter.js" + ".": "./dist/emitter/index.js" }, "engines": { "node": ">=18.0.0" @@ -44,7 +44,7 @@ "peerDependencies": { "@azure-tools/typespec-autorest": ">=0.50.0 <1.0.0", "@azure-tools/typespec-azure-core": ">=0.50.0 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.50.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.50.2 <1.0.0", "@typespec/compiler": ">=0.64.0 <1.0.0", "@typespec/http": ">=0.64.0 <1.0.0", "@typespec/openapi": ">=0.64.0 <1.0.0", @@ -63,7 +63,7 @@ "@azure-tools/typespec-azure-core": "0.50.0", "@azure-tools/typespec-azure-resource-manager": "0.50.0", "@azure-tools/typespec-azure-rulesets": "0.50.0", - "@azure-tools/typespec-client-generator-core": "0.50.0", + "@azure-tools/typespec-client-generator-core": "0.50.2", "@typespec/spector": "0.1.0-alpha.6", "@microsoft/api-extractor": "^7.49.1", "@microsoft/api-extractor-model": "^7.30.2",