* Add Python standalone activities reference * Add TypeScript standalone activities reference * Add .NET standalone activities reference * Add Java standalone activities reference * Finalize draft for 0001-standalone-activities * remove incomplete sections * Add core page which abstracts out all shared stuff * Standardize connection logic * Unify worker setup section across SDK standalone-activity refs Rename the worker section to "Worker setup & activity registration" in all four SDK files and lead with a single sentence noting the Activity is defined and registered exactly as normal. Drop the .NET "Define the Activity" section so no file repeats how to define an activity, matching the Python structure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * re-organize to a LOGICAL structure, not just a flat list of H2 headings. * finish cleaning up parts other than calling activities * Get client connection in order * cleanup of operations content * Add links --------- Co-authored-by: skill-sync[bot] <skill-sync[bot]@users.noreply.github.com> Co-authored-by: Donald Pinckney <donald.pinckney@temporal.io> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9.3 KiB
Temporal Java SDK Reference
Overview
The Temporal Java SDK (io.temporal:temporal-sdk) uses an interface + implementation pattern for both Workflows and Activities. Java 8+ required; Java 21+ strongly recommended for virtual thread support.
Quick Start
Add Dependencies:
Gradle:
implementation 'io.temporal:temporal-sdk:1.+'
Maven:
<dependency>
<groupId>io.temporal</groupId>
<artifactId>temporal-sdk</artifactId>
<version>[1.0,)</version>
</dependency>
GreetActivities.java - Activity interface:
package greetingapp;
import io.temporal.activity.ActivityInterface;
import io.temporal.activity.ActivityMethod;
@ActivityInterface
public interface GreetActivities {
@ActivityMethod
String greet(String name);
}
GreetActivitiesImpl.java - Activity implementation:
package greetingapp;
public class GreetActivitiesImpl implements GreetActivities {
@Override
public String greet(String name) {
return "Hello, " + name + "!";
}
}
GreetingWorkflow.java - Workflow interface:
package greetingapp;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
@WorkflowInterface
public interface GreetingWorkflow {
@WorkflowMethod
String greet(String name);
}
GreetingWorkflowImpl.java - Workflow implementation:
package greetingapp;
import io.temporal.activity.ActivityOptions;
import io.temporal.workflow.Workflow;
import java.time.Duration;
public class GreetingWorkflowImpl implements GreetingWorkflow {
private final GreetActivities activities = Workflow.newActivityStub(
GreetActivities.class,
ActivityOptions.newBuilder()
.setStartToCloseTimeout(Duration.ofSeconds(30))
.build()
);
@Override
public String greet(String name) {
return activities.greet(name);
}
}
GreetingWorker.java - Worker setup (registers activity and workflow, runs indefinitely and processes tasks):
package greetingapp;
import io.temporal.client.WorkflowClient;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
public class GreetingWorker {
public static void main(String[] args) {
// Create gRPC stubs for local dev server (localhost:7233)
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
// Create client
WorkflowClient client = WorkflowClient.newInstance(service);
// Create factory and worker
WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker("greeting-queue");
// Register workflow and activity implementations
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);
worker.registerActivitiesImplementations(new GreetActivitiesImpl());
// Start polling
factory.start();
}
}
Start the dev server: Start temporal server start-dev in the background.
Start the worker: Run GreetingWorker.main() (e.g., ./gradlew run or mvn compile exec:java -Dexec.mainClass="greetingapp.GreetingWorker").
Starter.java - Start a workflow execution:
package greetingapp;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.serviceclient.WorkflowServiceStubs;
import java.util.UUID;
public class Starter {
public static void main(String[] args) {
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
WorkflowClient client = WorkflowClient.newInstance(service);
GreetingWorkflow workflow = client.newWorkflowStub(
GreetingWorkflow.class,
WorkflowOptions.newBuilder()
.setWorkflowId(UUID.randomUUID().toString())
.setTaskQueue("greeting-queue")
.build()
);
String result = workflow.greet("my name");
System.out.println("Result: " + result);
}
}
Run the workflow: Run Starter.main(). Should output: Result: Hello, my name!.
Key Concepts
Workflow Definition
- Annotate interface with
@WorkflowInterface - Put any state initialization logic in the workflow constructor to guarantee that it happens before signals/updates arrive. If your state initialization logic requires the workflow parameters, then add the
@WorkflowInitdecorator and parameters to your constructor. - Annotate entry point method with
@WorkflowMethod(exactly one per interface) - Use
@SignalMethodfor signal handlers - Use
@QueryMethodfor query handlers - Use
@UpdateMethodfor update handlers - Implementation class implements the interface
Activity Definition
- Annotate interface with
@ActivityInterface - Optionally annotate methods with
@ActivityMethod(for custom names) - Implementation class can throw any exception
- Call from workflow via
Workflow.newActivityStub()
Worker Setup
WorkflowServiceStubs-- gRPC connection to Temporal ServerWorkflowClient-- client used by worker to communicate with serverWorkerFactory-- creates Worker instancesWorker-- polls a single Task Queue, register workflows and activities on it- Call
factory.start()to begin polling
For Spring Boot apps, temporal-spring-boot-starter handles all of the above automatically via auto-configuration. See references/java/integrations/spring-boot.md.
File Organization Best Practice
Keep Workflow and Activity definitions in separate files. Separating them is good practice for clarity and maintainability.
greetingapp/
├── GreetActivities.java # Activity interface
├── GreetActivitiesImpl.java # Activity implementation
├── GreetingWorkflow.java # Workflow interface
├── GreetingWorkflowImpl.java # Workflow implementation
├── GreetingWorker.java # Worker setup
└── Starter.java # Client code to start workflows
Determinism Rules
The Java SDK has no sandbox. The developer is fully responsible for writing deterministic workflow code. All non-deterministic operations must happen in Activities.
Do not use in workflow code:
Thread/new Thread()-- useWorkflow.newTimer()orAsync.function()synchronized/Lock-- workflow code is single-threadedUUID.randomUUID()-- useWorkflow.randomUUID()Math.random()-- useWorkflow.newRandom()System.currentTimeMillis()/Instant.now()-- useWorkflow.currentTimeMillis()- File I/O, network calls, database access -- use Activities
Thread.sleep()-- useWorkflow.sleep()- Mutable static fields -- workflow instances must not share state
Use Workflow.* APIs instead:
Workflow.sleep()for timersWorkflow.currentTimeMillis()for current timeWorkflow.randomUUID()for UUIDsWorkflow.newRandom()for random numbersWorkflow.getLogger()for replay-safe logging
See references/core/determinism.md for detailed determinism rules.
Common Pitfalls
- Non-deterministic code in workflows - Use
Workflow.*APIs instead of standard Java APIs; perform I/O in Activities - Forgetting
@WorkflowInterfaceor@ActivityInterface- Annotations are required on interfaces for registration - Multiple
@WorkflowMethodon one interface - Only one@WorkflowMethodis allowed per@WorkflowInterface - Using
Thread.sleep()in workflows - UseWorkflow.sleep()for deterministic timers - Forgetting to heartbeat - Long-running activities need
Activity.getExecutionContext().heartbeat() - Using
System.out.println()in workflows - UseWorkflow.getLogger()for replay-safe logging - Not registering activities as instances -
registerActivitiesImplementations()takes object instances (new MyActivitiesImpl()), not classes - Blocking the workflow thread - Never perform I/O or long computations in workflow code; use Activities
- Sharing mutable state between workflow instances - Each workflow execution must be independent
Writing Tests
See references/java/testing.md for info on writing tests.
Additional Resources
Reference Files
references/java/patterns.md- Signals, queries, child workflows, saga pattern, etc.references/java/determinism.md- Determinism rules and safe alternatives for Javareferences/java/gotchas.md- Java-specific mistakes and anti-patternsreferences/java/error-handling.md- ApplicationFailure, retry policies, non-retryable errorsreferences/java/observability.md- Logging, metrics, tracing, Search Attributesreferences/java/testing.md- TestWorkflowEnvironment, time-skipping, activity mockingreferences/java/advanced-features.md- Schedules, worker tuning, and morereferences/java/data-handling.md- Data converters, Jackson, payload encryptionreferences/java/versioning.md- Patching API, workflow type versioning, Worker Versioningreferences/java/standalone-activities.md- Standalone Activities: run an Activity directly from a Client without a Workflow (Public Preview). Concept overview atreferences/core/standalone-activities.md.
Java Integrations
For Java-specific third-party integrations (Spring Boot, Spring AI, etc.), see references/integrations.md and filter for Java. Reference files live under references/java/integrations/.