From 442052fd68123a88d42da667a71e3264093ff9bf Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:36:16 -0700 Subject: [PATCH 1/9] sync revert for component:abstractions --- .../com/microsoft/kiota/ApiException.java | 1 - .../microsoft/kiota/BaseRequestBuilder.java | 4 +-- .../microsoft/kiota/CaseInsensitiveMap.java | 5 +++- .../com/microsoft/kiota/Compatibility.java | 10 ++++++++ .../com/microsoft/kiota/MultipartBody.java | 21 ++++++++-------- .../kiota/NativeResponseHandler.java | 4 +-- .../microsoft/kiota/PeriodAndDuration.java | 1 + .../com/microsoft/kiota/RequestAdapter.java | 14 +++++------ .../com/microsoft/kiota/ResponseHandler.java | 11 ++++---- .../authentication/AccessTokenProvider.java | 2 +- .../AnonymousAuthenticationProvider.java | 8 +++--- .../ApiKeyAuthenticationProvider.java | 25 ++++++------------- .../AuthenticationProvider.java | 5 ++-- ...BaseBearerTokenAuthenticationProvider.java | 24 +++++------------- .../BasicAccessAuthenticationProvider.java | 4 +-- .../serialization/KiotaSerialization.java | 3 --- .../ParseNodeFactoryRegistry.java | 9 ++++--- .../kiota/serialization/ParseNodeHelper.java | 2 +- .../serialization/ParseNodeProxyFactory.java | 4 +-- .../SerializationWriterFactoryRegistry.java | 6 +++-- .../SerializationWriterProxyFactory.java | 2 +- .../store/BackingStoreFactorySingleton.java | 4 ++- .../kiota/store/InMemoryBackingStore.java | 4 ++- .../store/InMemoryBackingStoreFactory.java | 4 ++- .../ApiKeyAuthenticationProviderTest.java | 16 ++++++------ .../kiota/serialization/mocks/TestEntity.java | 7 ++++-- 26 files changed, 96 insertions(+), 104 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java b/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java index 10b9b4f7a..153247055 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java @@ -30,7 +30,6 @@ public ApiException(@Nonnull final Throwable cause) { * Gets the HTTP response status code * @return The response status code from the failed response. */ - @Nonnull public int getResponseStatusCode() { return responseStatusCode; } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestBuilder.java b/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestBuilder.java index 8be237f6f..9bb44aa42 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestBuilder.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestBuilder.java @@ -22,7 +22,7 @@ public abstract class BaseRequestBuilder { * @param urlTemplate Url template to use to build the URL for the current request builder */ protected BaseRequestBuilder(@Nonnull final RequestAdapter requestAdapter, @Nonnull final String urlTemplate) { - this(requestAdapter, urlTemplate, new HashMap()); + this(requestAdapter, urlTemplate, new HashMap<>()); } /** * Instantiates a new BaseRequestBuilder and sets the default values. @@ -33,7 +33,7 @@ protected BaseRequestBuilder(@Nonnull final RequestAdapter requestAdapter, @Nonn protected BaseRequestBuilder(@Nonnull final RequestAdapter requestAdapter, @Nonnull final String urlTemplate, @Nonnull final HashMap pathParameters) { this.requestAdapter = Objects.requireNonNull(requestAdapter); this.urlTemplate = Objects.requireNonNull(urlTemplate); - this.pathParameters = new HashMap(Objects.requireNonNull(pathParameters)); + this.pathParameters = new HashMap<>(Objects.requireNonNull(pathParameters)); } /** * Instantiates a new BaseRequestBuilder and sets the default values. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java b/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java index 625de8af4..03cc40f27 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java @@ -14,9 +14,12 @@ import jakarta.annotation.Nullable; /** - * A map that is case insensitive on the keys + * A map that is case-insensitive on the keys */ public class CaseInsensitiveMap implements Map>{ + public CaseInsensitiveMap() { + // default constructor + } private final HashMap> internalMap = new HashMap<>(); /** diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/Compatibility.java b/components/abstractions/src/main/java/com/microsoft/kiota/Compatibility.java index 8a01f1297..558fd8b1d 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/Compatibility.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/Compatibility.java @@ -5,6 +5,8 @@ import java.io.InputStream; import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + /** * Compatibility methods for android */ @@ -30,4 +32,12 @@ public static byte[] readAllBytes(@Nonnull final InputStream inputStream) throws return outputStream.toByteArray(); } } + /** INTERNAL METHOD, DO NOT USE DIRECTLY + * Checks if the string is null or empty or blank + * @param str the string to check + * @return true if the string is null or empty or blank + */ + public static boolean isBlank(@Nullable final String str) { + return str == null || str.trim().isEmpty(); + } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index 2f272c8cb..1a08aa5c6 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -2,11 +2,7 @@ import java.io.IOException; import java.io.InputStream; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.function.Consumer; import jakarta.annotation.Nonnull; @@ -24,7 +20,10 @@ public class MultipartBody implements Parsable { @Nonnull private final String boundary = UUID.randomUUID().toString().replace("-", ""); - /** @return the boundary string for the multipart body. */ + /** + * Gets the boundary string for the multipart body. + * @return the boundary string for the multipart body. + */ @Nonnull public String getBoundary() { return boundary; @@ -43,14 +42,14 @@ public String getBoundary() { */ public void addOrReplacePart(@Nonnull final String name, @Nonnull final String contentType, @Nonnull final T value) { Objects.requireNonNull(value); - if (Strings.isNullOrEmpty(contentType) || contentType.isBlank()) + if (Compatibility.isBlank(contentType)) throw new IllegalArgumentException("contentType cannot be blank or empty"); - if (Strings.isNullOrEmpty(name) || name.isBlank()) + if (Compatibility.isBlank(name)) throw new IllegalArgumentException("name cannot be blank or empty"); final String normalizedName = normalizePartName(name); originalNames.put(normalizedName, name); - parts.put(normalizedName, Map.entry(contentType, value)); + parts.put(normalizedName, new AbstractMap.SimpleEntry<>(contentType, value)); } private final Map> parts = new HashMap<>(); private final Map originalNames = new HashMap<>(); @@ -66,7 +65,7 @@ private String normalizePartName(@Nonnull final String original) @Nullable public Object getPartValue(@Nonnull final String partName) { - if (Strings.isNullOrEmpty(partName) || partName.isBlank()) + if (Compatibility.isBlank(partName)) throw new IllegalArgumentException("partName cannot be blank or empty"); final String normalizedName = normalizePartName(partName); final Map.Entry candidate = parts.get(normalizedName); @@ -81,7 +80,7 @@ public Object getPartValue(@Nonnull final String partName) */ public boolean removePart(@Nonnull final String partName) { - if (Strings.isNullOrEmpty(partName) || partName.isBlank()) + if (Compatibility.isBlank(partName)) throw new IllegalArgumentException("partName cannot be blank or empty"); final String normalizedName = normalizePartName(partName); final Object candidate = parts.remove(normalizedName); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java index 76056e543..604969e41 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java @@ -2,7 +2,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -18,11 +17,10 @@ public class NativeResponseHandler implements ResponseHandler { private HashMap> errorMappings; @Override @Nonnull - public CompletableFuture handleResponseAsync(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) { + public void handleResponseAsync(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) { this.value = response; if(errorMappings != null) this.errorMappings = new HashMap<>(errorMappings); - return CompletableFuture.completedFuture(null); } /** * Set the error mappings for the response to use when deserializing failed responses bodies. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/PeriodAndDuration.java b/components/abstractions/src/main/java/com/microsoft/kiota/PeriodAndDuration.java index 3ca43d921..48e993f24 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/PeriodAndDuration.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/PeriodAndDuration.java @@ -114,6 +114,7 @@ public static PeriodAndDuration ofPeriodAndDuration(@Nonnull PeriodAndDuration p return new PeriodAndDuration(periodAndDuration.getPeriod(), periodAndDuration.getDuration()); } /** + * Parses a string to produce a {@code PeriodAndDuration}. * @param stringValue the {@code String} parse from. * @return parsed instance of {@code PeriodAndDuration} */ diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java index 6bce04eb0..4fda0216a 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java @@ -35,7 +35,7 @@ public interface RequestAdapter { */ @Nullable @SuppressWarnings("LambdaLast") - CompletableFuture sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); + ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection. * @param requestInfo the request info to execute. @@ -46,7 +46,7 @@ public interface RequestAdapter { */ @Nullable @SuppressWarnings("LambdaLast") - CompletableFuture> sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); + List sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model. * @param requestInfo the request info to execute. @@ -56,7 +56,7 @@ public interface RequestAdapter { * @return a {@link CompletableFuture} with the deserialized primitive response model. */ @Nullable - CompletableFuture sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + ModelType sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive collection response model. * @param requestInfo the request info to execute. @@ -66,7 +66,7 @@ public interface RequestAdapter { * @return a {@link CompletableFuture} with the deserialized primitive collection response model. */ @Nullable - CompletableFuture> sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + List sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** Executes the HTTP request specified by the given RequestInformation and returns the deserialized enum value. @@ -77,7 +77,7 @@ public interface RequestAdapter { * @return a {@link CompletableFuture} with the deserialized primitive response model. */ @Nullable - > CompletableFuture sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + > ModelType sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** Executes the HTTP request specified by the given RequestInformation and returns the deserialized enum collection value. @@ -88,7 +88,7 @@ public interface RequestAdapter { * @return a {@link CompletableFuture} with the deserialized primitive response model. */ @Nullable - > CompletableFuture> sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + > List sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** * Sets The base url for every request. * @param baseUrl The base url for every request. @@ -107,5 +107,5 @@ public interface RequestAdapter { * @return the native HTTP request. */ @Nonnull - CompletableFuture convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo); + T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo); } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java index 532840621..6490e07fb 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java @@ -1,7 +1,6 @@ package com.microsoft.kiota; import java.util.HashMap; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -13,12 +12,12 @@ public interface ResponseHandler { /** * Callback method that is invoked when a response is received. - * @param response The native response object. - * @param errorMappings the error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. + * + * @param response The native response object. + * @param errorMappings the error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. * @param The type of the native response object. - * @param The type of the response model object. - * @return A CompletableFuture that represents the asynchronous operation and contains the deserialized response. + * @param The type of the response model object. */ @Nonnull - CompletableFuture handleResponseAsync(@Nonnull final NativeResponseType response, @Nullable final HashMap> errorMappings); + void handleResponseAsync(@Nonnull final NativeResponseType response, @Nullable final HashMap> errorMappings); } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java index 2d5638199..19200de26 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java @@ -16,7 +16,7 @@ public interface AccessTokenProvider { * @return A CompletableFuture that holds the access token. */ @Nonnull - CompletableFuture getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map additionalAuthenticationContext); + String getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map additionalAuthenticationContext); /** * Returns the allowed hosts validator. * @return The allowed hosts validator. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java index c9d8b08eb..93536e173 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java @@ -3,7 +3,6 @@ import com.microsoft.kiota.RequestInformation; import java.util.Map; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -13,8 +12,7 @@ public class AnonymousAuthenticationProvider implements AuthenticationProvider { /** Default constructor for the anonymous authentication provider. */ public AnonymousAuthenticationProvider() {} /** {@inheritDoc} */ - @Nonnull - public CompletableFuture authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { - return CompletableFuture.completedFuture(null); - } + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { + //This authentication provider does not perform any authentication. + } } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java index 8bbfdfefe..67066058d 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java @@ -49,10 +49,8 @@ public ApiKeyAuthenticationProvider(@Nonnull final String apiKey, @Nonnull final private static final String parentSpanKey = "parent-span"; /** {@inheritDoc} */ @Override - @Nonnull - public CompletableFuture authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException { Objects.requireNonNull(request); - final CompletableFuture resultFuture = new CompletableFuture<>(); Span span; if(additionalAuthenticationContext != null && additionalAuthenticationContext.containsKey(parentSpanKey) && additionalAuthenticationContext.get(parentSpanKey) instanceof Span) { final Span parentSpan = (Span) additionalAuthenticationContext.get(parentSpanKey); @@ -64,14 +62,11 @@ public CompletableFuture authenticateRequest(@Nonnull final RequestInforma final URI uri = request.getUri(); if(uri == null || !validator.isUrlHostValid(uri)) { span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", false); - return CompletableFuture.completedFuture(null); + return; } if(!uri.getScheme().equalsIgnoreCase("https")) { span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", false); - final Exception result = new IllegalArgumentException("Only https is supported"); - span.recordException(result); - resultFuture.completeExceptionally(result); - return resultFuture; + throw new IllegalArgumentException("Only https is supported"); } span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", true); @@ -83,17 +78,13 @@ public CompletableFuture authenticateRequest(@Nonnull final RequestInforma request.setUri(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery() == null ? paramName + "=" + apiKey : uri.getQuery() + "&" + paramName + "=" + apiKey, uri.getFragment())); break; default: - resultFuture.completeExceptionally(new IllegalArgumentException("Unsupported key location")); - } - if (!resultFuture.isDone()) { - resultFuture.complete(null); + throw new IllegalArgumentException("Unsupported key location"); } - return resultFuture; - } catch (URISyntaxException e) { + } catch (URISyntaxException | IllegalArgumentException e ) { span.recordException(e); - resultFuture.completeExceptionally(e); - return resultFuture; - } finally { + throw e; + } + finally { span.end(); } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java index 6e808ce76..8ebef359c 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java @@ -2,6 +2,7 @@ import com.microsoft.kiota.RequestInformation; +import java.net.URISyntaxException; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -14,8 +15,6 @@ public interface AuthenticationProvider { * Authenticates the application request. * @param request the request to authenticate. * @param additionalAuthenticationContext Additional authentication context to pass to the authentication library. - * @return a CompletableFuture to await for the authentication to be completed. */ - @Nonnull - CompletableFuture authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext); + void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException; } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java index 42390c133..4ab0980cf 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java @@ -2,6 +2,7 @@ import com.microsoft.kiota.RequestInformation; +import com.google.common.base.Strings; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.CompletableFuture; @@ -24,9 +25,8 @@ public BaseBearerTokenAuthenticationProvider(@Nonnull final AccessTokenProvider private final static String authorizationHeaderKey = "Authorization"; private final static String ClaimsKey = "claims"; @Nonnull - public CompletableFuture authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException { Objects.requireNonNull(request); - if (request.headers.containsKey(authorizationHeaderKey) && additionalAuthenticationContext != null && additionalAuthenticationContext.containsKey(ClaimsKey)) @@ -35,23 +35,11 @@ public CompletableFuture authenticateRequest(@Nonnull final RequestInforma } if(!request.headers.containsKey(authorizationHeaderKey)) { final URI targetUri; - try { - targetUri = request.getUri(); - } catch (URISyntaxException e) { - final CompletableFuture result = new CompletableFuture<>(); - result.completeExceptionally(e); - return result; + targetUri = request.getUri(); + String accessToken = this.accessTokenProvider.getAuthorizationToken(targetUri, additionalAuthenticationContext); + if(!Strings.isNullOrEmpty(accessToken)) { + request.headers.add(authorizationHeaderKey, "Bearer " + accessToken); } - return this.accessTokenProvider.getAuthorizationToken(targetUri, additionalAuthenticationContext) - .thenApply(token -> { - if(token != null && !token.isEmpty()) { - // Not an error, just no need to authenticate as we might have been given an external URL from the main API (large file upload, etc.) - request.headers.add(authorizationHeaderKey, "Bearer " + token); - } - return null; - }); - } else { - return CompletableFuture.completedFuture(null); } } } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java index cb062238a..d05faf6c7 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java @@ -35,9 +35,7 @@ public BasicAccessAuthenticationProvider(@Nonnull final String username, @Nonnul /** {@inheritDoc} */ @Override - @Nonnull - public CompletableFuture authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { request.headers.add(AUTHORIZATION_HEADER_KEY, BASIC + encoded); - return CompletableFuture.completedFuture(null); } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java index db29d65e8..7b886a399 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java @@ -1,7 +1,4 @@ package com.microsoft.kiota.serialization; -/** - * Serialization helpers for kiota models. - */ import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java index 82d784e12..60dcd3149 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java @@ -2,6 +2,7 @@ import java.io.InputStream; import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -12,17 +13,19 @@ */ public class ParseNodeFactoryRegistry implements ParseNodeFactory { /** Default constructor for the registry. */ - public ParseNodeFactoryRegistry() {} + public ParseNodeFactoryRegistry() { + // Default constructor for the registry. + } /** Default singleton instance of the registry to be used when registering new factories that should be available by default. */ public static final ParseNodeFactoryRegistry defaultInstance = new ParseNodeFactoryRegistry(); /** List of factories that are registered by content type. */ @Nonnull - public final HashMap contentTypeAssociatedFactories = new HashMap<>(); + public final Map contentTypeAssociatedFactories = new HashMap<>(); @Nonnull public String getValidContentType() { throw new UnsupportedOperationException("The registry supports multiple content types. Get the registered factory instead."); } - private static Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); + private static final Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); @Override @Nonnull public ParseNode getParseNode(@Nonnull final String contentType, @Nonnull final InputStream rawResponse) { diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeHelper.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeHelper.java index e125a8127..2e3707578 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeHelper.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeHelper.java @@ -10,7 +10,7 @@ /** Utility methods to reduce the amount of code being generated. */ public class ParseNodeHelper { /** Default constructor */ - public ParseNodeHelper() {} + private ParseNodeHelper() {} /** * Merges the given fields deserializers for an intersection type into a single collection. * @param targets The collection of deserializers to merge. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeProxyFactory.java index 9119f22c0..b5f4a9462 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/ParseNodeProxyFactory.java @@ -37,7 +37,7 @@ public ParseNode getParseNode(@Nonnull final String contentType, @Nonnull final final ParseNode node = _concrete.getParseNode(contentType, rawResponse); final Consumer originalOnBefore = node.getOnBeforeAssignFieldValues(); final Consumer originalOnAfter = node.getOnAfterAssignFieldValues(); - node.setOnBeforeAssignFieldValues((x) -> { + node.setOnBeforeAssignFieldValues(x -> { if(this._onBefore != null) { this._onBefore.accept(x); } @@ -45,7 +45,7 @@ public ParseNode getParseNode(@Nonnull final String contentType, @Nonnull final originalOnBefore.accept(x); } }); - node.setOnAfterAssignFieldValues((x) -> { + node.setOnAfterAssignFieldValues(x -> { if(this._onAfter != null) { this._onAfter.accept(x); } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 46adcea05..141096540 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -8,7 +8,9 @@ /** This factory holds a list of all the registered factories for the various types of nodes. */ public class SerializationWriterFactoryRegistry implements SerializationWriterFactory { /** Default constructor for the registry. */ - public SerializationWriterFactoryRegistry() {} + public SerializationWriterFactoryRegistry() { + // Default constructor for the registry. + } /** Default singleton instance of the registry to be used when registering new factories that should be available by default. */ public static final SerializationWriterFactoryRegistry defaultInstance = new SerializationWriterFactoryRegistry(); /** List of factories that are registered by content type. */ @@ -18,7 +20,7 @@ public SerializationWriterFactoryRegistry() {} public String getValidContentType() { throw new UnsupportedOperationException("The registry supports multiple content types. Get the registered factory instead."); } - private static Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); + private static final Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); @Override @Nonnull public SerializationWriter getSerializationWriter(@Nonnull final String contentType) { diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java index e0f08cef3..8dee1ac5e 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java @@ -24,7 +24,7 @@ public String getValidContentType() { * @param onAfterSerialization the callback to invoke after the serialization of any model object. * @param onStartObjectSerialization the callback to invoke when the serialization of a model object starts. */ - public SerializationWriterProxyFactory(@Nonnull final SerializationWriterFactory concrete, + protected SerializationWriterProxyFactory(@Nonnull final SerializationWriterFactory concrete, @Nullable final Consumer onBeforeSerialization, @Nullable final Consumer onAfterSerialization, @Nullable final BiConsumer onStartObjectSerialization) { diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java index c2ba544d2..27049a2f8 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java @@ -5,7 +5,9 @@ /** This class is used to register the backing store factory. */ public class BackingStoreFactorySingleton { /** Default constructor */ - public BackingStoreFactorySingleton() {} + public BackingStoreFactorySingleton() { + // default constructor + } /** The backing store factory singleton instance. */ @Nonnull public static BackingStoreFactory instance = new InMemoryBackingStoreFactory(); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java index 3c7872f5d..ed0b83512 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java @@ -18,7 +18,9 @@ /** In-memory implementation of the backing store. Allows for dirty tracking of changes. */ public class InMemoryBackingStore implements BackingStore { /** Creates a new instance of the backing store. */ - public InMemoryBackingStore() {} + public InMemoryBackingStore() { + // default constructor + } private boolean isInitializationCompleted = true; private boolean returnOnlyChangedValues; private final Map> store = new HashMap<>(); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java index 7a0164184..bd88686fb 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java @@ -5,7 +5,9 @@ /** This class is used to create instances of InMemoryBackingStore */ public class InMemoryBackingStoreFactory implements BackingStoreFactory { /** Creates a new instance of the factory */ - public InMemoryBackingStoreFactory() {} + public InMemoryBackingStoreFactory() { + // default constructor + } @Override @Nonnull public BackingStore createBackingStore() { diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java index 64a5ba819..7d7b2b211 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java @@ -11,7 +11,7 @@ public class ApiKeyAuthenticationProviderTest { @Test - public void DefensivePrograming() { + void DefensivePrograming() { assertThrows(IllegalArgumentException.class, () -> new ApiKeyAuthenticationProvider("", "paramName", ApiKeyLocation.QUERY_PARAMETER)); assertThrows(IllegalArgumentException.class, () -> new ApiKeyAuthenticationProvider("key", "", ApiKeyLocation.QUERY_PARAMETER)); @@ -20,34 +20,32 @@ public void DefensivePrograming() { } @Test - public void AddsInQueryParameter() throws IllegalStateException, URISyntaxException { + void AddsInQueryParameter() throws IllegalStateException, URISyntaxException { var value = new ApiKeyAuthenticationProvider("key", "param", ApiKeyLocation.QUERY_PARAMETER); var request = new RequestInformation() {{ urlTemplate = "https://localhost{?param1}"; }}; - value.authenticateRequest(request, null).join(); - assertNull(request.headers.get("param")); + value.authenticateRequest(request, null); assertEquals("https://localhost?param=key", request.getUri().toString()); } @Test - public void AddsInQueryParameterWithOtherParameters() throws IllegalStateException, URISyntaxException { + void AddsInQueryParameterWithOtherParameters() throws IllegalStateException, URISyntaxException { var value = new ApiKeyAuthenticationProvider("key", "param", ApiKeyLocation.QUERY_PARAMETER); var request = new RequestInformation() {{ urlTemplate = "https://localhost{?param1}"; }}; request.addQueryParameter("param1", "value1"); - value.authenticateRequest(request, null).join(); - assertNull(request.headers.get("param")); + value.authenticateRequest(request, null); assertEquals("https://localhost?param1=value1¶m=key", request.getUri().toString()); } @Test - public void AddsInHeaders() throws IllegalStateException, URISyntaxException { + void AddsInHeaders() throws IllegalStateException, URISyntaxException { var value = new ApiKeyAuthenticationProvider("key", "param", ApiKeyLocation.HEADER); var request = new RequestInformation() {{ urlTemplate = "https://localhost{?param1}"; }}; - value.authenticateRequest(request, null).join(); + value.authenticateRequest(request, null); assertEquals(new HashSet() {{ add("key"); }}, request.headers.get("param")); assertEquals("https://localhost", request.getUri().toString()); } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestEntity.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestEntity.java index d11c228d8..48c41f1ab 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestEntity.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestEntity.java @@ -14,6 +14,7 @@ import com.microsoft.kiota.serialization.Parsable; import com.microsoft.kiota.serialization.AdditionalDataHolder; +import jakarta.annotation.Nonnull; public class TestEntity implements Parsable, AdditionalDataHolder { private String _id; @@ -81,7 +82,8 @@ public void setCreatedDateTime(OffsetDateTime value) { this._createdDateTime = value; } - @Override + @Nonnull + @Override public Map> getFieldDeserializers() { return new HashMap<>() {{ put("id", (n) -> { @@ -109,7 +111,7 @@ public Map> getFieldDeserializers() { } @Override - public void serialize(SerializationWriter writer) { + public void serialize(@Nonnull SerializationWriter writer) { Objects.requireNonNull(writer); writer.writeStringValue("id", getId()); writer.writeStringValue("officeLocation", getOfficeLocation()); @@ -123,6 +125,7 @@ public void serialize(SerializationWriter writer) { private final Map _additionalData = new HashMap<>(); + @Nonnull @Override public Map getAdditionalData() { return _additionalData; From eb7005c23d83f60ff208eacb5ba393986d86c5ab Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:55:49 -0700 Subject: [PATCH 2/9] sync revert for component:authentication --- .../AzureIdentityAccessTokenProvider.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java index 4c176bcf9..3c2e754c6 100644 --- a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java +++ b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java @@ -69,7 +69,7 @@ public AzureIdentityAccessTokenProvider(@Nonnull final TokenCredential tokenCred private final static String ClaimsKey = "claims"; private final static String parentSpanKey = "parent-span"; @Nonnull - public CompletableFuture getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map additionalAuthenticationContext) { + public String getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map additionalAuthenticationContext) { Span span; if(additionalAuthenticationContext != null && additionalAuthenticationContext.containsKey(parentSpanKey) && additionalAuthenticationContext.get(parentSpanKey) instanceof Span) { final Span parentSpan = (Span) additionalAuthenticationContext.get(parentSpanKey); @@ -80,15 +80,11 @@ public CompletableFuture getAuthorizationToken(@Nonnull final URI uri, @ try(final Scope scope = span.makeCurrent()) { if(!_hostValidator.isUrlHostValid(uri)) { span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", false); - return CompletableFuture.completedFuture(""); + return ""; } if(!uri.getScheme().equalsIgnoreCase("https")) { span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", false); - final Exception result = new IllegalArgumentException("Only https is supported"); - span.recordException(result); - final CompletableFuture resultFuture = new CompletableFuture<>(); - resultFuture.completeExceptionally(result); - return resultFuture; + throw new IllegalArgumentException("Only https is supported"); } span.setAttribute("com.microsoft.kiota.authentication.is_url_valid", true); @@ -113,8 +109,13 @@ public CompletableFuture getAuthorizationToken(@Nonnull final URI uri, @ if(decodedClaim != null && !decodedClaim.isEmpty()) { context.setClaims(decodedClaim); } - return this.creds.getToken(context).toFuture().thenApply(r -> r.getToken()); - } finally { + return this.creds.getToken(context).toFuture().join().getToken(); + } + catch (IllegalArgumentException e){ + span.recordException(e); + throw e; + } + finally { span.end(); } } From 9e983263f9e273e75f02d69eee7d6a0de6038be2 Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:02:36 -0700 Subject: [PATCH 3/9] begin sync revert for component:http --- .../com/microsoft/kiota/RequestAdapter.java | 7 +- .../kiota/http/OkHttpRequestAdapter.java | 115 ++++++++---------- .../middleware/HeadersInspectionHandler.java | 10 +- .../kiota/http/OkHttpRequestAdapterTest.java | 11 +- 4 files changed, 70 insertions(+), 73 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java index 4fda0216a..9858671f7 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java @@ -1,5 +1,8 @@ package com.microsoft.kiota; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.concurrent.CompletableFuture; import java.util.HashMap; import java.util.List; @@ -35,7 +38,7 @@ public interface RequestAdapter { */ @Nullable @SuppressWarnings("LambdaLast") - ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); + ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) throws IOException, URISyntaxException; /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection. * @param requestInfo the request info to execute. @@ -107,5 +110,5 @@ public interface RequestAdapter { * @return the native HTTP request. */ @Nonnull - T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo); + T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo) throws URISyntaxException, MalformedURLException; } \ No newline at end of file diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index 222b17e6b..e936488f0 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -168,7 +168,7 @@ public void enableBackingStore(@Nullable final BackingStoreFactory backingStoreF } } @Nullable - public CompletableFuture> sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { + public List sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); Objects.requireNonNull(factory, "parameter factory cannot be null"); @@ -198,11 +198,11 @@ public CompletableFuture> sendColle deserializationSpan.end(); } } catch(ApiException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(ex); }}; } catch(IOException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); }}; } finally { @@ -240,7 +240,7 @@ private Span startSpan(@Nonnull final RequestInformation requestInfo, @Nonnull f @Nonnull public static final String eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked"; @Nullable - public CompletableFuture sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { + public ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) throws IOException, URISyntaxException { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); Objects.requireNonNull(factory, "parameter factory cannot be null"); @@ -269,16 +269,9 @@ public CompletableFuture sendAsync(@Nonn } finally { deserializationSpan.end(); } - } catch(ApiException ex) { - span.recordException(ex); - return new CompletableFuture(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { + } catch(ApiException | IOException ex) { span.recordException(ex); - return new CompletableFuture(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; + throw ex; } finally { closeResponse(closeResponse, response); } @@ -306,7 +299,7 @@ private String getMediaTypeAndSubType(@Nonnull final MediaType mediaType) { return mediaType.type() + "/" + mediaType.subtype(); } @Nullable - public CompletableFuture sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + public ModelType sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); final Span span = startSpan(requestInfo, "sendPrimitiveAsync"); @@ -381,11 +374,11 @@ public CompletableFuture sendPrimitiveAsync(@Nonnull fina } } } catch(ApiException ex) { - return new CompletableFuture(){{ + return new ModelType(){{ this.completeExceptionally(ex); }}; } catch(IOException ex) { - return new CompletableFuture(){{ + return new ModelType(){{ this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); }}; } finally { @@ -401,7 +394,7 @@ public CompletableFuture sendPrimitiveAsync(@Nonnull fina } } @Nullable - public > CompletableFuture sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + public > ModelType sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); final Span span = startSpan(requestInfo, "sendEnumAsync"); @@ -430,11 +423,11 @@ public > CompletableFuture sendEnum deserializationSpan.end(); } } catch(ApiException ex) { - return new CompletableFuture(){{ + return new ModelType(){{ this.completeExceptionally(ex); }}; } catch(IOException ex) { - return new CompletableFuture(){{ + return new ModelType(){{ this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); }}; } finally { @@ -450,7 +443,7 @@ public > CompletableFuture sendEnum } } @Nullable - public > CompletableFuture> sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + public > List sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); final Span span = startSpan(requestInfo, "sendEnumCollectionAsync"); @@ -479,11 +472,11 @@ public > CompletableFuture> se deserializationSpan.end(); } } catch(ApiException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(ex); }}; } catch(IOException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); }}; } finally { @@ -499,7 +492,7 @@ public > CompletableFuture> se } } @Nullable - public CompletableFuture> sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + public List sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); final Span span = startSpan(requestInfo, "sendPrimitiveCollectionAsync"); @@ -528,11 +521,11 @@ public CompletableFuture> sendPrimitiveCollectionAsy deserializationSpan.end(); } } catch(ApiException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(ex); }}; } catch(IOException ex) { - return new CompletableFuture>(){{ + return new List(){{ this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); }}; } finally { @@ -642,31 +635,22 @@ private Response throwIfFailedResponse(@Nonnull final Response response, @Nonnul } } private final static String claimsKey = "claims"; - private CompletableFuture getHttpResponseMessage(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) { + private Response getHttpResponseMessage(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) throws IOException, URISyntaxException { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getHttpResponseMessage").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { this.setBaseUrlForRequestInformation(requestInfo); - final Map additionalContext = new HashMap() {{ - put("parent-span", span); - }}; + final Map additionalContext = new HashMap(); + additionalContext.put("parent-span", span); if(claims != null && !claims.isEmpty()) { additionalContext.put(claimsKey, claims); } - return this.authProvider.authenticateRequest(requestInfo, additionalContext) - .thenCompose(x -> { - try { - final OkHttpCallbackFutureWrapper wrapper = new OkHttpCallbackFutureWrapper(); - this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).enqueue(wrapper); - return wrapper.future; - } catch (URISyntaxException | MalformedURLException ex) { - spanForAttributes.recordException(ex); - final CompletableFuture result = new CompletableFuture(); - result.completeExceptionally(ex); - return result; - } - }) - .thenApply(x -> { + this.authProvider.authenticateRequest(requestInfo, additionalContext); + final OkHttpCallbackFutureWrapper wrapper = new OkHttpCallbackFutureWrapper(); + this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).enqueue(wrapper); + + + Response response = wrapper.future.thenApply(x -> { final String contentLengthHeaderValue = getHeaderValue(x, "Content-Length"); if(contentLengthHeaderValue != null && !contentLengthHeaderValue.isEmpty()) { final Integer contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); @@ -679,8 +663,12 @@ private CompletableFuture getHttpResponseMessage(@Nonnull final Reques spanForAttributes.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, x.code()); spanForAttributes.setAttribute(SemanticAttributes.HTTP_FLAVOR, x.protocol().toString().toUpperCase(Locale.ROOT)); return x; - }) - .thenCompose(x -> this.retryCAEResponseIfRequired(x, requestInfo, span, spanForAttributes, claims)); + }).join(); + return this.retryCAEResponseIfRequired(response, requestInfo, span, spanForAttributes, claims); + } + catch (URISyntaxException | IOException ex) { + spanForAttributes.recordException(ex); + throw ex; } finally { span.end(); } @@ -695,12 +683,13 @@ private String getHeaderValue(final Response response, String key) { } return null; } - private final static Pattern bearerPattern = Pattern.compile("^Bearer\\s.*", Pattern.CASE_INSENSITIVE); - private final static Pattern claimsPattern = Pattern.compile("\\s?claims=\"([^\"]+)\"", Pattern.CASE_INSENSITIVE); + + private static final Pattern bearerPattern = Pattern.compile("^Bearer\\s.*", Pattern.CASE_INSENSITIVE); + private static final Pattern claimsPattern = Pattern.compile("\\s?claims=\"([^\"]+)\"", Pattern.CASE_INSENSITIVE); /** Key used for events when an authentication challenge is returned by the API */ @Nonnull public static final String authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received"; - private CompletableFuture retryCAEResponseIfRequired(@Nonnull final Response response, @Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) { + private Response retryCAEResponseIfRequired(@Nonnull final Response response, @Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) throws IOException, URISyntaxException { final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("retryCAEResponseIfRequired").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { final String responseClaims = this.getClaimsFromResponse(response, requestInfo, claims); @@ -710,9 +699,7 @@ private CompletableFuture retryCAEResponseIfRequired(@Nonnull final Re requestInfo.content.reset(); } catch (IOException ex) { spanForAttributes.recordException(ex); - return new CompletableFuture(){{ - this.completeExceptionally(ex); - }}; + throw ex; } } closeResponse(true, response); @@ -721,7 +708,10 @@ private CompletableFuture retryCAEResponseIfRequired(@Nonnull final Re return this.getHttpResponseMessage(requestInfo, span, spanForAttributes, responseClaims); } - return CompletableFuture.completedFuture(response); + return response; + } catch (URISyntaxException e) { + spanForAttributes.recordException(e); + throw e; } finally { span.end(); } @@ -760,18 +750,17 @@ private void setBaseUrlForRequestInformation(@Nonnull final RequestInformation r /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Nonnull - public CompletableFuture convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo) { + public T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo) throws URISyntaxException, MalformedURLException { Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); final Span span = startSpan(requestInfo, "convertToNativeRequestAsync"); try(final Scope scope = span.makeCurrent()) { - return this.authProvider.authenticateRequest(requestInfo, null) - .thenApply(x -> { - try { - return (T) getRequestFromRequestInformation(requestInfo, span, span); - } catch (MalformedURLException | URISyntaxException e) { - throw new RuntimeException(e); - } - }); + this.authProvider.authenticateRequest(requestInfo, null); + try { + return (T) getRequestFromRequestInformation(requestInfo, span, span); + } catch (MalformedURLException | URISyntaxException e) { + span.recordException(e); + throw e; + } } finally { span.end(); } @@ -815,7 +804,7 @@ public MediaType contentType() { } @Override - public void writeTo(BufferedSink sink) throws IOException { + public void writeTo(@Nonnull BufferedSink sink) throws IOException { sink.writeAll(Okio.source(requestInfo.content)); } @@ -849,7 +838,7 @@ public void writeTo(BufferedSink sink) throws IOException { requestBuilder.tag(Span.class, parentSpan); final Request request = requestBuilder.build(); final List contentLengthHeader = request.headers().values("Content-Length"); - if(contentLengthHeader != null && contentLengthHeader.size() > 0) { + if(contentLengthHeader != null && !contentLengthHeader.isEmpty()) { final String firstEntryValue = contentLengthHeader.get(0); if(firstEntryValue != null && !firstEntryValue.isEmpty()) { spanForAttributes.setAttribute(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, Long.parseLong(firstEntryValue)); diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/HeadersInspectionHandler.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/HeadersInspectionHandler.java index 8d5976bac..03bca4795 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/HeadersInspectionHandler.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/HeadersInspectionHandler.java @@ -4,6 +4,7 @@ import kotlin.Pair; import java.io.IOException; +import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -56,13 +57,17 @@ public Response intercept(final Chain chain) throws IOException { } if (inspectionOption.getInspectRequestHeaders()) { for(final Pair header : request.headers()) { - inspectionOption.getRequestHeaders().put(header.getFirst(), Set.of(header.getSecond())); + HashSet value = new HashSet<>(); + value.add(header.getSecond()); + inspectionOption.getRequestHeaders().put(header.getFirst(), value); } } final Response response = chain.proceed(request); if (inspectionOption.getInspectResponseHeaders()) { for(final Pair header : response.headers()) { - inspectionOption.getResponseHeaders().put(header.getFirst(), Set.of(header.getSecond())); + HashSet value = new HashSet<>(); + value.add(header.getSecond()); + inspectionOption.getResponseHeaders().put(header.getFirst(), value); } } return response; @@ -75,5 +80,4 @@ public Response intercept(final Chain chain) throws IOException { } } } - } diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java index c9b22f2b5..312ac17d3 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.*; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; import okio.Okio; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; @@ -46,14 +47,14 @@ public class OkHttpRequestAdapterTest { @ParameterizedTest @EnumSource(value = HttpMethod.class, names = {"PUT", "POST", "PATCH"}) public void PostRequestsShouldHaveEmptyBody(HttpMethod method) throws Exception { // Unexpected exception thrown: java.lang.IllegalArgumentException: method POST must have a request body. - final var authenticationProviderMock = mock(AuthenticationProvider.class); - final var adapter = new OkHttpRequestAdapter(authenticationProviderMock) { + final AuthenticationProvider authenticationProviderMock = mock(AuthenticationProvider.class); + final OkHttpRequestAdapter adapter = new OkHttpRequestAdapter(authenticationProviderMock) { public Request test() throws Exception { - var ri = new RequestInformation(); + RequestInformation ri = new RequestInformation(); ri.httpMethod = method; ri.urlTemplate = "http://localhost:1234"; - var span1 = GlobalOpenTelemetry.getTracer("").spanBuilder("").startSpan(); - var span2 = GlobalOpenTelemetry.getTracer("").spanBuilder("").startSpan(); + Span span1 = GlobalOpenTelemetry.getTracer("").spanBuilder("").startSpan(); + Span span2 = GlobalOpenTelemetry.getTracer("").spanBuilder("").startSpan(); return this.getRequestFromRequestInformation(ri, span1, span2); } }; From 9cb62a893e1c3fdb9a60dbd95953e2da2ac63029 Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:02:18 -0800 Subject: [PATCH 4/9] Async -> Sync revert revision --- .../kiota/NativeResponseHandler.java | 4 +- .../com/microsoft/kiota/RequestAdapter.java | 30 +- .../com/microsoft/kiota/ResponseHandler.java | 4 +- .../kiota/ResponseHandlerOption.java | 1 + .../authentication/AccessTokenProvider.java | 3 +- .../AnonymousAuthenticationProvider.java | 4 +- .../ApiKeyAuthenticationProvider.java | 11 +- .../AuthenticationProvider.java | 4 +- ...BaseBearerTokenAuthenticationProvider.java | 10 +- .../BasicAccessAuthenticationProvider.java | 1 - .../SerializationWriterProxyFactory.java | 2 +- .../AzureIdentityAccessTokenProvider.java | 3 - .../http/OkHttpCallbackFutureWrapper.java | 26 - .../kiota/http/OkHttpRequestAdapter.java | 596 ++++++++---------- .../kiota/http/OkHttpRequestAdapterTest.java | 25 +- 15 files changed, 326 insertions(+), 398 deletions(-) delete mode 100644 components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpCallbackFutureWrapper.java diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java index 604969e41..8b203dff9 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java @@ -16,11 +16,11 @@ public class NativeResponseHandler implements ResponseHandler { private Object value; private HashMap> errorMappings; @Override - @Nonnull - public void handleResponseAsync(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) { + public ModelType handleResponse(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) { this.value = response; if(errorMappings != null) this.errorMappings = new HashMap<>(errorMappings); + return null; } /** * Set the error mappings for the response to use when deserializing failed responses bodies. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java index 9858671f7..90c85e1ca 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/RequestAdapter.java @@ -1,9 +1,5 @@ package com.microsoft.kiota; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.concurrent.CompletableFuture; import java.util.HashMap; import java.util.List; @@ -34,42 +30,42 @@ public interface RequestAdapter { * @param factory the factory to create the parsable object from the type discriminator. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized response model. + * @return the deserialized response model. */ @Nullable @SuppressWarnings("LambdaLast") - ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) throws IOException, URISyntaxException; + ModelType send(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection. * @param requestInfo the request info to execute. * @param factory the factory to create the parsable object from the type discriminator. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized response model collection. + * @return the deserialized response model collection. */ @Nullable @SuppressWarnings("LambdaLast") - List sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); + List sendCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model. * @param requestInfo the request info to execute. * @param targetClass the class of the response model to deserialize the response into. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized primitive response model. + * @return the deserialized primitive response model. */ @Nullable - ModelType sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + ModelType sendPrimitive(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** * Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive collection response model. * @param requestInfo the request info to execute. * @param targetClass the class of the response model to deserialize the response into. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized primitive collection response model. + * @return the deserialized primitive collection response model. */ @Nullable - List sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + List sendPrimitiveCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** Executes the HTTP request specified by the given RequestInformation and returns the deserialized enum value. @@ -77,10 +73,10 @@ public interface RequestAdapter { * @param targetClass the class of the response model to deserialize the response into. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized primitive response model. + * @return the deserialized primitive response model. */ @Nullable - > ModelType sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + > ModelType sendEnum(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** Executes the HTTP request specified by the given RequestInformation and returns the deserialized enum collection value. @@ -88,10 +84,10 @@ public interface RequestAdapter { * @param targetClass the class of the response model to deserialize the response into. * @param errorMappings the error factories mapping to use in case of a failed request. * @param the type of the response model to deserialize the response into. - * @return a {@link CompletableFuture} with the deserialized primitive response model. + * @return the deserialized primitive response model. */ @Nullable - > List sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); + > List sendEnumCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings); /** * Sets The base url for every request. * @param baseUrl The base url for every request. @@ -110,5 +106,5 @@ public interface RequestAdapter { * @return the native HTTP request. */ @Nonnull - T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo) throws URISyntaxException, MalformedURLException; + T convertToNativeRequest(@Nonnull final RequestInformation requestInfo); } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java index 6490e07fb..ce88ecedd 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java @@ -18,6 +18,6 @@ public interface ResponseHandler { * @param The type of the native response object. * @param The type of the response model object. */ - @Nonnull - void handleResponseAsync(@Nonnull final NativeResponseType response, @Nullable final HashMap> errorMappings); + @Nullable + ModelType handleResponse(@Nonnull final NativeResponseType response, @Nullable final HashMap> errorMappings); } \ No newline at end of file diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandlerOption.java b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandlerOption.java index f83a0657e..08f393dfb 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandlerOption.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandlerOption.java @@ -7,6 +7,7 @@ public class ResponseHandlerOption implements RequestOption { /** Creates a new instance of the option */ public ResponseHandlerOption() { + // default constructor } private ResponseHandler responseHandler; diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java index 19200de26..4242551a2 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AccessTokenProvider.java @@ -2,7 +2,6 @@ import java.net.URI; import java.util.Map; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -13,7 +12,7 @@ public interface AccessTokenProvider { * This method returns the access token for the provided url. * @param uri The target URI to get an access token for. * @param additionalAuthenticationContext Additional authentication context to pass to the authentication library. - * @return A CompletableFuture that holds the access token. + * @return the access token. */ @Nonnull String getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map additionalAuthenticationContext); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java index 93536e173..1fd106058 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java @@ -10,7 +10,9 @@ /** This authentication provider does not perform any authentication. */ public class AnonymousAuthenticationProvider implements AuthenticationProvider { /** Default constructor for the anonymous authentication provider. */ - public AnonymousAuthenticationProvider() {} + public AnonymousAuthenticationProvider() { + // default constructor + } /** {@inheritDoc} */ public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { //This authentication provider does not perform any authentication. diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java index 67066058d..530325d38 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java @@ -4,7 +4,6 @@ import java.net.URISyntaxException; import java.util.Map; import java.util.Objects; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -49,7 +48,7 @@ public ApiKeyAuthenticationProvider(@Nonnull final String apiKey, @Nonnull final private static final String parentSpanKey = "parent-span"; /** {@inheritDoc} */ @Override - public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException { + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) { Objects.requireNonNull(request); Span span; if(additionalAuthenticationContext != null && additionalAuthenticationContext.containsKey(parentSpanKey) && additionalAuthenticationContext.get(parentSpanKey) instanceof Span) { @@ -80,11 +79,13 @@ public void authenticateRequest(@Nonnull final RequestInformation request, @Null default: throw new IllegalArgumentException("Unsupported key location"); } - } catch (URISyntaxException | IllegalArgumentException e ) { + } catch(URISyntaxException e){ + span.recordException(e); + throw new RuntimeException("Malformed URI",e); + } catch( IllegalArgumentException e ) { span.recordException(e); throw e; - } - finally { + } finally { span.end(); } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java index 8ebef359c..fef60bdee 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AuthenticationProvider.java @@ -2,9 +2,7 @@ import com.microsoft.kiota.RequestInformation; -import java.net.URISyntaxException; import java.util.Map; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -16,5 +14,5 @@ public interface AuthenticationProvider { * @param request the request to authenticate. * @param additionalAuthenticationContext Additional authentication context to pass to the authentication library. */ - void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException; + void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext); } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java index 4ab0980cf..739b900f1 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java @@ -5,7 +5,6 @@ import com.google.common.base.Strings; import java.net.URI; import java.net.URISyntaxException; -import java.util.concurrent.CompletableFuture; import java.util.Map; import java.util.Objects; @@ -24,8 +23,7 @@ public BaseBearerTokenAuthenticationProvider(@Nonnull final AccessTokenProvider private final AccessTokenProvider accessTokenProvider; private final static String authorizationHeaderKey = "Authorization"; private final static String ClaimsKey = "claims"; - @Nonnull - public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext) throws URISyntaxException { + public void authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map additionalAuthenticationContext){ Objects.requireNonNull(request); if (request.headers.containsKey(authorizationHeaderKey) && additionalAuthenticationContext != null && @@ -35,7 +33,11 @@ public void authenticateRequest(@Nonnull final RequestInformation request, @Null } if(!request.headers.containsKey(authorizationHeaderKey)) { final URI targetUri; - targetUri = request.getUri(); + try { + targetUri = request.getUri(); + } catch (URISyntaxException e){ + throw new RuntimeException("Malformed URI.", e); + } String accessToken = this.accessTokenProvider.getAuthorizationToken(targetUri, additionalAuthenticationContext); if(!Strings.isNullOrEmpty(accessToken)) { request.headers.add(authorizationHeaderKey, "Bearer " + accessToken); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java index d05faf6c7..cb301d713 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BasicAccessAuthenticationProvider.java @@ -8,7 +8,6 @@ import java.util.Base64; import java.util.Map; import java.util.Objects; -import java.util.concurrent.CompletableFuture; /** Provides an implementation of the Basic Access Authentication scheme: https://en.wikipedia.org/wiki/Basic_access_authentication . */ public class BasicAccessAuthenticationProvider implements AuthenticationProvider { diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java index 8dee1ac5e..e0f08cef3 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java @@ -24,7 +24,7 @@ public String getValidContentType() { * @param onAfterSerialization the callback to invoke after the serialization of any model object. * @param onStartObjectSerialization the callback to invoke when the serialization of a model object starts. */ - protected SerializationWriterProxyFactory(@Nonnull final SerializationWriterFactory concrete, + public SerializationWriterProxyFactory(@Nonnull final SerializationWriterFactory concrete, @Nullable final Consumer onBeforeSerialization, @Nullable final Consumer onAfterSerialization, @Nullable final BiConsumer onStartObjectSerialization) { diff --git a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java index 3c2e754c6..0de2cf450 100644 --- a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java +++ b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java @@ -8,7 +8,6 @@ import java.util.Arrays; import java.util.Base64; import java.util.Objects; -import java.util.concurrent.CompletableFuture; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -16,8 +15,6 @@ import com.azure.core.credential.TokenCredential; import com.azure.core.credential.TokenRequestContext; -import com.microsoft.kiota.authentication.AccessTokenProvider; - import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; import io.opentelemetry.api.GlobalOpenTelemetry; diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpCallbackFutureWrapper.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpCallbackFutureWrapper.java deleted file mode 100644 index e3d9e620a..000000000 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpCallbackFutureWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.microsoft.kiota.http; - -import java.io.IOException; - -import java.util.concurrent.CompletableFuture; - -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Response; - -/** - * Wraps the HTTP execution in a future, not public by intention - */ -class OkHttpCallbackFutureWrapper implements Callback { - final CompletableFuture future = new CompletableFuture<>(); - @Override - public void onFailure(Call arg0, IOException arg1) { - future.completeExceptionally(arg1); - } - - @Override - public void onResponse(Call arg0, Response arg1) throws IOException { - future.complete(arg1); - } - -} diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index e936488f0..83176d32b 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -20,7 +20,6 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import com.microsoft.kiota.ApiExceptionBuilder; import jakarta.annotation.Nonnull; @@ -47,12 +46,7 @@ import com.microsoft.kiota.store.BackingStoreFactory; import com.microsoft.kiota.store.BackingStoreFactorySingleton; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.ResponseBody; -import okhttp3.Response; +import okhttp3.*; import okio.BufferedSink; import okio.Okio; @@ -65,7 +59,7 @@ /** RequestAdapter implementation for OkHttp */ public class OkHttpRequestAdapter implements com.microsoft.kiota.RequestAdapter { - private final static String contentTypeHeaderKey = "Content-Type"; + private static final String contentTypeHeaderKey = "Content-Type"; @Nonnull private final OkHttpClient client; @Nonnull @@ -167,52 +161,50 @@ public void enableBackingStore(@Nullable final BackingStoreFactory backingStoreF BackingStoreFactorySingleton.instance = backingStoreFactory; } } + + private static final String nullRequestInfoParameter = "parameter requestInfo cannot be null"; + private static final String nullTargetClassParameter = "parameter targetClass cannot be null"; + private static final String nullFactoryParameter = "parameter factory cannot be null"; @Nullable - public List sendCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); - Objects.requireNonNull(factory, "parameter factory cannot be null"); + public List sendCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); + Objects.requireNonNull(factory, nullFactoryParameter); final Span span = startSpan(requestInfo, "sendCollectionAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); - } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfObjectValues").startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - final List result = rootNode.getCollectionOfObjectValues(factory); - setResponseType(result, span); - return CompletableFuture.completedFuture(result); - } finally { - deserializationSpan.end(); - } - } catch(ApiException ex) { - return new List(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { - return new List(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; + Response response = this.getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if (rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfObjectValues").startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + final List result = rootNode.getCollectionOfObjectValues(factory); + setResponseType(result, span); + return result; } finally { - closeResponse(closeResponse, response); + deserializationSpan.end(); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -240,46 +232,46 @@ private Span startSpan(@Nonnull final RequestInformation requestInfo, @Nonnull f @Nonnull public static final String eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked"; @Nullable - public ModelType sendAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) throws IOException, URISyntaxException { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); - Objects.requireNonNull(factory, "parameter factory cannot be null"); + public ModelType send(@Nonnull final RequestInformation requestInfo, @Nonnull final ParsableFactory factory, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); + Objects.requireNonNull(factory, nullFactoryParameter); final Span span = startSpan(requestInfo, "sendAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); - } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getObjectValue").setParent(Context.current().with(span)).startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - final ModelType result = rootNode.getObjectValue(factory); - setResponseType(result, span); - return CompletableFuture.completedFuture(result); - } finally { - deserializationSpan.end(); - } - } catch(ApiException | IOException ex) { - span.recordException(ex); - throw ex; + Response response = this.getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if (rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getObjectValue").setParent(Context.current().with(span)).startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + final ModelType result = rootNode.getObjectValue(factory); + setResponseType(result, span); + return result; } finally { - closeResponse(closeResponse, response); + deserializationSpan.end(); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } + else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -299,243 +291,222 @@ private String getMediaTypeAndSubType(@Nonnull final MediaType mediaType) { return mediaType.type() + "/" + mediaType.subtype(); } @Nullable - public ModelType sendPrimitiveAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); - Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); + public ModelType sendPrimitive(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); + Objects.requireNonNull(targetClass, nullTargetClassParameter); final Span span = startSpan(requestInfo, "sendPrimitiveAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - if(targetClass == Void.class) { - return CompletableFuture.completedFuture(null); - } else { - if(targetClass == InputStream.class) { - closeResponse = false; - final ResponseBody body = response.body(); - if(body == null) { - return CompletableFuture.completedFuture(null); - } - final InputStream rawInputStream = body.byteStream(); - return CompletableFuture.completedFuture((ModelType)rawInputStream); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); + Response response = this.getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + if(targetClass == Void.class) { + return null; + } else { + if(targetClass == InputStream.class) { + closeResponse = false; + final ResponseBody body = response.body(); + if(body == null) { + return null; } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("get"+targetClass.getName()+"Value").setParent(Context.current().with(span)).startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - Object result; - if(targetClass == Boolean.class) { - result = rootNode.getBooleanValue(); - } else if(targetClass == Byte.class) { - result = rootNode.getByteValue(); - } else if(targetClass == String.class) { - result = rootNode.getStringValue(); - } else if(targetClass == Short.class) { - result = rootNode.getShortValue(); - } else if(targetClass == BigDecimal.class) { - result = rootNode.getBigDecimalValue(); - } else if(targetClass == Double.class) { - result = rootNode.getDoubleValue(); - } else if(targetClass == Integer.class) { - result = rootNode.getIntegerValue(); - } else if(targetClass == Float.class) { - result = rootNode.getFloatValue(); - } else if(targetClass == Long.class) { - result = rootNode.getLongValue(); - } else if(targetClass == UUID.class) { - result = rootNode.getUUIDValue(); - } else if(targetClass == OffsetDateTime.class) { - result = rootNode.getOffsetDateTimeValue(); - } else if(targetClass == LocalDate.class) { - result = rootNode.getLocalDateValue(); - } else if(targetClass == LocalTime.class) { - result = rootNode.getLocalTimeValue(); - } else if(targetClass == PeriodAndDuration.class) { - result = rootNode.getPeriodAndDurationValue(); - } else if(targetClass == byte[].class) { - result = rootNode.getByteArrayValue(); - } else { - throw new RuntimeException("unexpected payload type " + targetClass.getName()); - } - setResponseType(result, span); - return CompletableFuture.completedFuture((ModelType)result); - } finally { - deserializationSpan.end(); + final InputStream rawInputStream = body.byteStream(); + return (ModelType) rawInputStream; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if(rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("get" + targetClass.getName() + "Value").setParent(Context.current().with(span)).startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + Object result; + if(targetClass == Boolean.class) { + result = rootNode.getBooleanValue(); + } else if(targetClass == Byte.class) { + result = rootNode.getByteValue(); + } else if(targetClass == String.class) { + result = rootNode.getStringValue(); + } else if(targetClass == Short.class) { + result = rootNode.getShortValue(); + } else if(targetClass == BigDecimal.class) { + result = rootNode.getBigDecimalValue(); + } else if(targetClass == Double.class) { + result = rootNode.getDoubleValue(); + } else if(targetClass == Integer.class) { + result = rootNode.getIntegerValue(); + } else if(targetClass == Float.class) { + result = rootNode.getFloatValue(); + } else if(targetClass == Long.class) { + result = rootNode.getLongValue(); + } else if(targetClass == UUID.class) { + result = rootNode.getUUIDValue(); + } else if(targetClass == OffsetDateTime.class) { + result = rootNode.getOffsetDateTimeValue(); + } else if(targetClass == LocalDate.class) { + result = rootNode.getLocalDateValue(); + } else if(targetClass == LocalTime.class) { + result = rootNode.getLocalTimeValue(); + } else if(targetClass == PeriodAndDuration.class) { + result = rootNode.getPeriodAndDurationValue(); + } else if(targetClass == byte[].class) { + result = rootNode.getByteArrayValue(); + } else { + throw new RuntimeException("unexpected payload type " + targetClass.getName()); } + setResponseType(result, span); + return (ModelType)result; + } finally { + deserializationSpan.end(); } - } catch(ApiException ex) { - return new ModelType(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { - return new ModelType(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; - } finally { - closeResponse(closeResponse, response); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } } @Nullable - public > ModelType sendEnumAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); - Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); + public > ModelType sendEnum(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); + Objects.requireNonNull(targetClass, nullTargetClassParameter); final Span span = startSpan(requestInfo, "sendEnumAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); - } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getEnumValue").setParent(Context.current().with(span)).startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - final Object result = rootNode.getEnumValue(targetClass); - setResponseType(result, span); - return CompletableFuture.completedFuture((ModelType)result); - } finally { - deserializationSpan.end(); - } - } catch(ApiException ex) { - return new ModelType(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { - return new ModelType(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; + Response response= this.getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if (rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getEnumValue").setParent(Context.current().with(span)).startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + final Object result = rootNode.getEnumValue(targetClass); + setResponseType(result, span); + return (ModelType)result; } finally { - closeResponse(closeResponse, response); + deserializationSpan.end(); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } } @Nullable - public > List sendEnumCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); - Objects.requireNonNull(targetClass, "parameter targetClass cannot be null"); + public > List sendEnumCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); + Objects.requireNonNull(targetClass, nullTargetClassParameter); final Span span = startSpan(requestInfo, "sendEnumCollectionAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); - } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfEnumValues").setParent(Context.current().with(span)).startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - final Object result = rootNode.getCollectionOfEnumValues(targetClass); - setResponseType(result, span); - return CompletableFuture.completedFuture((List)result); - } finally { - deserializationSpan.end(); - } - } catch(ApiException ex) { - return new List(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { - return new List(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; + Response response = this.getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if (rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfEnumValues").setParent(Context.current().with(span)).startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + final Object result = rootNode.getCollectionOfEnumValues(targetClass); + setResponseType(result, span); + return (List)result; } finally { - closeResponse(closeResponse, response); + deserializationSpan.end(); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + + + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } } @Nullable - public List sendPrimitiveCollectionAsync(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); + public List sendPrimitiveCollection(@Nonnull final RequestInformation requestInfo, @Nonnull final Class targetClass, @Nullable final HashMap> errorMappings) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); final Span span = startSpan(requestInfo, "sendPrimitiveCollectionAsync"); try(final Scope scope = span.makeCurrent()) { - return this.getHttpResponseMessage(requestInfo, span, span, null) - .thenCompose(response -> { - final ResponseHandler responseHandler = getResponseHandler(requestInfo); - if(responseHandler == null) { - boolean closeResponse = true; - try { - this.throwIfFailedResponse(response, span, errorMappings); - if(this.shouldReturnNull(response)) { - return CompletableFuture.completedFuture(null); - } - final ParseNode rootNode = getRootParseNode(response, span, span); - if (rootNode == null) { - closeResponse = false; - return CompletableFuture.completedFuture(null); - } - final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfPrimitiveValues").setParent(Context.current().with(span)).startSpan(); - try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { - final List result = rootNode.getCollectionOfPrimitiveValues(targetClass); - setResponseType(result, span); - return CompletableFuture.completedFuture(result); - } finally { - deserializationSpan.end(); - } - } catch(ApiException ex) { - return new List(){{ - this.completeExceptionally(ex); - }}; - } catch(IOException ex) { - return new List(){{ - this.completeExceptionally(new RuntimeException("failed to read the response body", ex)); - }}; + Response response = getHttpResponseMessage(requestInfo, span, span, null); + final ResponseHandler responseHandler = getResponseHandler(requestInfo); + if(responseHandler == null) { + boolean closeResponse = true; + try { + this.throwIfFailedResponse(response, span, errorMappings); + if(this.shouldReturnNull(response)) { + return null; + } + final ParseNode rootNode = getRootParseNode(response, span, span); + if (rootNode == null) { + closeResponse = false; + return null; + } + final Span deserializationSpan = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getCollectionOfPrimitiveValues").setParent(Context.current().with(span)).startSpan(); + try(final Scope deserializationScope = deserializationSpan.makeCurrent()) { + final List result = rootNode.getCollectionOfPrimitiveValues(targetClass); + setResponseType(result, span); + return result; } finally { - closeResponse(closeResponse, response); + deserializationSpan.end(); } - } else { - span.addEvent(eventResponseHandlerInvokedKey); - return responseHandler.handleResponseAsync(response, errorMappings); + } finally { + closeResponse(closeResponse, response); } - }); + } else { + span.addEvent(eventResponseHandlerInvokedKey); + return responseHandler.handleResponse(response, errorMappings); + } + } catch(ApiException ex) { + throw new RuntimeException(ex); + } catch(IOException ex) { + throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -635,8 +606,8 @@ private Response throwIfFailedResponse(@Nonnull final Response response, @Nonnul } } private final static String claimsKey = "claims"; - private Response getHttpResponseMessage(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) throws IOException, URISyntaxException { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); + private Response getHttpResponseMessage(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getHttpResponseMessage").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { this.setBaseUrlForRequestInformation(requestInfo); @@ -646,29 +617,24 @@ private Response getHttpResponseMessage(@Nonnull final RequestInformation reques additionalContext.put(claimsKey, claims); } this.authProvider.authenticateRequest(requestInfo, additionalContext); - final OkHttpCallbackFutureWrapper wrapper = new OkHttpCallbackFutureWrapper(); - this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).enqueue(wrapper); - - - Response response = wrapper.future.thenApply(x -> { - final String contentLengthHeaderValue = getHeaderValue(x, "Content-Length"); - if(contentLengthHeaderValue != null && !contentLengthHeaderValue.isEmpty()) { - final Integer contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, contentLengthHeaderValueAsInt); - } - final String contentTypeHeaderValue = getHeaderValue(x, "Content-Length"); - if(contentTypeHeaderValue != null && !contentTypeHeaderValue.isEmpty()) { - spanForAttributes.setAttribute("http.response_content_type", contentTypeHeaderValue); - } - spanForAttributes.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, x.code()); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_FLAVOR, x.protocol().toString().toUpperCase(Locale.ROOT)); - return x; - }).join(); + this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)); + Response response = this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).execute(); + final String contentLengthHeaderValue = getHeaderValue(response, "Content-Length"); + if(contentLengthHeaderValue != null && !contentLengthHeaderValue.isEmpty()) { + final Integer contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, contentLengthHeaderValueAsInt); + } + final String contentTypeHeaderValue = getHeaderValue(response, "Content-Length"); + if(contentTypeHeaderValue != null && !contentTypeHeaderValue.isEmpty()) { + spanForAttributes.setAttribute("http.response_content_type", contentTypeHeaderValue); + } + spanForAttributes.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, response.code()); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_FLAVOR, response.protocol().toString().toUpperCase(Locale.ROOT)); return this.retryCAEResponseIfRequired(response, requestInfo, span, spanForAttributes, claims); } - catch (URISyntaxException | IOException ex) { + catch (IOException | URISyntaxException ex) { spanForAttributes.recordException(ex); - throw ex; + throw new RuntimeException(ex); } finally { span.end(); } @@ -689,7 +655,7 @@ private String getHeaderValue(final Response response, String key) { /** Key used for events when an authentication challenge is returned by the API */ @Nonnull public static final String authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received"; - private Response retryCAEResponseIfRequired(@Nonnull final Response response, @Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) throws IOException, URISyntaxException { + private Response retryCAEResponseIfRequired(@Nonnull final Response response, @Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes, @Nullable final String claims) { final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("retryCAEResponseIfRequired").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { final String responseClaims = this.getClaimsFromResponse(response, requestInfo, claims); @@ -699,7 +665,7 @@ private Response retryCAEResponseIfRequired(@Nonnull final Response response, @N requestInfo.content.reset(); } catch (IOException ex) { spanForAttributes.recordException(ex); - throw ex; + throw new RuntimeException(ex); } } closeResponse(true, response); @@ -707,11 +673,7 @@ private Response retryCAEResponseIfRequired(@Nonnull final Response response, @N spanForAttributes.setAttribute(SemanticAttributes.HTTP_RETRY_COUNT, 1); return this.getHttpResponseMessage(requestInfo, span, spanForAttributes, responseClaims); } - return response; - } catch (URISyntaxException e) { - spanForAttributes.recordException(e); - throw e; } finally { span.end(); } @@ -750,17 +712,15 @@ private void setBaseUrlForRequestInformation(@Nonnull final RequestInformation r /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Nonnull - public T convertToNativeRequestAsync(@Nonnull final RequestInformation requestInfo) throws URISyntaxException, MalformedURLException { - Objects.requireNonNull(requestInfo, "parameter requestInfo cannot be null"); + public T convertToNativeRequest(@Nonnull final RequestInformation requestInfo) { + Objects.requireNonNull(requestInfo, nullRequestInfoParameter); final Span span = startSpan(requestInfo, "convertToNativeRequestAsync"); try(final Scope scope = span.makeCurrent()) { this.authProvider.authenticateRequest(requestInfo, null); - try { - return (T) getRequestFromRequestInformation(requestInfo, span, span); - } catch (MalformedURLException | URISyntaxException e) { - span.recordException(e); - throw e; - } + return (T) getRequestFromRequestInformation(requestInfo, span, span); + } catch (URISyntaxException | MalformedURLException ex) { + span.recordException(ex); + throw new RuntimeException(ex); } finally { span.end(); } @@ -776,7 +736,7 @@ public T convertToNativeRequestAsync(@Nonnull final RequestInformation reque * @throws URISyntaxException if the URI is invalid. * @throws MalformedURLException if the URL is invalid. */ - protected @Nonnull Request getRequestFromRequestInformation(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes) throws URISyntaxException, MalformedURLException { + protected @Nonnull Request getRequestFromRequestInformation(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes) throws URISyntaxException, MalformedURLException{ final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getRequestFromRequestInformation").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { spanForAttributes.setAttribute(SemanticAttributes.HTTP_METHOD, requestInfo.httpMethod.toString()); @@ -793,7 +753,7 @@ public T convertToNativeRequestAsync(@Nonnull final RequestInformation reque new RequestBody() { @Override public MediaType contentType() { - final Set contentTypes = requestInfo.headers.containsKey(contentTypeHeaderKey) ? requestInfo.headers.get(contentTypeHeaderKey) : Set.of(); + final Set contentTypes = requestInfo.headers.containsKey(contentTypeHeaderKey) ? requestInfo.headers.get(contentTypeHeaderKey) : new HashSet<>(); if(contentTypes.isEmpty()) { return null; } else { diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java index 312ac17d3..f9732934b 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java @@ -18,7 +18,6 @@ import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.io.InputStream; import java.io.IOException; @@ -48,7 +47,7 @@ public class OkHttpRequestAdapterTest { @EnumSource(value = HttpMethod.class, names = {"PUT", "POST", "PATCH"}) public void PostRequestsShouldHaveEmptyBody(HttpMethod method) throws Exception { // Unexpected exception thrown: java.lang.IllegalArgumentException: method POST must have a request body. final AuthenticationProvider authenticationProviderMock = mock(AuthenticationProvider.class); - final OkHttpRequestAdapter adapter = new OkHttpRequestAdapter(authenticationProviderMock) { + final var adapter = new OkHttpRequestAdapter(authenticationProviderMock) { public Request test() throws Exception { RequestInformation ri = new RequestInformation(); ri.httpMethod = method; @@ -64,9 +63,9 @@ public Request test() throws Exception { } @ParameterizedTest @ValueSource(ints = {200, 201, 202, 203, 206}) - public void SendStreamReturnsUsableStream(int statusCode) throws Exception { + void SendStreamReturnsUsableStream(int statusCode) throws Exception { final var authenticationProviderMock = mock(AuthenticationProvider.class); - when(authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class))).thenReturn(CompletableFuture.completedFuture(null)); + authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class)); final var text = "my-demo-text"; final var bufferedSource = Okio.buffer(Okio.source(new ByteArrayInputStream(text.getBytes("UTF-8")))); final var client = getMockClient(new Response.Builder() @@ -83,7 +82,7 @@ public void SendStreamReturnsUsableStream(int statusCode) throws Exception { }}; InputStream response = null; try { - response = requestAdapter.sendPrimitiveAsync(requestInformation, InputStream.class, null).get(); + response = requestAdapter.sendPrimitive(requestInformation, InputStream.class, null); assertNotNull(response); assertEquals(text, new String(response.readAllBytes(), StandardCharsets.UTF_8)); } finally { @@ -96,7 +95,7 @@ public void SendStreamReturnsUsableStream(int statusCode) throws Exception { @ValueSource(ints = {200, 201, 202, 203, 204}) public void SendStreamReturnsNullOnNoContent(int statusCode) throws Exception { final var authenticationProviderMock = mock(AuthenticationProvider.class); - when(authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class))).thenReturn(CompletableFuture.completedFuture(null)); + authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class)); final var client = getMockClient(new Response.Builder() .code(statusCode) .message("OK") @@ -109,14 +108,14 @@ public void SendStreamReturnsNullOnNoContent(int statusCode) throws Exception { setUri(new URI("https://localhost")); httpMethod = HttpMethod.GET; }}; - final var response = requestAdapter.sendPrimitiveAsync(requestInformation, InputStream.class, null).get(); + final var response = requestAdapter.sendPrimitive(requestInformation, InputStream.class, null); assertNull(response); } @ParameterizedTest @ValueSource(ints = {200, 201, 202, 203, 204, 205}) public void SendReturnsNullOnNoContent(int statusCode) throws Exception { final var authenticationProviderMock = mock(AuthenticationProvider.class); - when(authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class))).thenReturn(CompletableFuture.completedFuture(null)); + authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class)); final var client = getMockClient(new Response.Builder() .code(statusCode) .message("OK") @@ -131,14 +130,14 @@ public void SendReturnsNullOnNoContent(int statusCode) throws Exception { }}; final var mockEntity = mock(Parsable.class); when(mockEntity.getFieldDeserializers()).thenReturn(new HashMap<>()); - final var response = requestAdapter.sendAsync(requestInformation, (node) -> mockEntity, null).get(); + final var response = requestAdapter.send(requestInformation, (node) -> mockEntity, null); assertNull(response); } @ParameterizedTest @ValueSource(ints = {200, 201, 202, 203}) public void SendReturnsObjectOnContent(int statusCode) throws Exception { final var authenticationProviderMock = mock(AuthenticationProvider.class); - when(authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class))).thenReturn(CompletableFuture.completedFuture(null)); + authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class)); final var client = getMockClient(new Response.Builder() .code(statusCode) .message("OK") @@ -158,13 +157,13 @@ public void SendReturnsObjectOnContent(int statusCode) throws Exception { when(mockFactory.getParseNode(any(String.class), any(InputStream.class))).thenReturn(mockParseNode); when(mockFactory.getValidContentType()).thenReturn("application/json"); final var requestAdapter = new OkHttpRequestAdapter(authenticationProviderMock, mockFactory, null, client); - final var response = requestAdapter.sendAsync(requestInformation, (node) -> mockEntity, null).get(); + final var response = requestAdapter.send(requestInformation, (node) -> mockEntity, null); assertNotNull(response); } @Test public void throwsAPIException() throws Exception { final var authenticationProviderMock = mock(AuthenticationProvider.class); - when(authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class))).thenReturn(CompletableFuture.completedFuture(null)); + authenticationProviderMock.authenticateRequest(any(RequestInformation.class), any(Map.class)); final var client = getMockClient(new Response.Builder() .code(404) .message("Not Found") @@ -185,7 +184,7 @@ public void throwsAPIException() throws Exception { when(mockFactory.getParseNode(any(String.class), any(InputStream.class))).thenReturn(mockParseNode); when(mockFactory.getValidContentType()).thenReturn("application/json"); final var requestAdapter = new OkHttpRequestAdapter(authenticationProviderMock, mockFactory, null, client); - final var exception = assertThrows(ExecutionException.class, ()->requestAdapter.sendAsync(requestInformation, (node) -> mockEntity, null).get()) ; + final var exception = assertThrows(RuntimeException.class, ()->requestAdapter.send(requestInformation, (node) -> mockEntity, null)) ; final var cause = exception.getCause(); assertTrue(cause instanceof ApiException); assertEquals(404, ((ApiException)cause).getResponseStatusCode()); From da71febf1cf215c002a6b91fc8dea8886f6ed85a Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:20:49 -0800 Subject: [PATCH 5/9] use latest semanticAttribute key values --- .../http/okHttp/gradle/dependencies.gradle | 2 +- .../kiota/http/OkHttpRequestAdapter.java | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/http/okHttp/gradle/dependencies.gradle b/components/http/okHttp/gradle/dependencies.gradle index 9c938de9d..2c6a0421b 100644 --- a/components/http/okHttp/gradle/dependencies.gradle +++ b/components/http/okHttp/gradle/dependencies.gradle @@ -11,7 +11,7 @@ dependencies { // This dependency is used internally, and not exposed to consumers on their own compile classpath. implementation 'io.opentelemetry:opentelemetry-api:1.31.0' implementation 'io.opentelemetry:opentelemetry-context:1.31.0' - implementation 'io.opentelemetry:opentelemetry-semconv:1.30.1-alpha' + implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.22.0-alpha' implementation 'com.google.guava:guava:32.1.3-jre' implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' api 'com.squareup.okhttp3:okhttp:4.12.0' diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index 83176d32b..b09265030 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -54,7 +54,7 @@ import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Scope; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import io.opentelemetry.semconv.SemanticAttributes; import io.opentelemetry.context.Context; /** RequestAdapter implementation for OkHttp */ @@ -621,15 +621,15 @@ private Response getHttpResponseMessage(@Nonnull final RequestInformation reques Response response = this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).execute(); final String contentLengthHeaderValue = getHeaderValue(response, "Content-Length"); if(contentLengthHeaderValue != null && !contentLengthHeaderValue.isEmpty()) { - final Integer contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, contentLengthHeaderValueAsInt); + final int contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESPONSE_BODY_SIZE, contentLengthHeaderValueAsInt); } final String contentTypeHeaderValue = getHeaderValue(response, "Content-Length"); if(contentTypeHeaderValue != null && !contentTypeHeaderValue.isEmpty()) { spanForAttributes.setAttribute("http.response_content_type", contentTypeHeaderValue); } - spanForAttributes.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, response.code()); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_FLAVOR, response.protocol().toString().toUpperCase(Locale.ROOT)); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESPONSE_STATUS_CODE, response.code()); + spanForAttributes.setAttribute(SemanticAttributes.NETWORK_PROTOCOL_VERSION, response.protocol().toString().toUpperCase(Locale.ROOT)); return this.retryCAEResponseIfRequired(response, requestInfo, span, spanForAttributes, claims); } catch (IOException | URISyntaxException ex) { @@ -670,7 +670,7 @@ private Response retryCAEResponseIfRequired(@Nonnull final Response response, @N } closeResponse(true, response); span.addEvent(authenticateChallengedEventKey); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_RETRY_COUNT, 1); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_RESEND_COUNT, 1); return this.getHttpResponseMessage(requestInfo, span, spanForAttributes, responseClaims); } return response; @@ -739,14 +739,14 @@ public T convertToNativeRequest(@Nonnull final RequestInformation requestInf protected @Nonnull Request getRequestFromRequestInformation(@Nonnull final RequestInformation requestInfo, @Nonnull final Span parentSpan, @Nonnull final Span spanForAttributes) throws URISyntaxException, MalformedURLException{ final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getRequestFromRequestInformation").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { - spanForAttributes.setAttribute(SemanticAttributes.HTTP_METHOD, requestInfo.httpMethod.toString()); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_REQUEST_METHOD, requestInfo.httpMethod.toString()); final URL requestURL = requestInfo.getUri().toURL(); if (obsOptions.getIncludeEUIIAttributes()) { - spanForAttributes.setAttribute(SemanticAttributes.HTTP_URL, requestURL.toString()); + spanForAttributes.setAttribute(SemanticAttributes.URL_FULL, requestURL.toString()); } spanForAttributes.setAttribute("http.port", requestURL.getPort()); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_HOST, requestURL.getHost()); - spanForAttributes.setAttribute(SemanticAttributes.HTTP_SCHEME, requestURL.getProtocol()); + spanForAttributes.setAttribute(SemanticAttributes.SERVER_ADDRESS, requestURL.getHost()); + spanForAttributes.setAttribute(SemanticAttributes.URL_SCHEME, requestURL.getProtocol()); RequestBody body = requestInfo.content == null ? null : @@ -801,7 +801,7 @@ public void writeTo(@Nonnull BufferedSink sink) throws IOException { if(contentLengthHeader != null && !contentLengthHeader.isEmpty()) { final String firstEntryValue = contentLengthHeader.get(0); if(firstEntryValue != null && !firstEntryValue.isEmpty()) { - spanForAttributes.setAttribute(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, Long.parseLong(firstEntryValue)); + spanForAttributes.setAttribute(SemanticAttributes.HTTP_REQUEST_BODY_SIZE, Long.parseLong(firstEntryValue)); } } return request; From 792b123891d53137f72ff2c0f2dccd22c17e876d Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:59:36 -0800 Subject: [PATCH 6/9] code review --- .../src/main/java/com/microsoft/kiota/MultipartBody.java | 1 - .../authentication/BaseBearerTokenAuthenticationProvider.java | 4 ++-- .../authentication/ApiKeyAuthenticationProviderTest.java | 1 + .../authentication/AzureIdentityAccessTokenProvider.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index 1a08aa5c6..95c7ef0d0 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -8,7 +8,6 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; -import com.google.common.base.Strings; import com.microsoft.kiota.serialization.Parsable; import com.microsoft.kiota.serialization.ParseNode; import com.microsoft.kiota.serialization.SerializationWriter; diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java index 739b900f1..956effac3 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/BaseBearerTokenAuthenticationProvider.java @@ -1,8 +1,8 @@ package com.microsoft.kiota.authentication; +import com.microsoft.kiota.Compatibility; import com.microsoft.kiota.RequestInformation; -import com.google.common.base.Strings; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; @@ -39,7 +39,7 @@ public void authenticateRequest(@Nonnull final RequestInformation request, @Null throw new RuntimeException("Malformed URI.", e); } String accessToken = this.accessTokenProvider.getAuthorizationToken(targetUri, additionalAuthenticationContext); - if(!Strings.isNullOrEmpty(accessToken)) { + if(!Compatibility.isBlank(accessToken)) { request.headers.add(authorizationHeaderKey, "Bearer " + accessToken); } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java index 7d7b2b211..e4a5f3d71 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProviderTest.java @@ -37,6 +37,7 @@ void AddsInQueryParameterWithOtherParameters() throws IllegalStateException, URI }}; request.addQueryParameter("param1", "value1"); value.authenticateRequest(request, null); + assertNull(request.headers.get("param")); assertEquals("https://localhost?param1=value1¶m=key", request.getUri().toString()); } @Test diff --git a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java index 0de2cf450..4b746c3b9 100644 --- a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java +++ b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java @@ -106,7 +106,7 @@ public String getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map< if(decodedClaim != null && !decodedClaim.isEmpty()) { context.setClaims(decodedClaim); } - return this.creds.getToken(context).toFuture().join().getToken(); + return this.creds.getTokenSync(context).getToken(); } catch (IllegalArgumentException e){ span.recordException(e); From a65c09bdc4e5e1de208416efb5559444cb5f7ca1 Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:05:08 -0800 Subject: [PATCH 7/9] add headers compatibility class --- .../kiota/http/HeadersCompatibility.java | 48 +++++++++++++++++++ .../kiota/http/OkHttpRequestAdapter.java | 6 +-- 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java new file mode 100644 index 000000000..2bfd2a6d7 --- /dev/null +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java @@ -0,0 +1,48 @@ +package com.microsoft.kiota.http; + +import com.microsoft.kiota.RequestHeaders; +import com.microsoft.kiota.ResponseHeaders; +import jakarta.annotation.Nonnull; + +import java.util.HashSet; +import java.util.Objects; + +/** + * Compatibility class to bridge OkHttp Headers and Kiota Headers + */ +public class HeadersCompatibility { + private HeadersCompatibility() { + } + + /** + * INTERNAL METHOD, DO NOT USE DIRECTLY + * Get the response headers from the okhttp3 headers and convert them to a ResponseHeaders object + * @param headers the okhttp3 headers + * @return the ResponseHeaders object + */ + public static ResponseHeaders getResponseHeaders(@Nonnull final okhttp3.Headers headers) { + Objects.requireNonNull(headers); + final ResponseHeaders responseHeaders = new ResponseHeaders(); + headers.toMultimap().forEach((name,value) ->{ + Objects.requireNonNull(name); + responseHeaders.put(name, new HashSet<>(value)); + }); + return responseHeaders; + } + + /** + * INTERNAL METHOD, DO NOT USE DIRECTLY + * Get the request headers from the okhttp3 headers and convert them to a RequestHeaders object + * @param headers the okhttp3 headers + * @return the RequestHeaders object + */ + public static RequestHeaders getRequestHeaders(@Nonnull final okhttp3.Headers headers) { + Objects.requireNonNull(headers); + final RequestHeaders requestHeaders = new RequestHeaders(); + headers.toMultimap().forEach((name,value) ->{ + Objects.requireNonNull(name); + requestHeaders.put(name, new HashSet<>(value)); + }); + return requestHeaders; + } +} diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index b09265030..4f689b1cf 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -547,11 +547,7 @@ private Response throwIfFailedResponse(@Nonnull final Response response, @Nonnul final String statusCodeAsString = Integer.toString(response.code()); final Integer statusCode = response.code(); - final ResponseHeaders responseHeaders = new ResponseHeaders(); - response.headers().toMultimap().forEach((name,value) ->{ - Objects.requireNonNull(name); - responseHeaders.put(name, new HashSet<>(value)); - }); + final ResponseHeaders responseHeaders = HeadersCompatibility.getResponseHeaders(response.headers()); if (errorMappings == null || !errorMappings.containsKey(statusCodeAsString) && !(statusCode >= 400 && statusCode < 500 && errorMappings.containsKey("4XX")) && From cbe580b0e95a8b89ba9f6b6e675258718cfaadbf Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:10:02 -0800 Subject: [PATCH 8/9] Api Exception handling Changelog and Version --- CHANGELOG.md | 8 +++- .../com/microsoft/kiota/ApiException.java | 2 +- .../microsoft/kiota/ApiExceptionBuilder.java | 2 +- .../kiota/BaseRequestConfiguration.java | 6 +++ .../microsoft/kiota/CaseInsensitiveMap.java | 3 ++ .../com/microsoft/kiota/MultipartBody.java | 6 +++ .../kiota/NativeResponseHandler.java | 6 +++ .../com/microsoft/kiota/ResponseHandler.java | 1 + .../kiota/http/HeadersCompatibility.java | 3 +- .../kiota/http/OkHttpRequestAdapter.java | 46 ++----------------- .../kiota/http/OkHttpRequestAdapterTest.java | 10 ++-- gradle.properties | 4 +- 12 files changed, 44 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af8670de9..89be4722a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -Changed OkHttpRequestAdapter dependency from OkHttpClient to Call.Factory (parent interface implemented by OkHttpClient). +## [1.0.0] - 2023-11-10 + +### Changed + +- Kiota-Java has moved away from Async/Completable futures, thus Async components are no longer utilized and have been removed. Furthermore, requestAdapter methods no longer use the async suffix. [#175](https://github.com/microsoft/kiota-java/issues/175) +- ApiException class now extends RuntimeException instead of Exception. +- Changed OkHttpRequestAdapter dependency from OkHttpClient to Call.Factory (parent interface implemented by OkHttpClient). ## [0.8.0] - 2023-10-31 diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java b/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java index 153247055..987b06e7c 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ApiException.java @@ -5,7 +5,7 @@ import jakarta.annotation.Nonnull; /** Parent type for exceptions thrown by the client when receiving failed responses to its requests. */ -public class ApiException extends Exception { +public class ApiException extends RuntimeException { /** {@inheritDoc} */ public ApiException() { super(); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ApiExceptionBuilder.java b/components/abstractions/src/main/java/com/microsoft/kiota/ApiExceptionBuilder.java index 3b61d8f13..24c9d2305 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ApiExceptionBuilder.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ApiExceptionBuilder.java @@ -28,7 +28,7 @@ public ApiExceptionBuilder(@Nonnull final Supplier builder) { value = (ApiException) error; } else { value = new ApiExceptionBuilder() - .withMessage("\"unexpected error type \" + error.getClass().getName()") + .withMessage("\"unexpected error type \"" + error.getClass().getName()) .build(); } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestConfiguration.java b/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestConfiguration.java index 2a9bf403f..a93859219 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestConfiguration.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/BaseRequestConfiguration.java @@ -6,6 +6,12 @@ /** Base class for request configuration */ public abstract class BaseRequestConfiguration { + /** + * Default constructor + */ + public BaseRequestConfiguration() { + // default empty constructor + } /** Request headers */ @Nullable public RequestHeaders headers = new RequestHeaders(); diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java b/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java index 03cc40f27..8fe0a09a1 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/CaseInsensitiveMap.java @@ -17,6 +17,9 @@ * A map that is case-insensitive on the keys */ public class CaseInsensitiveMap implements Map>{ + /** + * Default constructor + */ public CaseInsensitiveMap() { // default constructor } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index 95c7ef0d0..ea8fee239 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -17,6 +17,12 @@ * Represents a multipart body for a request or a response. */ public class MultipartBody implements Parsable { + /** + * Creates a new instance of the MultipartBody class. + */ + public MultipartBody() { + // default empty constructor + } @Nonnull private final String boundary = UUID.randomUUID().toString().replace("-", ""); /** diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java index 8b203dff9..3145eb0c1 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/NativeResponseHandler.java @@ -13,6 +13,12 @@ * The {@code ResponseHandler} implementation to handle native response objects */ public class NativeResponseHandler implements ResponseHandler { + /** + * Default constructor + */ + public NativeResponseHandler() { + // default empty constructor + } private Object value; private HashMap> errorMappings; @Override diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java index ce88ecedd..64ed54e9f 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/ResponseHandler.java @@ -17,6 +17,7 @@ public interface ResponseHandler { * @param errorMappings the error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. * @param The type of the native response object. * @param The type of the response model object. + * @return The deserialized response model object. */ @Nullable ModelType handleResponse(@Nonnull final NativeResponseType response, @Nullable final HashMap> errorMappings); diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java index 2bfd2a6d7..d2c19cb9b 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/HeadersCompatibility.java @@ -20,6 +20,7 @@ private HeadersCompatibility() { * @param headers the okhttp3 headers * @return the ResponseHeaders object */ + @Nonnull public static ResponseHeaders getResponseHeaders(@Nonnull final okhttp3.Headers headers) { Objects.requireNonNull(headers); final ResponseHeaders responseHeaders = new ResponseHeaders(); @@ -29,13 +30,13 @@ public static ResponseHeaders getResponseHeaders(@Nonnull final okhttp3.Headers }); return responseHeaders; } - /** * INTERNAL METHOD, DO NOT USE DIRECTLY * Get the request headers from the okhttp3 headers and convert them to a RequestHeaders object * @param headers the okhttp3 headers * @return the RequestHeaders object */ + @Nonnull public static RequestHeaders getRequestHeaders(@Nonnull final okhttp3.Headers headers) { Objects.requireNonNull(headers); final RequestHeaders requestHeaders = new RequestHeaders(); diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index cb8f8407a..7ea0369d6 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -21,19 +21,10 @@ import java.util.Set; import java.util.UUID; -import com.microsoft.kiota.ApiExceptionBuilder; +import com.microsoft.kiota.*; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; -import com.microsoft.kiota.ApiClientBuilder; -import com.microsoft.kiota.ApiException; -import com.microsoft.kiota.HttpMethod; -import com.microsoft.kiota.RequestInformation; -import com.microsoft.kiota.RequestOption; -import com.microsoft.kiota.ResponseHandlerOption; -import com.microsoft.kiota.ResponseHeaders; -import com.microsoft.kiota.ResponseHandler; -import com.microsoft.kiota.PeriodAndDuration; import com.microsoft.kiota.authentication.AuthenticationProvider; import com.microsoft.kiota.http.middleware.ParametersNameDecodingHandler; import com.microsoft.kiota.serialization.ParseNodeFactoryRegistry; @@ -201,10 +192,6 @@ public List sendCollection(@Nonnull fina span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -268,10 +255,6 @@ public ModelType send(@Nonnull final RequestInforma span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -371,11 +354,6 @@ public ModelType sendPrimitive(@Nonnull final RequestInformation req span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -415,10 +393,6 @@ public > ModelType sendEnum(@Nonnull final Req span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -458,12 +432,6 @@ public > List sendEnumCollection(@N span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - - - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } @@ -503,16 +471,12 @@ public List sendPrimitiveCollection(@Nonnull final Reques span.addEvent(eventResponseHandlerInvokedKey); return responseHandler.handleResponse(response, errorMappings); } - } catch(ApiException ex) { - throw new RuntimeException(ex); - } catch(IOException ex) { - throw new RuntimeException("failed to read the response body", ex); } finally { span.end(); } } @Nullable - private ParseNode getRootParseNode(final Response response, final Span parentSpan, final Span spanForAttributes) throws IOException { + private ParseNode getRootParseNode(final Response response, final Span parentSpan, final Span spanForAttributes) { final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("getRootParseNode").setParent(Context.current().with(parentSpan)).startSpan(); try(final Scope scope = span.makeCurrent()) { final ResponseBody body = response.body(); // closing the response closes the body and stream https://square.github.io/okhttp/4.x/okhttp/okhttp3/-response-body/ @@ -539,14 +503,14 @@ private boolean shouldReturnNull(final Response response) { /** Key used for the attribute when an error response body is found */ @Nonnull public static final String errorBodyFoundAttributeName = "com.microsoft.kiota.error_body_found"; - private Response throwIfFailedResponse(@Nonnull final Response response, @Nonnull final Span spanForAttributes, @Nullable final HashMap> errorMappings) throws IOException, ApiException { + private Response throwIfFailedResponse(@Nonnull final Response response, @Nonnull final Span spanForAttributes, @Nullable final HashMap> errorMappings) { final Span span = GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName()).spanBuilder("throwIfFailedResponse").setParent(Context.current().with(spanForAttributes)).startSpan(); try(final Scope scope = span.makeCurrent()) { if (response.isSuccessful()) return response; spanForAttributes.setStatus(StatusCode.ERROR); final String statusCodeAsString = Integer.toString(response.code()); - final Integer statusCode = response.code(); + final int statusCode = response.code(); final ResponseHeaders responseHeaders = HeadersCompatibility.getResponseHeaders(response.headers()); if (errorMappings == null || !errorMappings.containsKey(statusCodeAsString) && @@ -679,7 +643,7 @@ String getClaimsFromResponse(@Nonnull final Response response, @Nonnull final Re (claims == null || claims.isEmpty()) && // we avoid infinite loops and retry only once (requestInfo.content == null || requestInfo.content.markSupported())) { final List authenticateHeader = response.headers("WWW-Authenticate"); - if(authenticateHeader != null && !authenticateHeader.isEmpty()) { + if(!authenticateHeader.isEmpty()) { String rawHeaderValue = null; for(final String authenticateEntry: authenticateHeader) { final Matcher matcher = bearerPattern.matcher(authenticateEntry); diff --git a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java index f9732934b..c6a59d1ca 100644 --- a/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java +++ b/components/http/okHttp/src/test/java/com/microsoft/kiota/http/OkHttpRequestAdapterTest.java @@ -18,7 +18,6 @@ import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutionException; import java.io.InputStream; import java.io.IOException; import java.net.URI; @@ -184,11 +183,10 @@ public void throwsAPIException() throws Exception { when(mockFactory.getParseNode(any(String.class), any(InputStream.class))).thenReturn(mockParseNode); when(mockFactory.getValidContentType()).thenReturn("application/json"); final var requestAdapter = new OkHttpRequestAdapter(authenticationProviderMock, mockFactory, null, client); - final var exception = assertThrows(RuntimeException.class, ()->requestAdapter.send(requestInformation, (node) -> mockEntity, null)) ; - final var cause = exception.getCause(); - assertTrue(cause instanceof ApiException); - assertEquals(404, ((ApiException)cause).getResponseStatusCode()); - assertTrue(((ApiException)cause).getResponseHeaders().containsKey("request-id")); + final var exception = assertThrows(ApiException.class, ()->requestAdapter.send(requestInformation, (node) -> mockEntity, null)) ; + assertNotNull(exception); + assertEquals(404, exception.getResponseStatusCode()); + assertTrue(exception.getResponseHeaders().containsKey("request-id")); } public static OkHttpClient getMockClient(final Response response) throws IOException { final OkHttpClient mockClient = mock(OkHttpClient.class); diff --git a/gradle.properties b/gradle.properties index e3b9cf6a5..d0d1ae918 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,8 +24,8 @@ org.gradle.parallel=true org.gradle.caching=true mavenGroupId = com.microsoft.kiota -mavenMajorVersion = 0 -mavenMinorVersion = 8 +mavenMajorVersion = 1 +mavenMinorVersion = 0 mavenPatchVersion = 0 mavenArtifactSuffix = From d705c5ac60d41a371bf86a313392e9a63d0da4b7 Mon Sep 17 00:00:00 2001 From: ramsessanchez <63934382+ramsessanchez@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:31:36 -0800 Subject: [PATCH 9/9] code review --- CHANGELOG.md | 2 +- .../java/com/microsoft/kiota/http/OkHttpRequestAdapter.java | 3 +-- gradle.properties | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89be4722a..afa29e057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -## [1.0.0] - 2023-11-10 +## [0.9.0] - 2023-11-10 ### Changed diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java index 7ea0369d6..72b4d072e 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/OkHttpRequestAdapter.java @@ -577,8 +577,7 @@ private Response getHttpResponseMessage(@Nonnull final RequestInformation reques additionalContext.put(claimsKey, claims); } this.authProvider.authenticateRequest(requestInfo, additionalContext); - this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)); - Response response = this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).execute(); + final Response response = this.client.newCall(getRequestFromRequestInformation(requestInfo, span, spanForAttributes)).execute(); final String contentLengthHeaderValue = getHeaderValue(response, "Content-Length"); if(contentLengthHeaderValue != null && !contentLengthHeaderValue.isEmpty()) { final int contentLengthHeaderValueAsInt = Integer.parseInt(contentLengthHeaderValue); diff --git a/gradle.properties b/gradle.properties index d0d1ae918..50ae259c3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,8 +24,8 @@ org.gradle.parallel=true org.gradle.caching=true mavenGroupId = com.microsoft.kiota -mavenMajorVersion = 1 -mavenMinorVersion = 0 +mavenMajorVersion = 0 +mavenMinorVersion = 9 mavenPatchVersion = 0 mavenArtifactSuffix =