Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
weidongxu-microsoft committed Jan 2, 2024
2 parents 557fe4c + 2927ca7 commit c49a67a
Show file tree
Hide file tree
Showing 38 changed files with 2,341 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import com.azure.autorest.customization.implementation.Utils;
import com.azure.autorest.customization.implementation.ls.EclipseLanguageClient;
import com.azure.autorest.extension.base.util.FileUtils;
import org.slf4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;

Expand All @@ -31,7 +31,7 @@ public final Map<String, String> run(Map<String, String> files, Logger logger) {
// Populate editor
Editor editor;
try {
tempDirWithPrefix = Files.createTempDirectory("temp");
tempDirWithPrefix = FileUtils.createTempDirectory("temp");
editor = new Editor(files, tempDirWithPrefix);
InputStream pomStream = Customization.class.getResourceAsStream("/pom.xml");
byte[] buffer = new byte[pomStream.available()];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.azure.autorest.customization;

import com.azure.autorest.customization.implementation.Utils;
import com.azure.autorest.extension.base.util.FileUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -12,7 +13,6 @@

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.UUID;
Expand All @@ -32,7 +32,7 @@ public class AnnotationTests {

@BeforeEach
public void setup() throws IOException {
workingDir = Files.createTempDirectory("removeComplexAnnotation" + UUID.randomUUID());
workingDir = FileUtils.createTempDirectory("removeComplexAnnotation" + UUID.randomUUID());
}

@AfterEach
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.autorest.extension.base.util;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Utility class for file operations.
*/
public final class FileUtils {
private FileUtils() {
}

/**
* Creates a temporary directory.
* <p>
* If the environment setting {@code codegen.java.temp.directory} is set, the directory will be created under the
* specified path. Otherwise, the directory will be created under the system default temporary directory.
* <p>
* {@link System#getProperty(String)} is checked before {@link System#getenv(String)}.
* <p>
* If {@code codegen.java.temp.directory} is set to a non-existent path, the directory will be created under the
* system default temporary directory.
*
* @param prefix The prefix string to be used in generating the directory's name; may be {@code null}.
* @return The path to the newly created directory.
* @throws IOException If an I/O error occurs.
*/
public static Path createTempDirectory(String prefix) throws IOException {
String tempDirectory = System.getProperty("codegen.java.temp.directory");
if (tempDirectory == null) {
tempDirectory = System.getenv("codegen.java.temp.directory");
}

if (tempDirectory != null) {
Path tempDirectoryPath = Paths.get(tempDirectory);
if (Files.exists(tempDirectoryPath)) {
return Files.createTempDirectory(tempDirectoryPath, prefix);
}
}

return Files.createTempDirectory(prefix);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.azure.autorest.extension.base.plugin.JavaSettings;
import com.azure.autorest.extension.base.plugin.NewPlugin;
import com.azure.autorest.extension.base.plugin.PluginLogger;
import com.azure.autorest.extension.base.util.FileUtils;
import com.azure.autorest.fluent.namer.FluentNamerFactory;
import com.azure.autorest.fluent.transformer.FluentTransformer;
import com.azure.autorest.fluent.util.FluentJavaSettings;
Expand Down Expand Up @@ -59,7 +60,7 @@ public CodeModel processCodeModel() {

Path codeModelFolder;
try {
codeModelFolder = Files.createTempDirectory("code-model" + UUID.randomUUID());
codeModelFolder = FileUtils.createTempDirectory("code-model" + UUID.randomUUID());
logger.info("Created temp directory for code model: {}", codeModelFolder);
} catch (IOException ex) {
logger.error("Failed to create temp directory for code model.", ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ protected void writeInvocationAndConversion(
IType rawResponseBodyType = convenienceMethod.getProxyMethod().getRawResponseBodyType();

if (methodType == ClientMethodType.PagingAsync) {
String expressionMapFromBinaryData = expressionMapFromBinaryData(responseBodyType, rawResponseBodyType, typeReferenceStaticClasses);
String expressionMapFromBinaryData = expressionMapFromBinaryData(
responseBodyType, rawResponseBodyType,
protocolMethod.getProxyMethod().getResponseContentTypes(),
typeReferenceStaticClasses);
if (expressionMapFromBinaryData == null) {
// no need to do the map
methodBlock.methodReturn(String.format("%1$s(%2$s)", getMethodName(protocolMethod), invocationExpression));
Expand All @@ -100,7 +103,10 @@ protected void writeInvocationAndConversion(
} else {
String returnTypeConversionExpression = "";
if (protocolResponseBodyType == ClassType.BINARY_DATA) {
returnTypeConversionExpression = expressionConvertFromBinaryData(responseBodyType, rawResponseBodyType, typeReferenceStaticClasses);
returnTypeConversionExpression = expressionConvertFromBinaryData(
responseBodyType, rawResponseBodyType,
protocolMethod.getProxyMethod().getResponseContentTypes(),
typeReferenceStaticClasses);
}

methodBlock.methodReturn(
Expand Down Expand Up @@ -133,8 +139,13 @@ private IType getResponseBodyType(ClientMethod method) {
return type;
}

private String expressionConvertFromBinaryData(IType responseBodyType, IType rawType, Set<GenericType> typeReferenceStaticClasses) {
String expressionMapFromBinaryData = expressionMapFromBinaryData(responseBodyType, rawType, typeReferenceStaticClasses);
private String expressionConvertFromBinaryData(IType responseBodyType, IType rawType,
Set<String> mediaTypes,
Set<GenericType> typeReferenceStaticClasses) {
String expressionMapFromBinaryData = expressionMapFromBinaryData(
responseBodyType, rawType,
mediaTypes,
typeReferenceStaticClasses);
if (expressionMapFromBinaryData != null) {
return String.format(".map(%s)", expressionMapFromBinaryData);
} else {
Expand All @@ -143,28 +154,45 @@ private String expressionConvertFromBinaryData(IType responseBodyType, IType raw
}
}

private String expressionMapFromBinaryData(IType responseBodyType, IType rawType, Set<GenericType> typeReferenceStaticClasses) {
private String expressionMapFromBinaryData(IType responseBodyType, IType rawType,
Set<String> mediaTypes,
Set<GenericType> typeReferenceStaticClasses) {
String mapExpression = null;
if (responseBodyType instanceof EnumType) {
// enum
mapExpression = String.format("protocolMethodData -> %1$s.from%2$s(protocolMethodData.toObject(%2$s.class))", responseBodyType, ((EnumType) responseBodyType).getElementType());
} else if (responseBodyType instanceof GenericType) {
// generic, e.g. list, map
typeReferenceStaticClasses.add((GenericType) responseBodyType);
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s)", TemplateUtil.getTypeReferenceCreation(responseBodyType));
} else if (responseBodyType == ClassType.BINARY_DATA) {
// BinaryData, no need to do the map in expressionConvertFromBinaryData
mapExpression = null;
} else if (isModelOrBuiltin(responseBodyType)) {
// class
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s.class)", responseBodyType.asNullable());
} else if (responseBodyType == ArrayType.BYTE_ARRAY) {
// byte[]
if (rawType == ClassType.BASE_64_URL) {
return "protocolMethodData -> protocolMethodData.toObject(Base64Url.class).decodedBytes()";
} else {
return "protocolMethodData -> protocolMethodData.toObject(byte[].class)";
}
SupportedMimeType mimeType = getResponseKnownMimeType(mediaTypes);
// TODO (weidxu): support XML etc.
switch (mimeType) {
case TEXT:
mapExpression = "protocolMethodData -> protocolMethodData.toString()";
break;

case BINARY:
mapExpression = null;
break;

default:
// JSON etc.
if (responseBodyType instanceof EnumType) {
// enum
mapExpression = String.format("protocolMethodData -> %1$s.from%2$s(protocolMethodData.toObject(%2$s.class))", responseBodyType, ((EnumType) responseBodyType).getElementType());
} else if (responseBodyType instanceof GenericType) {
// generic, e.g. list, map
typeReferenceStaticClasses.add((GenericType) responseBodyType);
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s)", TemplateUtil.getTypeReferenceCreation(responseBodyType));
} else if (responseBodyType == ClassType.BINARY_DATA) {
// BinaryData, no need to do the map in expressionConvertFromBinaryData
mapExpression = null;
} else if (isModelOrBuiltin(responseBodyType)) {
// class
mapExpression = String.format("protocolMethodData -> protocolMethodData.toObject(%1$s.class)", responseBodyType.asNullable());
} else if (responseBodyType == ArrayType.BYTE_ARRAY) {
// byte[]
if (rawType == ClassType.BASE_64_URL) {
return "protocolMethodData -> protocolMethodData.toObject(Base64Url.class).decodedBytes()";
} else {
return "protocolMethodData -> protocolMethodData.toObject(byte[].class)";
}
}
break;
}
return mapExpression;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.azure.core.util.serializer.TypeReference;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
Expand All @@ -48,6 +50,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -123,7 +126,7 @@ protected void writeMethodImplementation(
methodBlock.line(String.format("requestOptions.setContext(%s);", parameter.getName()));
} else if (protocolParameter != null) {
// protocol method parameter exists
String expression = expressionConvertToType(parameter.getName(), parameter);
String expression = expressionConvertToType(parameter.getName(), parameter, protocolMethod.getProxyMethod().getRequestContentType());
parameterExpressionsMap.put(protocolParameter.getName(), expression);
} else if (parameter.getProxyMethodParameter() != null) {
// protocol method parameter not exist, set the parameter via RequestOptions
Expand All @@ -139,7 +142,9 @@ protected void writeMethodImplementation(
case BODY: {
Consumer<JavaBlock> writeLine = javaBlock -> javaBlock.line(
String.format("requestOptions.setBody(%s);",
expressionConvertToBinaryData(parameter.getName(), parameter.getClientMethodParameter().getWireType())));
expressionConvertToBinaryData(
parameter.getName(), parameter.getClientMethodParameter().getWireType(),
protocolMethod.getProxyMethod().getRequestContentType())));
if (!parameter.getClientMethodParameter().isRequired()) {
methodBlock.ifBlock(String.format("%s != null", parameter.getName()), writeLine);
} else {
Expand Down Expand Up @@ -387,18 +392,65 @@ protected boolean isModelOrBuiltin(IType type) {
|| ClientModelUtil.isClientModel(type); // client model
}

private static String expressionConvertToBinaryData(String name, IType type) {
if (type == ClassType.BINARY_DATA) {
return name;
} else {
if (type == ClassType.BASE_64_URL) {
return "BinaryData.fromObject(Base64Url.encode(" + name + "))";
} else if (type instanceof EnumType) {
return "BinaryData.fromObject(" + name + " == null ? null : " + name + "." + ((EnumType) type).getToMethodName() + "())";
} else {
return "BinaryData.fromObject(" + name + ")";
protected enum SupportedMimeType {
TEXT,
XML,
MULTIPART,
BINARY,
JSON
}

// azure-core SerializerEncoding.SUPPORTED_MIME_TYPES
private static final Map<String, SupportedMimeType> SUPPORTED_MIME_TYPES = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
static {
SUPPORTED_MIME_TYPES.put("text/xml", SupportedMimeType.XML);
SUPPORTED_MIME_TYPES.put("application/xml", SupportedMimeType.XML);
SUPPORTED_MIME_TYPES.put("application/json", SupportedMimeType.JSON);
SUPPORTED_MIME_TYPES.put("text/css", SupportedMimeType.TEXT);
SUPPORTED_MIME_TYPES.put("text/csv", SupportedMimeType.TEXT);
SUPPORTED_MIME_TYPES.put("text/html", SupportedMimeType.TEXT);
SUPPORTED_MIME_TYPES.put("text/javascript", SupportedMimeType.TEXT);
SUPPORTED_MIME_TYPES.put("text/plain", SupportedMimeType.TEXT);
// not in azure-core
SUPPORTED_MIME_TYPES.put("application/merge-patch+json", SupportedMimeType.JSON);
}

protected static SupportedMimeType getResponseKnownMimeType(Collection<String> mediaTypes) {
// Response adds a "application/json;q=0.9" if no "application/json" specified in media types.
// This is mostly for the error response which is in JSON, and is not included in this calculation.

for (String mediaType : mediaTypes) {
SupportedMimeType type = SUPPORTED_MIME_TYPES.get(mediaType);
if (type != null) {
return type;
}
}
return SupportedMimeType.BINARY; // BINARY if not recognized
}

private static String expressionConvertToBinaryData(String name, IType type, String mediaType) {
SupportedMimeType mimeType = getResponseKnownMimeType(Collections.singleton(mediaType));
switch (mimeType) {
case TEXT:
return "BinaryData.fromString(" + name + ")";

case BINARY:
return name;

default:
// JSON etc.
if (type == ClassType.BINARY_DATA) {
return name;
} else {
if (type == ClassType.BASE_64_URL) {
return "BinaryData.fromObject(Base64Url.encode(" + name + "))";
} else if (type instanceof EnumType) {
return "BinaryData.fromObject(" + name + " == null ? null : " + name + "." + ((EnumType) type).getToMethodName() + "())";
} else {
return "BinaryData.fromObject(" + name + ")";
}
}
}
}

private static void writeHeader(MethodParameter parameter, JavaBlock methodBlock) {
Expand Down Expand Up @@ -525,7 +577,7 @@ private static String expressionConvertToString(String name, IType type, ProxyMe
}
}

private static String expressionConvertToType(String name, MethodParameter convenienceParameter) {
private static String expressionConvertToType(String name, MethodParameter convenienceParameter, String mediaType) {
if (convenienceParameter.getProxyMethodParameter().getRequestParameterLocation() == RequestParameterLocation.BODY) {
IType bodyType = convenienceParameter.getProxyMethodParameter().getRawType();
if (bodyType instanceof ClassType) {
Expand All @@ -535,7 +587,7 @@ private static String expressionConvertToType(String name, MethodParameter conve
return expressionMultipartFormDataToBinaryData(name, model);
}
}
return expressionConvertToBinaryData(name, convenienceParameter.getClientMethodParameter().getWireType());
return expressionConvertToBinaryData(name, convenienceParameter.getClientMethodParameter().getWireType(), mediaType);
} else {
IType type = convenienceParameter.getClientMethodParameter().getWireType();
if (type instanceof EnumType) {
Expand Down
Loading

0 comments on commit c49a67a

Please sign in to comment.