diff --git a/sdk/src/main/java/io/dapr/client/DaprBodyPublishers.java b/sdk/src/main/java/io/dapr/client/DaprBodyPublishers.java index 37651e30b..4c48bef91 100644 --- a/sdk/src/main/java/io/dapr/client/DaprBodyPublishers.java +++ b/sdk/src/main/java/io/dapr/client/DaprBodyPublishers.java @@ -59,6 +59,18 @@ private DaprBodyPublishers() { *
Callers are still responsible for setting an appropriate * {@code Content-Type} header (typically {@code application/json}). * + *
This helper is a convenience for the default-serializer case. It does + * not honor a custom {@link io.dapr.serializer.DaprObjectSerializer} + * configured on the {@link DaprClientBuilder}. Callers with a custom serializer + * should serialize the value themselves and wrap the resulting bytes: + *
{@code
+ * byte[] bytes = mySerializer.serialize(value);
+ * BodyPublisher body = HttpRequest.BodyPublishers.ofByteArray(bytes);
+ * }
+ * The only behavior this helper adds over a direct {@code ofByteArray} call is
+ * choosing a length-known {@link BodyPublisher} so the JDK emits
+ * {@code Content-Length} rather than {@code Transfer-Encoding: chunked}.
+ *
* @param value object to serialize; {@code null} yields an empty body.
* @return a body publisher carrying the JSON-encoded bytes.
* @throws UncheckedIOException if serialization fails.
diff --git a/sdk/src/main/java/io/dapr/client/DaprInvokeHttpClient.java b/sdk/src/main/java/io/dapr/client/DaprInvokeHttpClient.java
index 34564dcbb..f13edb6cf 100644
--- a/sdk/src/main/java/io/dapr/client/DaprInvokeHttpClient.java
+++ b/sdk/src/main/java/io/dapr/client/DaprInvokeHttpClient.java
@@ -13,6 +13,8 @@
package io.dapr.client;
+import io.dapr.utils.Version;
+
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
@@ -100,8 +102,9 @@ public URI baseUri() {
/**
* Creates an {@link HttpRequest.Builder} pre-bound to the Dapr invoke URL for the
- * configured app id, with the {@code dapr-api-token} header attached (when one is
- * configured) and the SDK's HTTP read timeout applied.
+ * configured app id, with the SDK {@code User-Agent} header attached, the
+ * {@code dapr-api-token} header attached (when one is configured) and the SDK's
+ * HTTP read timeout applied.
*
* The {@code relativePath} is resolved against {@link #baseUri()} via * {@link URI#resolve(String)}. Per {@link URI#resolve(String)} semantics, a leading @@ -113,7 +116,9 @@ public URI baseUri() { */ public HttpRequest.Builder newRequestBuilder(String relativePath) { Objects.requireNonNull(relativePath, "relativePath"); - HttpRequest.Builder builder = HttpRequest.newBuilder().uri(baseUri.resolve(relativePath)); + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(baseUri.resolve(relativePath)) + .header(Headers.DAPR_USER_AGENT, Version.getSdkVersion()); if (daprApiToken != null && !daprApiToken.isEmpty()) { builder.header(Headers.DAPR_API_TOKEN, daprApiToken); } diff --git a/sdk/src/test/java/io/dapr/client/DaprInvokeHttpClientTest.java b/sdk/src/test/java/io/dapr/client/DaprInvokeHttpClientTest.java index 826f9583f..c3c0514a0 100644 --- a/sdk/src/test/java/io/dapr/client/DaprInvokeHttpClientTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprInvokeHttpClientTest.java @@ -13,6 +13,7 @@ package io.dapr.client; +import io.dapr.utils.Version; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -80,6 +81,16 @@ public void newRequestBuilder_resolvesRelativePathAgainstBaseUri() { request.uri().toString()); } + @Test + public void newRequestBuilder_attachesSdkUserAgentHeader() { + DaprInvokeHttpClient invoker = new DaprInvokeHttpClient(httpClient, BASE_URI, null, null); + + HttpRequest request = invoker.newRequestBuilder("orders").GET().build(); + + assertEquals(Version.getSdkVersion(), + request.headers().firstValue(Headers.DAPR_USER_AGENT).orElse(null)); + } + @Test public void newRequestBuilder_attachesApiTokenHeaderWhenConfigured() { DaprInvokeHttpClient invoker = new DaprInvokeHttpClient(httpClient, BASE_URI, "xyz", null);