Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@typespec/http-client-java"
---

Support File from TypeSpec.
33 changes: 23 additions & 10 deletions packages/http-client-java/emitter/src/code-model-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ import { createPollOperationDetailsSchema, getFileDetailsSchema } from "./extern
import { createDiagnostic, reportDiagnostic } from "./lib.js";
import { ClientContext } from "./models.js";
import {
CONTENT_TYPE_KEY,
ORIGIN_API_VERSION,
SPECIAL_HEADER_NAMES,
cloneOperationParameter,
findResponsePropertySegments,
getServiceVersion,
isContentTypeHeader,
isKnownContentType,
isLroNewPollingStrategy,
operationIsJsonMergePatch,
Expand Down Expand Up @@ -1002,14 +1002,14 @@ export class CodeModelBuilder {
httpOperation.bodyParam &&
param.kind === "header"
) {
if (param.serializedName.toLocaleLowerCase() === CONTENT_TYPE_KEY) {
if (isContentTypeHeader(param)) {
continue;
}
}
// if the request body is optional, skip content-type header added by TCGC
// TODO: add optional content type to code-model, and support optional content-type from codegen, https://github.com/Azure/autorest.java/issues/2930
if (httpOperation.bodyParam && httpOperation.bodyParam.optional) {
if (param.serializedName.toLocaleLowerCase() === CONTENT_TYPE_KEY) {
if (isContentTypeHeader(param)) {
continue;
}
}
Expand Down Expand Up @@ -2199,7 +2199,7 @@ export class CodeModelBuilder {

if (schema instanceof ConstantSchema) {
// skip constant header in response
if (header.serializedName.toLowerCase() !== "content-type") {
if (isContentTypeHeader(header)) {
// we does not warn on content-type as constant, as this is the most common case
reportDiagnostic(this.program, {
code: "constant-header-in-response-removed",
Expand All @@ -2226,14 +2226,27 @@ export class CodeModelBuilder {
const bodyType: SdkType | undefined = sdkResponse.type;
let trackConvenienceApi: boolean = Boolean(op.convenienceApi);

const unknownResponseBody =
sdkResponse.contentTypes &&
sdkResponse.contentTypes.length > 0 &&
!isKnownContentType(sdkResponse.contentTypes);
let responseIsFile: boolean = false;
if (
bodyType &&
bodyType.kind === "model" &&
bodyType.serializationOptions.binary &&
bodyType.serializationOptions.binary.isFile
) {
// check for File
responseIsFile = true;
} else if (bodyType && bodyType.kind === "bytes") {
// check for bytes + unknown content-type
const unknownResponseBody =
sdkResponse.contentTypes &&
sdkResponse.contentTypes.length > 0 &&
!isKnownContentType(sdkResponse.contentTypes);
responseIsFile = Boolean(unknownResponseBody);
}

let response: Response;
if (unknownResponseBody && bodyType && bodyType.kind === "bytes") {
// binary
if (responseIsFile) {
// binary/file
response = new BinaryResponse({
protocol: {
http: {
Expand Down
22 changes: 21 additions & 1 deletion packages/http-client-java/emitter/src/operation-utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ObjectSchema, Parameter, Property, SchemaResponse } from "@autorest/codemodel";
import {
SdkCookieParameter,
SdkHeaderParameter,
SdkHttpOperation,
SdkLroServiceMetadata,
SdkModelPropertyType,
SdkPathParameter,
SdkQueryParameter,
SdkServiceResponseHeader,
} from "@azure-tools/typespec-client-generator-core";
import { Operation, Program, Type, Union } from "@typespec/compiler";
Expand All @@ -24,7 +28,8 @@ export const SPECIAL_HEADER_NAMES = new Set([

export const ORIGIN_API_VERSION = "modelerfour:synthesized/api-version";

export const CONTENT_TYPE_KEY = "content-type";
const CONTENT_TYPE_KEY = "content-type";
const CONTENT_TYPE_NAME = "contentType";

// azure-core SerializerEncoding.SUPPORTED_MIME_TYPES
const SUPPORTED_MIME_TYPES = new Set<string>([
Expand All @@ -40,6 +45,21 @@ const SUPPORTED_MIME_TYPES = new Set<string>([
"application/merge-patch+json",
]);

export function isContentTypeHeader(
header:
| SdkPathParameter
| SdkQueryParameter
| SdkHeaderParameter
| SdkCookieParameter
| SdkServiceResponseHeader,
): boolean {
return (
(header.serializedName && header.serializedName.toLowerCase() === CONTENT_TYPE_KEY) ||
// TODO: remove after TCGC bug fix
(!header.serializedName && header.name === CONTENT_TYPE_NAME)
);
}

export function isKnownContentType(contentTypes: string[]): boolean {
return contentTypes
.map((it) => it.toLowerCase())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.Response;
import com.azure.core.management.polling.PollResult;
import com.azure.core.util.BinaryData;
import com.azure.core.util.Context;
import com.azure.core.util.polling.PollerFlux;
import com.azure.core.util.polling.SyncPoller;
Expand Down Expand Up @@ -511,4 +512,58 @@ SyncPoller<PollResult<ResultInner>, ResultInner> beginAction(String resourceGrou
*/
@ServiceMethod(returns = ReturnType.SINGLE)
ResultInner action(String resourceGroupName, String topLevelArmResourceName, Context context);

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body along with {@link Response} on successful completion of {@link Mono}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
Mono<Response<BinaryData>> publishXmlWithResponseAsync(String resourceGroupName, String topLevelArmResourceName);

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body on successful completion of {@link Mono}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
Mono<BinaryData> publishXmlAsync(String resourceGroupName, String topLevelArmResourceName);

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body along with {@link Response}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
Response<BinaryData> publishXmlWithResponse(String resourceGroupName, String topLevelArmResourceName,
Context context);

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
BinaryData publishXml(String resourceGroupName, String topLevelArmResourceName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

package tsptest.armresourceprovider.implementation;

import com.azure.core.http.rest.Response;
import com.azure.core.management.Region;
import com.azure.core.management.SystemData;
import com.azure.core.util.BinaryData;
import com.azure.core.util.Context;
import java.time.OffsetDateTime;
import java.util.Collections;
Expand Down Expand Up @@ -191,6 +193,15 @@ public Result action(Context context) {
.action(resourceGroupName, topLevelArmResourceName, context);
}

public Response<BinaryData> publishXmlWithResponse(Context context) {
return serviceManager.topLevelArmResourceInterfaces()
.publishXmlWithResponse(resourceGroupName, topLevelArmResourceName, context);
}

public BinaryData publishXml() {
return serviceManager.topLevelArmResourceInterfaces().publishXml(resourceGroupName, topLevelArmResourceName);
}

public TopLevelArmResourceImpl withRegion(Region location) {
this.innerModel().withLocation(location.toString());
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,26 @@ Response<BinaryData> actionSync(@HostParam("endpoint") String endpoint,
@PathParam("topLevelArmResourceName") String topLevelArmResourceName, @HeaderParam("Accept") String accept,
Context context);

@Headers({ "Content-Type: application/json" })
@Post("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/TspTest.ArmResourceProvider/topLevelArmResources/{topLevelArmResourceName}/publishxml")
@ExpectedResponses({ 200 })
@UnexpectedResponseExceptionType(ManagementException.class)
Mono<Response<BinaryData>> publishXml(@HostParam("endpoint") String endpoint,
@QueryParam("api-version") String apiVersion, @PathParam("subscriptionId") String subscriptionId,
@PathParam("resourceGroupName") String resourceGroupName,
@PathParam("topLevelArmResourceName") String topLevelArmResourceName, @HeaderParam("Accept") String accept,
Context context);

@Headers({ "Content-Type: application/json" })
@Post("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/TspTest.ArmResourceProvider/topLevelArmResources/{topLevelArmResourceName}/publishxml")
@ExpectedResponses({ 200 })
@UnexpectedResponseExceptionType(ManagementException.class)
Response<BinaryData> publishXmlSync(@HostParam("endpoint") String endpoint,
@QueryParam("api-version") String apiVersion, @PathParam("subscriptionId") String subscriptionId,
@PathParam("resourceGroupName") String resourceGroupName,
@PathParam("topLevelArmResourceName") String topLevelArmResourceName, @HeaderParam("Accept") String accept,
Context context);

@Headers({ "Content-Type: application/json" })
@Get("{nextLink}")
@ExpectedResponses({ 200 })
Expand Down Expand Up @@ -1088,6 +1108,76 @@ public ResultInner action(String resourceGroupName, String topLevelArmResourceNa
return beginAction(resourceGroupName, topLevelArmResourceName, context).getFinalResult();
}

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body along with {@link Response} on successful completion of {@link Mono}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Response<BinaryData>> publishXmlWithResponseAsync(String resourceGroupName,
String topLevelArmResourceName) {
final String accept = "application/xml";
return FluxUtil
.withContext(context -> service.publishXml(this.client.getEndpoint(), this.client.getApiVersion(),
this.client.getSubscriptionId(), resourceGroupName, topLevelArmResourceName, accept, context))
.contextWrite(context -> context.putAll(FluxUtil.toReactorContext(this.client.getContext()).readOnly()));
}

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body on successful completion of {@link Mono}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<BinaryData> publishXmlAsync(String resourceGroupName, String topLevelArmResourceName) {
return publishXmlWithResponseAsync(resourceGroupName, topLevelArmResourceName)
.flatMap(res -> Mono.justOrEmpty(res.getValue()));
}

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body along with {@link Response}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Response<BinaryData> publishXmlWithResponse(String resourceGroupName, String topLevelArmResourceName,
Context context) {
final String accept = "application/xml";
return service.publishXmlSync(this.client.getEndpoint(), this.client.getApiVersion(),
this.client.getSubscriptionId(), resourceGroupName, topLevelArmResourceName, accept, context);
}

/**
* A synchronous resource action.
*
* @param resourceGroupName The name of the resource group. The name is case insensitive.
* @param topLevelArmResourceName arm resource name for path.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public BinaryData publishXml(String resourceGroupName, String topLevelArmResourceName) {
return publishXmlWithResponse(resourceGroupName, topLevelArmResourceName, Context.NONE).getValue();
}

/**
* Get the next page of items.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.SimpleResponse;
import com.azure.core.util.BinaryData;
import com.azure.core.util.Context;
import com.azure.core.util.logging.ClientLogger;
import tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient;
Expand Down Expand Up @@ -98,6 +99,15 @@ public Result action(String resourceGroupName, String topLevelArmResourceName, C
}
}

public Response<BinaryData> publishXmlWithResponse(String resourceGroupName, String topLevelArmResourceName,
Context context) {
return this.serviceClient().publishXmlWithResponse(resourceGroupName, topLevelArmResourceName, context);
}

public BinaryData publishXml(String resourceGroupName, String topLevelArmResourceName) {
return this.serviceClient().publishXml(resourceGroupName, topLevelArmResourceName);
}

public TopLevelArmResource getById(String id) {
String resourceGroupName = ResourceManagerUtils.getValueFromIdByName(id, "resourceGroups");
if (resourceGroupName == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

package tsptest.armresourceprovider.models;

import com.azure.core.http.rest.Response;
import com.azure.core.management.Region;
import com.azure.core.management.SystemData;
import com.azure.core.util.BinaryData;
import com.azure.core.util.Context;
import java.time.OffsetDateTime;
import java.util.List;
Expand Down Expand Up @@ -393,4 +395,24 @@ interface WithAccuserName {
* @return the response.
*/
Result action(Context context);

/**
* A synchronous resource action.
*
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response body along with {@link Response}.
*/
Response<BinaryData> publishXmlWithResponse(Context context);

/**
* A synchronous resource action.
*
* @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the response.
*/
BinaryData publishXml();
}
Loading
Loading