Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another round of ClientCore API updates based on review #44531

Merged
merged 2 commits into from
Mar 7, 2025
Merged
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
Expand Up @@ -18,29 +18,23 @@
import io.clientcore.core.http.models.RequestOptions;
import io.clientcore.core.http.models.Response;
import io.clientcore.core.http.pipeline.HttpPipeline;
import io.clientcore.core.implementation.http.ContentType;
import io.clientcore.core.models.binarydata.BinaryData;
import io.clientcore.core.serialization.ObjectSerializer;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.util.List;

import static io.clientcore.core.implementation.http.ContentType.APPLICATION_OCTET_STREAM;

@ServiceInterface(name = "myService")
public interface TestInterfaceClientService {
static TestInterfaceClientService getNewInstance(HttpPipeline pipeline, ObjectSerializer serializer) {
if (pipeline == null) {
throw new IllegalArgumentException("pipeline cannot be null");
}
try {
Class<?> clazz = Class.forName("io.clientcore.annotation.processor.test.implementation.TestInterfaceClientServiceImpl");
return (TestInterfaceClientService) clazz
.getMethod("getNewInstance", HttpPipeline.class, ObjectSerializer.class)
.invoke(null, pipeline, serializer);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
| InvocationTargetException e) {
throw new RuntimeException(e);
}

return TestInterfaceClientServiceImpl.getNewInstance(pipeline, serializer);
}

@HttpRequestInformation(method = HttpMethod.POST, path = "my/uri/path", expectedStatusCodes = { 200 })
Expand All @@ -60,7 +54,6 @@ Response<Void> testMethod(@BodyParam("application/octet-stream") BinaryData data
@HttpRequestInformation(method = HttpMethod.HEAD, path = "my/uri/path", expectedStatusCodes = { 200 })
void testHeadMethod();


@HttpRequestInformation(method = HttpMethod.HEAD, path = "my/uri/path", expectedStatusCodes = { 200, 207 })
boolean testBooleanHeadMethod();

Expand All @@ -79,44 +72,44 @@ Response<Foo> getFoo(@PathParam("key") String key, @QueryParam("label") String l
Response<Void> deleteFoo(@PathParam("key") String key, @QueryParam("label") String label,
@HeaderParam("Sync-Token") String syncToken);


@HttpRequestInformation(method = HttpMethod.GET, path = "foos", expectedStatusCodes = { 200 })
Response<FooListResult> listFooListResult(@HostParam("uri") String uri, RequestOptions requestOptions);

@HttpRequestInformation(method = HttpMethod.GET, path = "{nextLink}", expectedStatusCodes = { 200 })
Response<FooListResult> listNextFooListResult(@PathParam(value = "nextLink", encoded = true) String nextLink,
RequestOptions requestOptions);
RequestOptions requestOptions);

@HttpRequestInformation(method = HttpMethod.GET, path = "foos", expectedStatusCodes = { 200 })
Response<List<Foo>> listFoo(@HostParam("uri") String uri, RequestOptions requestOptions);

@HttpRequestInformation(method = HttpMethod.GET, path = "{nextLink}", expectedStatusCodes = { 200 })
Response<List<Foo>> listNextFoo(@PathParam(value = "nextLink", encoded = true) String nextLink,
RequestOptions requestOptions);
RequestOptions requestOptions);

// HttpClientTests
// Need to add RequestOptions to specify ResponseBodyMode, which is otherwise provided by convenience methods
@SuppressWarnings({ "unchecked", "cast" })
@HttpRequestInformation(method = HttpMethod.PUT, path = "put", expectedStatusCodes = {200})
@HttpRequestInformation(method = HttpMethod.PUT, path = "put", expectedStatusCodes = { 200 })
default HttpBinJSON putConvenience(String uri, int putBody, RequestOptions options) {
return putResponse(uri, putBody, options).getValue();
}

@HttpRequestInformation(method = HttpMethod.PUT, path = "put", expectedStatusCodes = { 200 })
Response<HttpBinJSON> putResponse(@HostParam("uri") String uri,
@BodyParam(ContentType.APPLICATION_OCTET_STREAM) int putBody, RequestOptions options);
Response<HttpBinJSON> putResponse(@HostParam("uri") String uri, @BodyParam(APPLICATION_OCTET_STREAM) int putBody,
RequestOptions options);

@HttpRequestInformation(method = HttpMethod.POST, path = "stream", expectedStatusCodes = { 200 })
default HttpBinJSON postStreamConvenience(@HostParam("uri") String uri,
@BodyParam(ContentType.APPLICATION_OCTET_STREAM) int putBody, RequestOptions options) {
@BodyParam(APPLICATION_OCTET_STREAM) int putBody, RequestOptions options) {
return postStreamResponse(uri, putBody, options).getValue();
}

@HttpRequestInformation(method = HttpMethod.POST, path = "stream", expectedStatusCodes = { 200 })
Response<HttpBinJSON> postStreamResponse(@HostParam("uri") String uri,
@BodyParam(ContentType.APPLICATION_OCTET_STREAM) int putBody, RequestOptions options);
@BodyParam(APPLICATION_OCTET_STREAM) int putBody, RequestOptions options);

// Service 1
@HttpRequestInformation(method = HttpMethod.GET, path = "bytes/100", expectedStatusCodes = {200})
@HttpRequestInformation(method = HttpMethod.GET, path = "bytes/100", expectedStatusCodes = { 200 })
byte[] getByteArray(@HostParam("uri") String uri);

// Service 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,8 @@
import io.clientcore.core.http.models.HttpRequest;
import io.clientcore.core.http.models.Response;
import io.clientcore.core.http.pipeline.HttpPipeline;
import io.clientcore.core.implementation.http.HttpResponse;
import io.clientcore.core.models.binarydata.BinaryData;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
Expand All @@ -41,6 +37,10 @@
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Annotation processor that generates client code based on annotated interfaces.
Expand Down Expand Up @@ -145,7 +145,6 @@ private void addImports(TemplateInput templateInput) {
templateInput.addImport(HttpPipeline.class.getName());
templateInput.addImport(HttpHeaderName.class.getName());
templateInput.addImport(HttpMethod.class.getName());
templateInput.addImport(HttpResponse.class.getName());
templateInput.addImport(HttpRequest.class.getName());
templateInput.addImport(Response.class.getName());
templateInput.addImport(Void.class.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@
import io.clientcore.core.http.models.HttpRequest;
import io.clientcore.core.http.models.Response;
import io.clientcore.core.http.pipeline.HttpPipeline;
import io.clientcore.core.implementation.http.ContentType;
import io.clientcore.core.serialization.json.JsonSerializer;
import io.clientcore.core.instrumentation.logging.ClientLogger;
import io.clientcore.core.models.binarydata.BinaryData;
import io.clientcore.core.serialization.ObjectSerializer;
import io.clientcore.core.serialization.json.JsonSerializer;
import io.clientcore.core.utils.CodegenUtil;

import javax.annotation.processing.ProcessingEnvironment;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Writer;
Expand All @@ -47,14 +48,16 @@
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;

import static io.clientcore.annotation.processor.utils.ResponseBodyModeGeneration.generateResponseHandling;

/**
* This class generates the implementation of the service interface.
*/
public class JavaParserTemplateProcessor implements TemplateProcessor {
private static final String APPLICATION_JSON = "application/json";
private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";

private static final Map<String, String> LOWERCASE_HEADER_TO_HTTPHEADENAME_CONSTANT;

static {
Expand Down Expand Up @@ -491,12 +494,11 @@ public void configureRequestWithBodyAndContentType(BlockStmt body, String parame
} else {

if (contentType == null || contentType.isEmpty()) {
// TODO (alzimmer): Why is String octet-stream?
if ("byte[]".equals(parameterType) || "String".equals(parameterType)) {

contentType = ContentType.APPLICATION_OCTET_STREAM;
contentType = APPLICATION_OCTET_STREAM;
} else {

contentType = ContentType.APPLICATION_JSON;
contentType = APPLICATION_JSON;
}
}
// Set the content type header if it is not already set in the headers
Expand All @@ -518,7 +520,7 @@ public void configureRequestWithBodyAndContentType(BlockStmt body, String parame
final String[] contentTypeParts = contentType.split(";");

for (final String contentTypePart : contentTypeParts) {
if (contentTypePart.trim().equalsIgnoreCase(ContentType.APPLICATION_JSON)) {
if (contentTypePart.trim().equalsIgnoreCase(APPLICATION_JSON)) {
isJson = true;

break;
Expand Down
17 changes: 10 additions & 7 deletions sdk/clientcore/core/spotbugs-exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,20 @@
<Class name="io.clientcore.core.implementation.http.rest.RestProxyImpl" />
<Class name="io.clientcore.core.implementation.utils.AuthenticateChallengeParser" />
<Class name="io.clientcore.core.implementation.utils.InternalContext" />
<Class name="io.clientcore.core.serialization.json.JsonSerializer" />
<Class name="io.clientcore.core.implementation.utils.Providers" />
<Class name="io.clientcore.core.implementation.utils.SliceInputStream" />
<Class name="io.clientcore.core.implementation.utils.StreamUtil" />
<Class name="io.clientcore.core.implementation.utils.XmlSerializer" />
<Class name="io.clientcore.core.models.CloudEvent" />
<Class name="io.clientcore.core.models.binarydata.FileBinaryData" />
<Class name="io.clientcore.core.models.binarydata.InputStreamBinaryData" />
<Class name="io.clientcore.core.models.binarydata.ListByteBufferBinaryData" />
<Class name="io.clientcore.core.models.geo.GeoArray" />
<Class name="io.clientcore.core.models.geo.GeoBoundingBox" />
<Class name="io.clientcore.core.models.geo.GeoLinearRing" />
<Class name="io.clientcore.core.models.geo.GeoPosition" />
<Class name="io.clientcore.core.serialization.json.JsonSerializer" />
<Class name="io.clientcore.core.serialization.xml.XmlReader" />
<Class name="io.clientcore.core.serialization.xml.XmlSerializer" />
<Class name="io.clientcore.core.shared.HttpClientTests" />
<Class name="io.clientcore.core.utils.AuthenticateChallenge" />
<Class name="io.clientcore.core.utils.DateTimeRfc1123" />
Expand All @@ -68,7 +69,7 @@
<Class name="io.clientcore.core.credentials.KeyCredential" />
<Class name="io.clientcore.core.http.client.JdkHttpClientBuilder" />
<Class name="io.clientcore.core.http.pipeline.KeyCredentialPolicy" />
<Class name="io.clientcore.core.http.pipeline.SetUserAgentPolicy" />
<Class name="io.clientcore.core.http.pipeline.UserAgentPolicy" />
<Class name="io.clientcore.core.implementation.http.rest.SwaggerMethodParser" />
<Class name="io.clientcore.core.implementation.instrumentation.otel.OTelInstrumentation" />
<Class name="io.clientcore.core.instrumentation.logging.ClientLogger" />
Expand All @@ -89,6 +90,7 @@
<Class name="io.clientcore.core.http.pipeline.SetUserAgentPolicyJavadocCodeSnippets" />
<Class name="io.clientcore.core.implementation.http.serializer.HttpResponseDecodeData" />
<Class name="io.clientcore.core.instrumentation.TelemetryForLibraryDevelopersJavaDocCodeSnippets" />
<Class name="io.clientcore.core.models.CloudEventJavaDocCodeSnippet" />
<Class name="io.clientcore.core.models.ContextJavaDocCodeSnippets" />
<Class name="io.clientcore.core.serialization.xml.implementation.aalto.in.ReaderScanner" />
<Class name="io.clientcore.core.utils.AuthorizationChallengeHandlerTests" />
Expand All @@ -115,7 +117,7 @@
<Or>
<Class name="io.clientcore.core.http.RestProxyTests" />
<Class name="io.clientcore.core.http.client.SimpleBasicAuthHttpProxyServer" />
<Class name="io.clientcore.core.implementation.http.client.DefaultHttpClientIT" />
<Class name="io.clientcore.core.implementation.http.client.JdkHttpClientIT" />
<Class name="io.clientcore.core.implementation.http.rest.RestProxyImplTests" />
<Class name="io.clientcore.core.implementation.serializer.AdditionalPropertiesSerializerTests" />
<Class name="io.clientcore.core.implementation.serializer.BinaryDataSerializationTests" />
Expand All @@ -125,6 +127,7 @@
<Class name="io.clientcore.core.implementation.serializer.JsonSerializableEndToEndTests" />
<Class name="io.clientcore.core.instrumentation.logging.ClientLoggerTests" />
<Class name="io.clientcore.core.instrumentation.logging.InstrumentationTestUtils" />
<Class name="io.clientcore.core.models.CloudEventTests" />
<Class name="io.clientcore.core.models.binarydata.BinaryDataJavaDocCodeSnippet" />
<Class name="io.clientcore.core.models.binarydata.BinaryDataTest" />
<Class name="io.clientcore.core.serialization.json.JsonReader" />
Expand Down Expand Up @@ -271,7 +274,6 @@
<Class name="io.clientcore.core.models.geo.GeoPolygonTests" />
<Class name="io.clientcore.core.serialization.json.implementation.StringBuilderWriterTests" />
<Class name="io.clientcore.core.serialization.json.models.JsonPatchDocument" />
<Class name="io.clientcore.core.utils.IterableStreamTests" />
</Or>
</Match>
<Match>
Expand All @@ -298,10 +300,10 @@
<Match>
<Bug pattern="PZLA_PREFER_ZERO_LENGTH_ARRAYS" />
<Or>
<Class name="io.clientcore.core.serialization.json.JsonSerializer" />
<Class name="io.clientcore.core.implementation.utils.XmlSerializer" />
<Class name="io.clientcore.core.models.binarydata.BinaryDataJavaDocCodeSnippet$MyJsonSerializer" />
<Class name="io.clientcore.core.serialization.json.JsonReader" />
<Class name="io.clientcore.core.serialization.json.JsonSerializer" />
<Class name="io.clientcore.core.serialization.xml.XmlSerializer" />
<Class name="io.clientcore.core.utils.Base64Uri" />
<Class name="io.clientcore.core.utils.CoreUtils" />
<Class name="io.clientcore.core.utils.serializers.MockSerializer" />
Expand All @@ -319,6 +321,7 @@
<Bug pattern="RR_NOT_CHECKED" />
<Or>
<Class name="io.clientcore.core.implementation.http.rest.LengthValidatingInputStreamTests" />
<Class name="io.clientcore.core.models.CloudEventTests" />
<Class name="io.clientcore.core.models.binarydata.BinaryDataJavaDocCodeSnippet" />
</Or>
</Match>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,9 @@
@Target({ TYPE, METHOD, CONSTRUCTOR, FIELD })
public @interface Metadata {
/**
* The conditions that apply to the annotated class.
* The properties that apply to the annotated class.
*
* @return The conditions that apply to the annotated class.
* @return The properties that apply to the annotated class.
*/
TypeConditions[] conditions() default { };

/**
* Indicates whether the class was automatically generated.
*
* @return {@code true} if the class is automatically generated, {@code false} otherwise.
*/
boolean generated() default false;
MetadataProperties[] properties() default { };
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* Enum that defines the conditions that can be applied to a class.
*/
public enum TypeConditions {
public enum MetadataProperties {
/**
* Indicates that a class is expected to provide a fluent API to end users. If a class is marked as this, checks can
* be made to ensure all APIs meet this expectation. Similarly, classes that are not marked as fluent should not
Expand All @@ -18,5 +18,10 @@ public enum TypeConditions {
* Indicates that a class is immutable. If a class is marked as this, checks can be made to ensure all fields in
* the class are final.
*/
IMMUTABLE
IMMUTABLE,

/**
* Indicates that a class is generated and will be overwritten by the code generator if modified.
*/
GENERATED
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
package io.clientcore.core.credentials;

import io.clientcore.core.annotations.Metadata;
import io.clientcore.core.annotations.TypeConditions;
import io.clientcore.core.annotations.MetadataProperties;

/**
* Represents a credential bag containing the key and the name of the key.
*
* @see NamedKeyCredential
*/
@Metadata(conditions = TypeConditions.IMMUTABLE)
@Metadata(properties = MetadataProperties.IMMUTABLE)
public final class NamedKey {
private final String name;
private final String key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

package io.clientcore.core.credentials.oauth;

import io.clientcore.core.annotations.Metadata;
import io.clientcore.core.annotations.MetadataProperties;

import java.time.OffsetDateTime;

/**
Expand All @@ -24,6 +27,7 @@
*
* @see io.clientcore.core.credentials
*/
@Metadata(properties = MetadataProperties.IMMUTABLE)
public class AccessToken {
private final String token;
private final OffsetDateTime expiresAt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package io.clientcore.core.credentials.oauth;

import io.clientcore.core.annotations.Metadata;
import io.clientcore.core.annotations.MetadataProperties;
import io.clientcore.core.instrumentation.logging.ClientLogger;
import io.clientcore.core.utils.CoreUtils;

Expand Down Expand Up @@ -36,6 +38,7 @@
*
* @see io.clientcore.core.credentials
*/
@Metadata(properties = MetadataProperties.FLUENT)
public class OAuthTokenRequestContext {
private static final ClientLogger LOGGER = new ClientLogger(OAuthTokenRequestContext.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import io.clientcore.core.implementation.http.rest.SwaggerMethodParser;
import io.clientcore.core.serialization.json.JsonSerializer;
import io.clientcore.core.serialization.ObjectSerializer;
import io.clientcore.core.implementation.utils.XmlSerializer;
import io.clientcore.core.serialization.xml.XmlSerializer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import io.clientcore.core.http.models.HttpRequest;
import io.clientcore.core.http.models.Response;
import io.clientcore.core.implementation.http.client.DefaultHttpClientProvider;
import io.clientcore.core.implementation.http.client.GlobalJdkHttpClient;

import java.io.IOException;

Expand Down Expand Up @@ -49,6 +49,6 @@ static HttpClient getNewInstance() {
*/
static HttpClient getSharedInstance() {
return HttpClientProvider.getProviders()
.create(HttpClientProvider::getSharedInstance, new DefaultHttpClientProvider()::getSharedInstance, null);
.create(HttpClientProvider::getSharedInstance, GlobalJdkHttpClient.HTTP_CLIENT::getHttpClient, null);
}
}
Loading