Skip to content

Commit

Permalink
Java sync to 16e2939c38dec8bb5322214d1a99f2c44284a2bf (#4293)
Browse files Browse the repository at this point in the history
I didn't include Azure/autorest.java#2936

I will remove prenamer in next PR.
  • Loading branch information
weidongxu-microsoft authored Sep 3, 2024
1 parent c7ed92e commit bc1c599
Show file tree
Hide file tree
Showing 87 changed files with 2,951 additions and 2,540 deletions.
287 changes: 151 additions & 136 deletions packages/http-client-java/emitter/src/code-model-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import {
SdkServiceMethod,
SdkType,
SdkUnionType,
UsageFlags,
createSdkContext,
getAllModels,
getClientType,
Expand Down Expand Up @@ -107,10 +106,7 @@ import {
getHeaderFieldName,
getPathParamName,
getQueryParamName,
isBody,
isBodyRoot,
isHeader,
isMultipartBodyProperty,
isPathParam,
isQueryParam,
} from "@typespec/http";
Expand Down Expand Up @@ -463,6 +459,7 @@ export class CodeModelBuilder {
schema instanceof ConstantSchema
) {
const schemaUsage: SchemaContext[] | undefined = schema.usage;

// Public override Internal
if (schemaUsage?.includes(SchemaContext.Public)) {
const index = schemaUsage.indexOf(SchemaContext.Internal);
Expand All @@ -471,11 +468,17 @@ export class CodeModelBuilder {
}
}

// Internal on Anonymous
if (schemaUsage?.includes(SchemaContext.Anonymous)) {
const index = schemaUsage.indexOf(SchemaContext.Internal);
if (index < 0) {
schemaUsage.push(SchemaContext.Internal);
// Internal on PublicSpread, but Public takes precedence
if (schemaUsage?.includes(SchemaContext.PublicSpread)) {
// remove PublicSpread as it now served its purpose
schemaUsage.splice(schemaUsage.indexOf(SchemaContext.PublicSpread), 1);

// Public would override PublicSpread, hence do nothing if this schema is Public
if (!schemaUsage?.includes(SchemaContext.Public)) {
// set the model as Internal, so that it is not exposed to user
if (!schemaUsage.includes(SchemaContext.Internal)) {
schemaUsage.push(SchemaContext.Internal);
}
}
}
}
Expand Down Expand Up @@ -1350,6 +1353,12 @@ export class CodeModelBuilder {
});
op.addParameter(parameter);

const jsonMergePatch = operationIsJsonMergePatch(sdkHttpOperation);

const schemaIsPublicBeforeProcess =
schema instanceof ObjectSchema &&
(schema as SchemaUsage).usage?.includes(SchemaContext.Public);

this.trackSchemaUsage(schema, { usage: [SchemaContext.Input] });

if (op.convenienceApi) {
Expand All @@ -1359,130 +1368,143 @@ export class CodeModelBuilder {
});
}

if (operationIsJsonMergePatch(sdkHttpOperation)) {
if (jsonMergePatch) {
this.trackSchemaUsage(schema, { usage: [SchemaContext.JsonMergePatch] });
}
if (op.convenienceApi && operationIsMultipart(sdkHttpOperation)) {
this.trackSchemaUsage(schema, { serializationFormats: [KnownMediaType.Multipart] });
}

// Implicit body parameter would have usage flag: UsageFlags.Spread, for this case we need to do body parameter flatten
const bodyParameterFlatten =
sdkType.kind === "model" && sdkType.usage & UsageFlags.Spread && !this.isArm();

if (schema instanceof ObjectSchema && bodyParameterFlatten) {
// flatten body parameter
const parameters = sdkHttpOperation.parameters;
const bodyParameter = sdkHttpOperation.bodyParam;
// name the schema for documentation
schema.language.default.name = pascalCase(op.language.default.name) + "Request";

if (!parameter.language.default.name) {
// name the parameter for documentation
parameter.language.default.name = "request";
}

if (operationIsJsonMergePatch(sdkHttpOperation)) {
// skip model flatten, if "application/merge-patch+json"
schema.language.default.name = pascalCase(op.language.default.name) + "PatchRequest";
return;
}

this.trackSchemaUsage(schema, { usage: [SchemaContext.Anonymous] });
if (op.convenienceApi) {
// Explicit body parameter @body or @bodyRoot would result to the existence of rawHttpOperation.parameters.body.property
// Implicit body parameter would result to rawHttpOperation.parameters.body.property be undefined
// see https://typespec.io/docs/libraries/http/cheat-sheet#data-types
const bodyParameterFlatten =
schema instanceof ObjectSchema &&
sdkType.kind === "model" &&
!rawHttpOperation.parameters.body?.property &&
!this.isArm();

if (schema instanceof ObjectSchema && bodyParameterFlatten) {
// flatten body parameter
const parameters = sdkHttpOperation.parameters;
const bodyParameter = sdkHttpOperation.bodyParam;

if (!parameter.language.default.name) {
// name the parameter for documentation
parameter.language.default.name = "request";
}

if (op.convenienceApi && op.parameters) {
op.convenienceApi.requests = [];
const request = new Request({
protocol: op.requests![0].protocol,
});
request.parameters = [];
op.convenienceApi.requests.push(request);
if (jsonMergePatch) {
// skip model flatten, if "application/merge-patch+json"
if (sdkType.isGeneratedName) {
schema.language.default.name = pascalCase(op.language.default.name) + "PatchRequest";
}
return;
}

// header/query/path params
for (const opParameter of parameters) {
this.addParameterOrBodyPropertyToCodeModelRequest(
opParameter,
op,
request,
schema,
parameter
);
const schemaUsage = (schema as SchemaUsage).usage;
if (!schemaIsPublicBeforeProcess && schemaUsage?.includes(SchemaContext.Public)) {
// Public added in this op, change it to PublicSpread
// This means that if this op would originally add Public to this schema, it adds PublicSpread instead
schemaUsage?.splice(schemaUsage?.indexOf(SchemaContext.Public), 1);
this.trackSchemaUsage(schema, { usage: [SchemaContext.PublicSpread] });
}
// body param
if (bodyParameter) {
if (bodyParameter.type.kind === "model") {
for (const bodyProperty of bodyParameter.type.properties) {
if (bodyProperty.kind === "property") {
this.addParameterOrBodyPropertyToCodeModelRequest(
bodyProperty,
op,
request,
schema,
parameter
);

if (op.convenienceApi && op.parameters) {
op.convenienceApi.requests = [];
const request = new Request({
protocol: op.requests![0].protocol,
});
request.parameters = [];
op.convenienceApi.requests.push(request);

// header/query/path params
for (const opParameter of parameters) {
this.addParameterOrBodyPropertyToCodeModelRequest(
opParameter,
op,
request,
schema,
parameter
);
}
// body param
if (bodyParameter) {
if (bodyParameter.type.kind === "model") {
for (const bodyProperty of bodyParameter.type.properties) {
if (bodyProperty.kind === "property") {
this.addParameterOrBodyPropertyToCodeModelRequest(
bodyProperty,
op,
request,
schema,
parameter
);
}
}
}
}
}
request.signatureParameters = request.parameters;

if (request.signatureParameters.length > 6) {
// create an option bag
const name = op.language.default.name + "Options";
const namespace = getNamespace(rawHttpOperation.operation);
// option bag schema
const optionBagSchema = this.codeModel.schemas.add(
new GroupSchema(name, `Options for ${op.language.default.name} API`, {
language: {
default: {
namespace: namespace,
},
java: {
namespace: this.getJavaNamespace(namespace),
request.signatureParameters = request.parameters;

if (request.signatureParameters.length > 6) {
// create an option bag
const name = op.language.default.name + "Options";
const namespace = getNamespace(rawHttpOperation.operation);
// option bag schema
const optionBagSchema = this.codeModel.schemas.add(
new GroupSchema(name, `Options for ${op.language.default.name} API`, {
language: {
default: {
namespace: namespace,
},
java: {
namespace: this.getJavaNamespace(namespace),
},
},
},
})
);
request.parameters.forEach((it) => {
optionBagSchema.add(
new GroupProperty(
it.language.default.name,
it.language.default.description,
it.schema,
{
originalParameter: [it],
summary: it.summary,
required: it.required,
nullable: it.nullable,
readOnly: false,
serializedName: it.language.default.serializedName,
}
)
})
);
});

this.trackSchemaUsage(optionBagSchema, { usage: [SchemaContext.Input] });
if (op.convenienceApi) {
this.trackSchemaUsage(optionBagSchema, {
usage: [op.internalApi ? SchemaContext.Internal : SchemaContext.Public],
request.parameters.forEach((it) => {
optionBagSchema.add(
new GroupProperty(
it.language.default.name,
it.language.default.description,
it.schema,
{
originalParameter: [it],
summary: it.summary,
required: it.required,
nullable: it.nullable,
readOnly: false,
serializedName: it.language.default.serializedName,
}
)
);
});
}

// option bag parameter
const optionBagParameter = new Parameter(
"options",
optionBagSchema.language.default.description,
optionBagSchema,
{
implementation: ImplementationLocation.Method,
required: true,
nullable: false,
this.trackSchemaUsage(optionBagSchema, { usage: [SchemaContext.Input] });
if (op.convenienceApi) {
this.trackSchemaUsage(optionBagSchema, {
usage: [op.internalApi ? SchemaContext.Internal : SchemaContext.Public],
});
}
);

request.signatureParameters = [optionBagParameter];
request.parameters.forEach((it) => (it.groupedBy = optionBagParameter));
request.parameters.push(optionBagParameter);
// option bag parameter
const optionBagParameter = new Parameter(
"options",
optionBagSchema.language.default.description,
optionBagSchema,
{
implementation: ImplementationLocation.Method,
required: true,
nullable: false,
}
);

request.signatureParameters = [optionBagParameter];
request.parameters.forEach((it) => (it.groupedBy = optionBagParameter));
request.parameters.push(optionBagParameter);
}
}
}
}
Expand Down Expand Up @@ -2340,24 +2362,6 @@ export class CodeModelBuilder {
}
}

private getParameterLocation(target: ModelProperty): ParameterLocation | "BodyProperty" {
if (isHeader(this.program, target)) {
return ParameterLocation.Header;
} else if (isQueryParam(this.program, target)) {
return ParameterLocation.Query;
} else if (isPathParam(this.program, target)) {
return ParameterLocation.Path;
} else if (
isBody(this.program, target) ||
isBodyRoot(this.program, target) ||
isMultipartBodyProperty(this.program, target)
) {
return ParameterLocation.Body;
} else {
return "BodyProperty";
}
}

private isReadOnly(target: SdkModelPropertyType): boolean {
const segment = target.__raw ? getSegment(this.program, target.__raw) !== undefined : false;
if (segment) {
Expand Down Expand Up @@ -2646,10 +2650,21 @@ export class CodeModelBuilder {
};

// Exclude context that not to be propagated
const updatedSchemaUsage = (schema as SchemaUsage).usage?.filter(
(it) => it !== SchemaContext.Paged && it !== SchemaContext.PublicSpread
);
const indexSpread = (schema as SchemaUsage).usage?.indexOf(SchemaContext.PublicSpread);
if (
updatedSchemaUsage &&
indexSpread &&
indexSpread >= 0 &&
!(schema as SchemaUsage).usage?.includes(SchemaContext.Public)
) {
// Propagate Public, if schema is PublicSpread
updatedSchemaUsage.push(SchemaContext.Public);
}
const schemaUsage = {
usage: (schema as SchemaUsage).usage?.filter(
(it) => it !== SchemaContext.Paged && it !== SchemaContext.Anonymous
),
usage: updatedSchemaUsage,
serializationFormats: (schema as SchemaUsage).serializationFormats?.filter(
(it) => it !== KnownMediaType.Multipart
),
Expand Down
4 changes: 2 additions & 2 deletions packages/http-client-java/emitter/src/common/schemas/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export enum SchemaContext {
/** Schema is used from the pageable operation. This usage does not propagate. */
Paged = "paged",

/** Schema as anonymous model. This usage does not propagate. */
Anonymous = "anonymous",
/** Schema as spread/flatten model. "Public", if present in usage, will have precedence over "PublicSpread". This usage does not propagate. Instead, it propagate "Public". */
PublicSpread = "spread",

/** Schema is used in json-merge-patch operation */
JsonMergePatch = "json-merge-patch",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public Connection(OutputStream writer, InputStream input) {
this.requestId = new AtomicInteger(0);
}

private boolean isAlive = true;
private volatile boolean isAlive = true;

/**
* Stops the connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ public enum SchemaContext {
*/
PAGED("paged"),

/**
* The schema is used as an anonymous type.
*/
ANONYMOUS("anonymous"),

/**
* The schema is used internally.
*/
Expand Down
Loading

0 comments on commit bc1c599

Please sign in to comment.