In this sample, we'll create two java applications: a service application which exposes a method and a client application which will invoke the method from the service using Dapr. This sample includes:
- DemoService (Exposes the method to be remotely accessed)
- InvokeClient (Invokes the exposed method from DemoService)
Visit this link for more information about Dapr and service invocation.
This sample invokes a method on another Dapr-enabled application via the Dapr sidecar using java.net.http.HttpClient. The previous SDK-provided DaprClient.invokeMethod wrappers are deprecated; calling the sidecar directly is the recommended approach.
Two equivalent approaches are demonstrated:
DaprClient.invokeHttpClient(appId)— an SDK-provided wrapper that returns a pre-configuredHttpClientbound to the sidecar's/v1.0/invoke/<app-id>/method/prefix, with thedapr-api-tokenheader attached when configured.- A raw
java.net.http.HttpClientsending the request to the sidecar's base URL with adapr-app-idheader identifying the target app — no SDK helper required.
Migrating from
DaprClient.invokeMethod: the deprecatedinvokeMethodAPIs serialized request bodies through the configuredDaprObjectSerializer(JSON by default), so aStringpayload was sent as a JSON string literal — e.g."hello"instead ofhello.invokeHttpClientdoes not serialize bodies: callers supply rawBodyPublishers exactly as with anyjava.net.http.HttpClient. To preserve the previous JSON encoding, useDaprBodyPublishers.json(Object):HttpRequest request = invoker.newRequestBuilder("orders") .header("Content-Type", "application/json") .POST(DaprBodyPublishers.json(order)) .build();
- Dapr CLI.
- Java JDK 17 (or greater):
- Apache Maven version 3.x.
Clone this repository:
git clone https://github.com/dapr/java-sdk.git
cd java-sdkThen build the Maven project:
# make sure you are in the `java-sdk` directory.
mvn installThen get into the examples directory:
cd examplesInitialize Dapr in Self-Hosted Mode by running: dapr init
The Demo service application is meant to expose a method that can be remotely invoked. In this example, the service code has two parts:
In the DemoService.java file, you will find the DemoService class, containing the main method. The main method uses the Spring Boot´s DaprApplication class for initializing the ExposerServiceController. See the code snippet below:
public class DemoService {
///...
public static void main(String[] args) throws Exception {
///...
// If port string is not valid, it will throw an exception.
int port = Integer.parseInt(cmd.getOptionValue("port"));
DaprApplication.start(port);
}
}DaprApplication.start() Method will run an Spring Boot application that registers the DemoServiceController, which exposes the invoking action as a POST request. The Dapr's sidecar is the one that performs the actual call to the controller, triggered by client invocations or bindings.
This Spring Controller exposes the say method. The method retrieves metadata from the headers and prints them along with the current date in console. The actual response from method is the formatted current date. See the code snippet below:
@RestController
public class DemoServiceController {
///...
@PostMapping(path = "/say")
public Mono<String> handleMethod(@RequestBody(required = false) byte[] body,
@RequestHeader Map<String, String> headers) {
return Mono.fromSupplier(() -> {
try {
String message = body == null ? "" : new String(body, StandardCharsets.UTF_8);
Calendar utcNow = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
String utcNowAsString = DATE_FORMAT.format(utcNow.getTime());
String metadataString = headers == null ? "" : OBJECT_MAPPER.writeValueAsString(headers);
// Handles the request by printing message.
System.out.println(
"Server: " + message + " @ " + utcNowAsString + " and metadata: " + metadataString);
return utcNowAsString;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}Use the following command to execute the demo service example:
dapr run --app-id invokedemo --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.DemoService -p 3000Once running, the ExposerService is now ready to be invoked by Dapr.
The Invoke client sample calls the remote method through the Dapr sidecar using two equivalent approaches:
DaprClient.invokeHttpClient(appId)— an SDK-provided wrapper aroundjava.net.http.HttpClientpre-bound to/v1.0/invoke/<app-id>/method/.- A raw
java.net.http.HttpClientagainst the sidecar's base URL with adapr-app-idheader.
In InvokeClient.java file, you will find the InvokeClient class and the main method. See the code snippet below:
public class InvokeClient {
private static final String SERVICE_APP_ID = "invokedemo";
private static final String METHOD = "say";
public static void main(String[] args) throws Exception {
try (DaprClient daprClient = new DaprClientBuilder().build()) {
DaprInvokeHttpClient invoker = daprClient.invokeHttpClient(SERVICE_APP_ID);
int port = Properties.HTTP_PORT.get();
String sidecarBase = "http://localhost:" + port;
HttpClient rawHttpClient = HttpClient.newHttpClient();
for (String message : args) {
// Form 1: SDK helper — paths resolve against /v1.0/invoke/<app-id>/method/.
HttpRequest sdkRequest = invoker.newRequestBuilder(METHOD)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(message))
.build();
HttpResponse<byte[]> sdkResponse =
invoker.send(sdkRequest, HttpResponse.BodyHandlers.ofByteArray());
System.out.println(new String(sdkResponse.body()));
// Form 2: raw HttpClient + dapr-app-id header against the sidecar's base URL.
HttpRequest headerRequest = HttpRequest.newBuilder()
.uri(URI.create(sidecarBase + "/" + METHOD))
.header("Content-Type", "application/json")
.header("dapr-app-id", SERVICE_APP_ID)
.POST(HttpRequest.BodyPublishers.ofString(message))
.build();
HttpResponse<byte[]> headerResponse =
rawHttpClient.send(headerRequest, HttpResponse.BodyHandlers.ofByteArray());
System.out.println(new String(headerResponse.body()));
}
}
System.out.println("Done");
}
}Form 1 uses DaprClient.invokeHttpClient(SERVICE_APP_ID) to obtain an HTTP client whose base URI already targets the desired app via the sidecar's invoke API. Form 2 sends the request directly to the sidecar's base URL and uses the dapr-app-id header to identify the target app. Both forms call the remote say method and print its response.
Execute the follow script in order to run the InvokeClient example, passing two messages for the remote method:
dapr run --app-id invokeclient -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.invoke.http.InvokeClient "message one" "message two"Finally, the console for invokeclient should output two timestamps per message — one from each URL form — followed by Done. The exact timestamps come from the say method on DemoService. For example:
2026-05-12 13:45:00.123
2026-05-12 13:45:00.456
2026-05-12 13:45:00.789
2026-05-12 13:45:01.012
Done
For more details on Dapr Spring Boot integration, please refer to Dapr Spring Boot Application implementation.
To stop the apps run (or press CTRL+C):
dapr stop --app-id invokedemo
dapr stop --app-id invokeclient