The Anthropic Java SDK provides convenient access to the Anthropic REST API from applications written in Java
Complete reference for the anthropic-java SDK's tool use (function calling) capabilities, enabling Claude to interact with external tools and functions.
Custom tool definition for function calling.
package com.anthropic.models.messages;
class Tool {
fun inputSchema(): InputSchema
fun name(): String
fun cacheControl(): Optional<CacheControlEphemeral>
fun description(): Optional<String>
fun type(): Optional<Type>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun inputSchema(inputSchema: InputSchema): Builder
fun name(name: String): Builder
fun cacheControl(cacheControl: CacheControlEphemeral?): Builder
fun description(description: String): Builder
fun build(): Tool
}
}Fields:
inputSchema: JSON schema defining tool input parameters (required)name: Tool identifier used by model in tool_use blocks (required)cacheControl: Cache control breakpoint for prompt caching (optional)description: Detailed tool description for model guidance (optional)type: Tool type, defaults to "custom" (optional)Example:
Tool weatherTool = Tool.builder()
.name("get_weather")
.description("Get current weather for a location")
.inputSchema(Tool.InputSchema.builder()
.properties(Tool.InputSchema.Properties.builder()
.putAdditionalProperty("location", JsonValue.from(Map.of(
"type", "string",
"description", "City and state, e.g. San Francisco, CA"
)))
.putAdditionalProperty("unit", JsonValue.from(Map.of(
"type", "string",
"enum", List.of("celsius", "fahrenheit")
)))
.build())
.addRequired("location")
.build())
.build();JSON schema definition for tool parameters using JSON Schema Draft 2020-12.
class InputSchema {
fun properties(): Optional<Properties>
fun required(): Optional<List<String>>
fun _type(): JsonValue // Always returns "object"
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun properties(properties: Properties?): Builder
fun required(required: List<String>?): Builder
fun addRequired(required: String): Builder
fun build(): InputSchema
}
class Properties {
fun _additionalProperties(): Map<String, JsonValue>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun putAdditionalProperty(key: String, value: JsonValue): Builder
fun putAllAdditionalProperties(additionalProperties: Map<String, JsonValue>): Builder
fun build(): Properties
}
}
}Schema Structure:
Union of all tool types (custom and built-in).
package com.anthropic.models.messages;
class ToolUnion {
// Type checking
fun isTool(): Boolean
fun isBash20250124(): Boolean
fun isTextEditor20250124(): Boolean
fun isTextEditor20250429(): Boolean
fun isTextEditor20250728(): Boolean
fun isWebSearchTool20250305(): Boolean
// Type access
fun tool(): Optional<Tool>
fun bash20250124(): Optional<ToolBash20250124>
fun textEditor20250124(): Optional<ToolTextEditor20250124>
fun textEditor20250429(): Optional<ToolTextEditor20250429>
fun textEditor20250728(): Optional<ToolTextEditor20250728>
fun webSearchTool20250305(): Optional<WebSearchTool20250305>
// Type conversion
fun asTool(): Tool
fun asBash20250124(): ToolBash20250124
fun asTextEditor20250124(): ToolTextEditor20250124
fun asTextEditor20250429(): ToolTextEditor20250429
fun asTextEditor20250728(): ToolTextEditor20250728
fun asWebSearchTool20250305(): WebSearchTool20250305
// Visitor pattern
fun <T> accept(visitor: Visitor<T>): T
companion object {
@JvmStatic fun ofTool(tool: Tool): ToolUnion
@JvmStatic fun ofBash20250124(bash20250124: ToolBash20250124): ToolUnion
@JvmStatic fun ofTextEditor20250124(textEditor20250124: ToolTextEditor20250124): ToolUnion
@JvmStatic fun ofTextEditor20250429(textEditor20250429: ToolTextEditor20250429): ToolUnion
@JvmStatic fun ofTextEditor20250728(textEditor20250728: ToolTextEditor20250728): ToolUnion
@JvmStatic fun ofWebSearchTool20250305(webSearchTool20250305: WebSearchTool20250305): ToolUnion
}
interface Visitor<out T> {
fun visitTool(tool: Tool): T
fun visitBash20250124(bash20250124: ToolBash20250124): T
fun visitTextEditor20250124(textEditor20250124: ToolTextEditor20250124): T
fun visitTextEditor20250429(textEditor20250429: ToolTextEditor20250429): T
fun visitTextEditor20250728(textEditor20250728: ToolTextEditor20250728): T
fun visitWebSearchTool20250305(webSearchTool20250305: WebSearchTool20250305): T
fun unknown(json: JsonValue?): T
}
}Variants:
Tool: Custom user-defined toolsToolBash20250124: Bash execution toolToolTextEditor20250124/20250429/20250728: Text editor tools (versioned)WebSearchTool20250305: Web search toolExample:
ToolUnion customTool = ToolUnion.ofTool(
Tool.builder()
.name("calculator")
.description("Perform arithmetic operations")
.inputSchema(/* ... */)
.build()
);
// Check type
if (customTool.isTool()) {
Tool tool = customTool.asTool();
System.out.println("Tool name: " + tool.name());
}
// Using visitor pattern
String toolType = customTool.accept(new ToolUnion.Visitor<String>() {
public String visitTool(Tool tool) {
return "custom: " + tool.name();
}
public String visitBash20250124(ToolBash20250124 bash) {
return "bash";
}
public String visitTextEditor20250124(ToolTextEditor20250124 editor) {
return "text_editor";
}
// ... other visit methods
});Bash command execution tool.
package com.anthropic.models.messages;
class ToolBash20250124 {
fun name(): Name // Returns "bash"
fun type(): Type // Returns "bash_20250124"
fun cacheControl(): Optional<CacheControlEphemeral>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun cacheControl(cacheControl: CacheControlEphemeral?): Builder
fun build(): ToolBash20250124
}
}Text file editing tool (multiple versions available).
package com.anthropic.models.messages;
class ToolTextEditor20250728 {
fun name(): Name // Returns "str_replace_editor"
fun type(): Type // Returns "text_editor_20250728"
fun cacheControl(): Optional<CacheControlEphemeral>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun cacheControl(cacheControl: CacheControlEphemeral?): Builder
fun build(): ToolTextEditor20250728
}
}
// Similar structure for ToolTextEditor20250124 and ToolTextEditor20250429Web search tool for retrieving online information.
package com.anthropic.models.messages;
class WebSearchTool20250305 {
fun name(): Name // Returns "web_search"
fun type(): Type // Returns "web_search_20250305"
fun cacheControl(): Optional<CacheControlEphemeral>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun cacheControl(cacheControl: CacheControlEphemeral?): Builder
fun build(): WebSearchTool20250305
}
}Example:
// Add bash tool
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(1024L)
.addUserMessage("Run 'ls -la' command")
.tools(List.of(
ToolUnion.ofBash20250124(
ToolBash20250124.builder().build()
)
))
.build();Specifies how the model should use provided tools.
package com.anthropic.models.messages;
class ToolChoice {
// Type checking
fun isAuto(): Boolean
fun isAny(): Boolean
fun isTool(): Boolean
fun isNone(): Boolean
// Type access
fun auto(): Optional<ToolChoiceAuto>
fun any(): Optional<ToolChoiceAny>
fun tool(): Optional<ToolChoiceTool>
fun none(): Optional<ToolChoiceNone>
// Type conversion
fun asAuto(): ToolChoiceAuto
fun asAny(): ToolChoiceAny
fun asTool(): ToolChoiceTool
fun asNone(): ToolChoiceNone
// Visitor pattern
fun <T> accept(visitor: Visitor<T>): T
companion object {
@JvmStatic fun ofAuto(auto: ToolChoiceAuto): ToolChoice
@JvmStatic fun ofAny(any: ToolChoiceAny): ToolChoice
@JvmStatic fun ofTool(tool: ToolChoiceTool): ToolChoice
@JvmStatic fun ofNone(none: ToolChoiceNone): ToolChoice
}
interface Visitor<out T> {
fun visitAuto(auto: ToolChoiceAuto): T
fun visitAny(any: ToolChoiceAny): T
fun visitTool(tool: ToolChoiceTool): T
fun visitNone(none: ToolChoiceNone): T
fun unknown(json: JsonValue?): T
}
}ToolChoiceAuto: Model automatically decides whether to use tools.
class ToolChoiceAuto {
fun type(): Type // Returns "auto"
fun disableParallelToolUse(): Optional<Boolean>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun disableParallelToolUse(disableParallelToolUse: Boolean?): Builder
fun build(): ToolChoiceAuto
}
}ToolChoiceAny: Model must use at least one available tool.
class ToolChoiceAny {
fun type(): Type // Returns "any"
fun disableParallelToolUse(): Optional<Boolean>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun disableParallelToolUse(disableParallelToolUse: Boolean?): Builder
fun build(): ToolChoiceAny
}
}ToolChoiceTool: Model must use the specified tool.
class ToolChoiceTool {
fun name(): String
fun type(): Type // Returns "tool"
fun disableParallelToolUse(): Optional<Boolean>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun name(name: String): Builder
fun disableParallelToolUse(disableParallelToolUse: Boolean?): Builder
fun build(): ToolChoiceTool
}
}ToolChoiceNone: Model must not use any tools.
class ToolChoiceNone {
fun type(): Type // Returns "none"
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun build(): ToolChoiceNone
}
}Example:
// Auto (model decides)
ToolChoice autoChoice = ToolChoice.ofAuto(
ToolChoiceAuto.builder().build()
);
// Any (must use at least one tool)
ToolChoice anyChoice = ToolChoice.ofAny(
ToolChoiceAny.builder()
.disableParallelToolUse(true)
.build()
);
// Specific tool (must use named tool)
ToolChoice specificTool = ToolChoice.ofTool(
ToolChoiceTool.builder()
.name("get_weather")
.build()
);
// None (no tools allowed)
ToolChoice noTools = ToolChoice.ofNone(
ToolChoiceNone.builder().build()
);package com.anthropic.models.messages;
class MessageCreateParams {
fun tools(): Optional<List<ToolUnion>>
fun toolChoice(): Optional<ToolChoice>
class Builder {
// Tools
fun tools(tools: List<ToolUnion>): Builder
fun addTool(tool: Tool): Builder
// Tool choice
fun toolChoice(toolChoice: ToolChoice): Builder
fun build(): MessageCreateParams
}
}Example:
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(2048L)
.addUserMessage("What's the weather in San Francisco?")
.addTool(Tool.builder()
.name("get_weather")
.description("Get current weather for a location")
.inputSchema(/* schema */)
.build())
.toolChoice(ToolChoice.ofAuto(
ToolChoiceAuto.builder().build()
))
.build();
Message response = client.messages().create(params);Tool use request from the model in response content.
package com.anthropic.models.messages;
class ToolUseBlock {
fun id(): String
fun name(): String
fun _input(): JsonValue
fun _type(): JsonValue // Returns "tool_use"
fun toParam(): ToolUseBlockParam
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun id(id: String): Builder
fun name(name: String): Builder
fun input(input: JsonValue): Builder
fun build(): ToolUseBlock
}
}Fields:
id: Unique identifier for this tool usename: Name of the tool to invokeinput: Tool parameters as JSONtype: Always "tool_use"Example:
Message response = client.messages().create(params);
// Process tool use blocks
response.content().forEach(block -> {
if (block.isToolUse()) {
ToolUseBlock toolUse = block.asToolUse();
System.out.println("Tool: " + toolUse.name());
System.out.println("ID: " + toolUse.id());
System.out.println("Input: " + toolUse._input());
// Execute tool and prepare result
Object result = executeToolByName(toolUse.name(), toolUse._input());
}
});Tool execution result to send back to the model.
package com.anthropic.models.messages;
class ToolResultBlockParam {
fun toolUseId(): String
fun content(): Optional<Content>
fun isError(): Optional<Boolean>
fun cacheControl(): Optional<CacheControlEphemeral>
fun _type(): JsonValue // Returns "tool_result"
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun toolUseId(toolUseId: String): Builder
fun content(content: String): Builder
fun content(content: Content): Builder
fun contentOfTextBlockParams(textBlockParams: List<TextBlockParam>): Builder
fun contentOfImageBlockParams(imageBlockParams: List<ImageBlockParam>): Builder
fun contentOfDocumentBlockParams(documentBlockParams: List<DocumentBlockParam>): Builder
fun isError(isError: Boolean?): Builder
fun cacheControl(cacheControl: CacheControlEphemeral?): Builder
fun build(): ToolResultBlockParam
}
@JsonDeserialize(using = Content.Deserializer::class)
@JsonSerialize(using = Content.Serializer::class)
class Content {
fun string(): Optional<String>
fun contentBlockParams(): Optional<List<ContentBlockParam>>
fun isString(): Boolean
fun isContentBlockParams(): Boolean
fun asString(): String
fun asContentBlockParams(): List<ContentBlockParam>
companion object {
@JvmStatic fun ofString(string: String): Content
@JvmStatic fun ofContentBlockParams(contentBlockParams: List<ContentBlockParam>): Content
}
}
}Example:
// Simple text result
ToolResultBlockParam result = ToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.content("Temperature: 72°F")
.build();
// JSON result
ToolResultBlockParam jsonResult = ToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.content(JsonValue.from(Map.of(
"temperature", 72,
"unit", "fahrenheit",
"conditions", "sunny"
)).toJsonString())
.build();
// Error result
ToolResultBlockParam errorResult = ToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.content("Tool execution failed: Invalid location")
.isError(true)
.build();
// Send result back in next message
MessageCreateParams followUp = params.toBuilder()
.addUserMessageOfContentBlockParams(
List.of(ContentBlockParam.ofToolResult(result))
)
.build();Automatically derive tool schema from Java class structure.
package com.anthropic.models.beta.messages;
class MessageCreateParams {
class Builder {
fun <T> addTool(
toolClass: Class<T>,
localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES
): Builder
}
}Class-to-Schema Mapping:
public fields/getters → tool parametersExample:
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
@JsonClassDescription("Get the weather in a given location")
static class GetWeather {
@JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
public String location;
@JsonPropertyDescription("The unit of temperature")
public Unit unit;
public Weather execute() {
// Tool implementation
return new Weather(/* ... */);
}
}
enum Unit {
CELSIUS, FAHRENHEIT
}
static class Weather {
public String temperature;
public Weather(String temperature) {
this.temperature = temperature;
}
}
// Add tool by class
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(2048)
.addTool(GetWeather.class) // Automatically derives schema
.addUserMessage("What's the temperature in New York?")
.build();BetaToolUseBlock.input(Class<T>): Parse tool parameters JSON to class instance.
package com.anthropic.models.beta.messages;
class BetaToolUseBlock {
fun <T> input(toolClass: Class<T>): T?
}BetaToolResultBlockParam.Builder.contentAsJson(Object): Convert result object to JSON.
class BetaToolResultBlockParam {
class Builder {
fun contentAsJson(content: Object): Builder
}
}Complete Flow:
// 1. Add tool from class
MessageCreateParams.Builder paramsBuilder = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(2048)
.addTool(GetWeather.class)
.addUserMessage("What's the temperature in New York?");
// 2. Get response with tool use
BetaMessage response = client.beta().messages().create(paramsBuilder.build());
// 3. Process tool uses
response.content().stream()
.flatMap(block -> block.toolUse().stream())
.forEach(toolUse -> {
// Parse parameters to class instance
GetWeather tool = toolUse.input(GetWeather.class);
// Execute tool
Weather result = tool.execute();
// Add tool request to conversation
paramsBuilder.addAssistantMessageOfBetaContentBlockParams(
List.of(BetaContentBlockParam.ofToolUse(
BetaToolUseBlockParam.builder()
.name(toolUse.name())
.id(toolUse.id())
.input(toolUse._input())
.build()
))
);
// Add tool result to conversation
paramsBuilder.addUserMessageOfBetaContentBlockParams(
List.of(BetaContentBlockParam.ofToolResult(
BetaToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.contentAsJson(result) // Converts object to JSON
.build()
))
);
});
// 4. Get final response
BetaMessage finalResponse = client.beta().messages().create(paramsBuilder.build());Helper class that handles the complete tool use conversation flow.
package com.anthropic.helpers;
class BetaToolRunner : Iterable<BetaMessage> {
// Iterate through conversation turns
override fun iterator(): Iterator<BetaMessage>
// Stream responses instead of buffered messages
fun streaming(): Iterable<StreamResponse<BetaRawMessageStreamEvent>>
// Get current request parameters
fun params(): MessageCreateParams
// Set parameters for next API call
fun setNextParams(nextParams: MessageCreateParams)
// Get last tool response (cached)
fun lastToolResponse(): Optional<BetaMessageParam>
}Created via MessageService:
package com.anthropic.services.blocking.beta;
interface MessageService {
fun createToolRunner(params: ToolRunnerCreateParams): BetaToolRunner
fun createToolRunner(
params: ToolRunnerCreateParams,
requestOptions: RequestOptions
): BetaToolRunner
}ToolRunnerCreateParams:
package com.anthropic.models.beta.messages;
class ToolRunnerCreateParams {
fun initialMessageParams(): MessageCreateParams
fun maxIterations(): Optional<Long>
companion object {
@JvmStatic fun builder(): Builder
}
class Builder {
fun initialMessageParams(initialMessageParams: MessageCreateParams): Builder
fun maxIterations(maxIterations: Long?): Builder
fun build(): ToolRunnerCreateParams
}
}Example (Basic):
// Define tool class
@JsonClassDescription("Calculate the result of an arithmetic expression")
static class Calculator {
@JsonPropertyDescription("The arithmetic expression to evaluate")
public String expression;
public CalculatorResult execute() {
// Simple eval (for demo only - use proper parser in production)
double result = evaluateExpression(expression);
return new CalculatorResult(result);
}
}
static class CalculatorResult {
public double result;
public CalculatorResult(double result) {
this.result = result;
}
}
// Create initial params
MessageCreateParams initialParams = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(2048)
.addTool(Calculator.class)
.addUserMessage("What is 15 * 23 + 42?")
.build();
// Create tool runner
ToolRunnerCreateParams runnerParams = ToolRunnerCreateParams.builder()
.initialMessageParams(initialParams)
.maxIterations(5)
.build();
BetaToolRunner runner = client.beta().messages().createToolRunner(runnerParams);
// Iterate through conversation automatically
for (BetaMessage message : runner) {
message.content().stream()
.flatMap(block -> block.text().stream())
.forEach(text -> System.out.println("Claude: " + text.text()));
}Example (Streaming):
BetaToolRunner runner = client.beta().messages().createToolRunner(runnerParams);
// Stream responses
for (StreamResponse<BetaRawMessageStreamEvent> streamResponse : runner.streaming()) {
streamResponse.stream()
.flatMap(event -> event.contentBlockDelta().stream())
.flatMap(delta -> delta.delta().text().stream())
.forEach(text -> System.out.print(text.text()));
System.out.println(); // New line after each turn
}Example (Custom Tool Execution):
// Custom tool handler with external API calls
static class WeatherAPI {
@JsonClassDescription("Get real-time weather data")
public String location;
public WeatherData execute() {
// Call external weather API
return callWeatherAPI(location);
}
}
// Runner with error handling
BetaToolRunner runner = client.beta().messages().createToolRunner(runnerParams);
try {
for (BetaMessage message : runner) {
// Access tool response for logging/debugging
runner.lastToolResponse().ifPresent(toolResponse -> {
System.out.println("Tool executed: " + toolResponse);
});
// Process message
message.content().forEach(block -> {
if (block.isText()) {
System.out.println(block.asText().text());
} else if (block.isToolUse()) {
BetaToolUseBlock toolUse = block.asToolUse();
System.out.println("Using tool: " + toolUse.name());
}
});
// Modify params for next iteration if needed
if (needsAdjustment(message)) {
MessageCreateParams nextParams = runner.params()
.toBuilder()
.temperature(0.7)
.build();
runner.setNextParams(nextParams);
}
}
} catch (Exception e) {
System.err.println("Tool runner error: " + e.getMessage());
}Use Jackson Databind annotations to enhance tool schemas.
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeName;@JsonClassDescription: Tool description.
@JsonClassDescription("Get the weather in a given location")
class GetWeather {
// ...
}@JsonPropertyDescription: Parameter description.
class GetWeather {
@JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
public String location;
}@JsonProperty: Include non-public fields or custom names.
class GetWeather {
@JsonProperty("loc") // Use "loc" instead of "location" in schema
private String location;
@JsonProperty // Include private field
private String apiKey;
}@JsonIgnore: Exclude public fields from schema.
class GetWeather {
public String location;
@JsonIgnore
public String internalCache; // Excluded from tool schema
}@JsonTypeName: Override tool name.
@JsonTypeName("weather_api") // Use "weather_api" instead of "get_weather"
class GetWeather {
// ...
}Use Swagger annotations for type-specific constraints.
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.ArraySchema;@Schema: Property constraints.
class Article {
@Schema(minimum = "1", maximum = "1000")
public int pageCount;
@Schema(pattern = "^[A-Z].*$")
public String title;
@Schema(format = "date")
public String publicationDate;
@Schema(description = "ISBN-13 identifier", minLength = 13, maxLength = 13)
public String isbn;
}@ArraySchema: Array constraints.
class BookList {
@ArraySchema(minItems = 1, maxItems = 100)
public List<Book> books;
}Supported Constraints:
minimum, maximum, exclusiveMinimum, exclusiveMaximumminLength, maxLength, pattern, formatminItems, maxItems, uniqueItemsExample:
@JsonClassDescription("Search for books in a library catalog")
class LibrarySearch {
@JsonPropertyDescription("Search query terms")
@Schema(minLength = 1, maxLength = 200)
public String query;
@JsonPropertyDescription("Publication year range")
@Schema(minimum = "1800", maximum = "2100")
public Integer year;
@ArraySchema(
schema = @Schema(description = "Genre filters"),
minItems = 0,
maxItems = 5
)
public List<String> genres;
@Schema(format = "date")
public String searchDate;
}Validate tool schemas locally before sending to API.
package com.anthropic.core;
enum class JsonSchemaLocalValidation {
YES, // Enable local validation (default)
NO // Disable local validation
}Enable/Disable:
// Default: validation enabled
MessageCreateParams params = MessageCreateParams.builder()
.addTool(GetWeather.class) // Validates schema
.build();
// Explicitly enable
MessageCreateParams params = MessageCreateParams.builder()
.addTool(GetWeather.class, JsonSchemaLocalValidation.YES)
.build();
// Disable validation
MessageCreateParams params = MessageCreateParams.builder()
.addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
.build();Validation Checks:
When to Disable:
Note: Remote API always validates schemas regardless of local validation setting.
Full workflow showing tool definition, execution, and result handling.
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.messages.*;
import com.anthropic.models.messages.Model;
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import java.util.List;
public class ToolUseExample {
// 1. Define tool classes with annotations
enum Unit {
CELSIUS, FAHRENHEIT;
public String toString() {
return this == CELSIUS ? "°C" : "°F";
}
public double fromKelvin(double k) {
return this == CELSIUS ? k - 273.15 : (k - 273.15) * 1.8 + 32.0;
}
}
@JsonClassDescription("Get the weather in a given location")
static class GetWeather {
@JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
public String location;
@JsonPropertyDescription("The unit of temperature")
public Unit unit;
public Weather execute() {
// Simulate weather lookup
double tempK = switch (location) {
case "San Francisco, CA" -> 300.0;
case "New York, NY" -> 310.0;
case "Dallas, TX" -> 305.0;
default -> 295.0;
};
return new Weather(
String.format("%.0f%s", unit.fromKelvin(tempK), unit)
);
}
}
static class Weather {
public String temperature;
public Weather(String temperature) {
this.temperature = temperature;
}
}
public static void main(String[] args) {
// 2. Create client
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// 3. Build initial message params with tool
MessageCreateParams.Builder paramsBuilder = MessageCreateParams.builder()
.model(Model.CLAUDE_SONNET_4_5)
.maxTokens(2048)
.addTool(GetWeather.class) // Add tool from class
.addUserMessage("What's the temperature in New York?");
// 4. Create message and get tool use
client.beta().messages()
.create(paramsBuilder.build())
.content()
.stream()
.flatMap(block -> block.toolUse().stream())
.forEach(toolUse -> {
System.out.println("Tool requested: " + toolUse.name());
// 5. Parse tool parameters
GetWeather tool = toolUse.input(GetWeather.class);
System.out.println("Location: " + tool.location);
System.out.println("Unit: " + tool.unit);
// 6. Execute tool
Weather result = tool.execute();
System.out.println("Result: " + result.temperature);
// 7. Add assistant message with tool use
paramsBuilder.addAssistantMessageOfBetaContentBlockParams(
List.of(BetaContentBlockParam.ofToolUse(
BetaToolUseBlockParam.builder()
.name(toolUse.name())
.id(toolUse.id())
.input(toolUse._input())
.build()
))
);
// 8. Add user message with tool result
paramsBuilder.addUserMessageOfBetaContentBlockParams(
List.of(BetaContentBlockParam.ofToolResult(
BetaToolResultBlockParam.builder()
.toolUseId(toolUse.id())
.contentAsJson(result) // Convert to JSON
.build()
))
);
});
// 9. Get final response from Claude
client.beta().messages()
.create(paramsBuilder.build())
.content()
.stream()
.flatMap(block -> block.text().stream())
.forEach(text -> System.out.println("Claude: " + text.text()));
}
}Output:
Tool requested: get_weather
Location: New York, NY
Unit: FAHRENHEIT
Result: 99°F
Claude: The temperature in New York is 99°F.See Also:
Install with Tessl CLI
npx tessl i tessl/maven-com-anthropic--anthropic-java@2.11.1