Azure Core provides shared primitives, abstractions, and helpers for modern Java Azure SDK client libraries
—
Declarative annotations for building REST APIs with automatic HTTP request generation, parameter binding, and response handling. These annotations enable method-based service client interfaces that are processed by RestProxy.
Annotations for specifying HTTP methods and request paths for service interface methods.
/**
* HTTP GET method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Get {
/**
* Get the relative path for the annotated method's GET URL.
* @return The relative path for the annotated method's GET URL
*/
String value();
}
/**
* HTTP POST method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Post {
/**
* Get the relative path for the annotated method's POST URL.
* @return The relative path for the annotated method's POST URL
*/
String value();
}
/**
* HTTP PUT method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Put {
/**
* Get the relative path for the annotated method's PUT URL.
* @return The relative path for the annotated method's PUT URL
*/
String value();
}
/**
* HTTP PATCH method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Patch {
/**
* Get the relative path for the annotated method's PATCH URL.
* @return The relative path for the annotated method's PATCH URL
*/
String value();
}
/**
* HTTP DELETE method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Delete {
/**
* Get the relative path for the annotated method's DELETE URL.
* @return The relative path for the annotated method's DELETE URL
*/
String value();
}
/**
* HTTP HEAD method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Head {
/**
* Get the relative path for the annotated method's HEAD URL.
* @return The relative path for the annotated method's HEAD URL
*/
String value();
}
/**
* HTTP OPTIONS method annotation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Options {
/**
* Get the relative path for the annotated method's OPTIONS URL.
* @return The relative path for the annotated method's OPTIONS URL
*/
String value();
}Annotations for binding method parameters to different parts of HTTP requests.
/**
* Annotation to annotate a parameter to be substituted into a path segment in a REST endpoint URL.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface PathParam {
/**
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
* @return The name of the variable in the endpoint URI template
*/
String value();
/**
* A value true for this argument indicates that value of {@link #value()} is already encoded hence engine should not encode it.
* @return Whether or not this path parameter is already encoded
*/
boolean encoded() default false;
}
/**
* Annotation to annotate a parameter to be substituted into a query parameter in a REST endpoint URL.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface QueryParam {
/**
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
* @return The name of the variable in the endpoint URI template
*/
String value();
/**
* A value true for this argument indicates that value of {@link #value()} is already encoded hence engine should not encode it.
* @return Whether or not this query parameter is already encoded
*/
boolean encoded() default false;
/**
* A value true for this argument indicates that the REST API expects multiple parameters with the same name and different values.
* @return Whether or not the query parameter supports multiple values
*/
boolean multipleQueryParams() default false;
}
/**
* Annotation to annotate a parameter to be substituted into a header in a REST API request.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface HeaderParam {
/**
* The name of the header in the REST API request that the parameter should be added to.
* @return The name of the header
*/
String value();
}
/**
* Annotation to annotate a parameter to be substituted into a form parameter in a REST API request.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface FormParam {
/**
* The name of the form parameter.
* @return The name of the form parameter
*/
String value();
}
/**
* Annotation to annotate a parameter to be sent to a REST endpoint as HTTP request content.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface BodyParam {
/**
* Content type that the body should be treated as when sending to the REST API.
* @return The Content-Type for the body
*/
String value();
}
/**
* Annotation to annotate a parameter to be substituted into the host for a REST API call.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface HostParam {
/**
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
* @return The name of the variable in the endpoint URI template
*/
String value();
}
/**
* Annotation to annotate a parameter that contains all of the headers for a REST API call.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface HeaderCollection {
/**
* The prefix that will be prepended to each header name in the collection.
* @return The prefix for header names
*/
String value() default "";
}Annotations for specifying expected responses and exception handling behavior.
/**
* Annotation to annotate list of HTTP status codes that are expected in response from a REST API.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ExpectedResponses {
/**
* The expected success status codes for the annotated method.
* @return The expected success status codes
*/
int[] value();
}
/**
* Annotation for the type of exception that should be thrown when the API returns an error status code.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface UnexpectedResponseExceptionType {
/**
* The exception type to throw when the API returns an unexpected status code.
* @return The exception type
*/
Class<? extends HttpResponseException> value();
/**
* HTTP status codes that should trigger this exception type.
* @return Array of status codes
*/
int[] code() default {};
}
/**
* Container annotation for multiple UnexpectedResponseExceptionType annotations.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface UnexpectedResponseExceptionTypes {
/**
* Array of UnexpectedResponseExceptionType annotations.
* @return Array of exception type annotations
*/
UnexpectedResponseExceptionType[] value();
}
/**
* Annotation to indicate that the method represents a resumable operation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ResumeOperation {
/**
* The name of the operation for resumption.
* @return Operation name
*/
String value() default "";
}Annotations for defining service interfaces and client characteristics.
/**
* Annotation for interfaces that represent REST API service interfaces.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ServiceInterface {
/**
* The name of the service. This is used in telemetry and logging.
* @return The name of the service
*/
String name();
}
/**
* Annotation for service client classes.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ServiceClient {
/**
* The builder class that is used to build instances of the service client.
* @return The builder class
*/
Class<?> builder();
/**
* Indicates whether the service client is asynchronous.
* @return true if the service client is asynchronous
*/
boolean isAsync() default false;
/**
* The service interfaces that this client implements.
* @return Array of service interface classes
*/
Class<?>[] serviceInterfaces() default {};
}
/**
* Annotation for service client builder classes.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ServiceClientBuilder {
/**
* An array of classes that this builder can build.
* @return Array of service client classes this builder can create
*/
Class<?>[] serviceClients();
/**
* The protocol that the built service clients will use to communicate.
* @return The service client protocol
*/
ServiceClientProtocol protocol() default ServiceClientProtocol.HTTP;
}
/**
* Annotation for service client methods that perform network operations.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ServiceMethod {
/**
* The expected return type from the service method.
* @return The return type
*/
ReturnType returns();
}Annotations for configuring headers and host information.
/**
* Annotation for static headers that will be sent to a REST endpoint.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Headers {
/**
* List of static headers in "name: value" format.
* @return Array of header strings
*/
String[] value();
}
/**
* Annotation for specifying the host for REST API calls.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Host {
/**
* The host URL for the REST service. Can contain parameters enclosed in braces.
* @return The host URL
*/
String value();
}Annotations for marking classes with specific characteristics.
/**
* Annotation for classes that provide a fluent API.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Fluent {
// Marker annotation - no methods
}
/**
* Annotation for classes that are immutable.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Immutable {
// Marker annotation - no methods
}
/**
* Annotation for generated classes.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Generated {
/**
* The name of the code generator.
* @return Generator name
*/
String value() default "";
/**
* Date and time the code was generated.
* @return Generation timestamp
*/
String date() default "";
/**
* Comments about the generation.
* @return Generation comments
*/
String comments() default "";
}
/**
* Annotation for JSON flattening in serialization.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface JsonFlatten {
// Marker annotation for JSON processing
}Enumerations used by the annotation system.
/**
* Enumeration of return types for ServiceMethod annotation.
*/
enum ReturnType {
/**
* Return type is a single entity.
*/
SINGLE,
/**
* Return type is a collection or list of entities.
*/
COLLECTION,
/**
* Return type represents a long-running operation.
*/
LONG_RUNNING_OPERATION
}
/**
* Enumeration of service client protocols.
*/
enum ServiceClientProtocol {
/**
* HTTP protocol for REST services.
*/
HTTP,
/**
* AMQP protocol for message-based services.
*/
AMQP
}import com.azure.core.annotation.*;
import com.azure.core.http.rest.Response;
import com.azure.core.util.Context;
import reactor.core.publisher.Mono;
@ServiceInterface(name = "UserService")
@Host("https://api.example.com")
interface UserServiceClient {
@Get("/users/{userId}")
@ExpectedResponses({200})
@UnexpectedResponseExceptionType(ResourceNotFoundException.class)
Mono<Response<User>> getUser(
@PathParam("userId") String userId,
@HeaderParam("Accept") String acceptHeader,
Context context);
@Get("/users")
@ExpectedResponses({200})
@Headers({"Accept: application/json", "User-Agent: MyApp/1.0"})
Mono<Response<List<User>>> listUsers(
@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset,
@QueryParam("filter") String filter,
Context context);
@Post("/users")
@ExpectedResponses({201})
@UnexpectedResponseExceptionTypes({
@UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = {401, 403}),
@UnexpectedResponseExceptionType(value = ResourceExistsException.class, code = {409})
})
Mono<Response<User>> createUser(
@BodyParam("application/json") User user,
@HeaderParam("Content-Type") String contentType,
Context context);
@Put("/users/{userId}")
@ExpectedResponses({200, 204})
Mono<Response<User>> updateUser(
@PathParam("userId") String userId,
@BodyParam("application/json") User user,
Context context);
@Delete("/users/{userId}")
@ExpectedResponses({204})
Mono<Response<Void>> deleteUser(
@PathParam("userId") String userId,
Context context);
}import com.azure.core.annotation.*;
@ServiceClient(builder = UserServiceClientBuilder.class, isAsync = false)
class UserServiceClientImpl {
private final UserServiceClient client;
UserServiceClientImpl(HttpPipeline pipeline) {
this.client = RestProxy.create(UserServiceClient.class, pipeline);
}
@ServiceMethod(returns = ReturnType.SINGLE)
public User getUser(String userId) {
return client.getUser(userId, "application/json", Context.NONE)
.block()
.getValue();
}
@ServiceMethod(returns = ReturnType.COLLECTION)
public List<User> listUsers(Integer limit, Integer offset, String filter) {
return client.listUsers(limit, offset, filter, Context.NONE)
.block()
.getValue();
}
@ServiceMethod(returns = ReturnType.SINGLE)
public User createUser(User user) {
return client.createUser(user, "application/json", Context.NONE)
.block()
.getValue();
}
}import com.azure.core.annotation.ServiceClientBuilder;
import com.azure.core.client.traits.*;
@ServiceClientBuilder(serviceClients = {UserServiceClientImpl.class, UserServiceAsyncClient.class})
@Fluent
class UserServiceClientBuilder implements
HttpTrait<UserServiceClientBuilder>,
TokenCredentialTrait<UserServiceClientBuilder>,
EndpointTrait<UserServiceClientBuilder> {
private HttpClient httpClient;
private HttpPipeline pipeline;
private TokenCredential credential;
private String endpoint;
private List<HttpPipelinePolicy> policies = new ArrayList<>();
@Override
public UserServiceClientBuilder httpClient(HttpClient httpClient) {
this.httpClient = httpClient;
return this;
}
@Override
public UserServiceClientBuilder pipeline(HttpPipeline pipeline) {
this.pipeline = pipeline;
return this;
}
@Override
public UserServiceClientBuilder addPolicy(HttpPipelinePolicy policy) {
this.policies.add(policy);
return this;
}
@Override
public UserServiceClientBuilder credential(TokenCredential credential) {
this.credential = credential;
return this;
}
@Override
public UserServiceClientBuilder endpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}
public UserServiceClientImpl buildClient() {
HttpPipeline pipeline = buildPipeline();
return new UserServiceClientImpl(pipeline);
}
public UserServiceAsyncClient buildAsyncClient() {
HttpPipeline pipeline = buildPipeline();
return new UserServiceAsyncClient(pipeline);
}
private HttpPipeline buildPipeline() {
if (pipeline != null) {
return pipeline;
}
List<HttpPipelinePolicy> allPolicies = new ArrayList<>();
allPolicies.add(new UserAgentPolicy("UserService/1.0"));
if (credential != null) {
allPolicies.add(new BearerTokenAuthenticationPolicy(credential,
"https://api.example.com/.default"));
}
allPolicies.addAll(policies);
allPolicies.add(new RetryPolicy());
return new HttpPipelineBuilder()
.httpClient(httpClient != null ? httpClient : HttpClient.createDefault())
.policies(allPolicies.toArray(new HttpPipelinePolicy[0]))
.build();
}
}@ServiceInterface(name = "SearchService")
interface SearchServiceClient {
@Get("/search")
@ExpectedResponses({200})
Mono<Response<SearchResults>> search(
@QueryParam("q") String query,
@QueryParam("filters", multipleQueryParams = true) List<String> filters,
@QueryParam("sort") String sortBy,
@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset,
@HeaderCollection("X-Custom-") Map<String, String> customHeaders,
Context context);
@Post("/documents/batch")
@ExpectedResponses({200})
@Headers({"Content-Type: application/json"})
Mono<Response<BatchResult>> batchOperation(
@BodyParam("application/json") BatchRequest request,
@HeaderParam("X-Request-ID") String requestId,
@QueryParam("timeout") Duration timeout,
Context context);
}
// Usage
Map<String, String> customHeaders = Map.of(
"Trace-ID", "trace-123",
"Client-Version", "1.0"
);
List<String> filters = List.of(
"category:electronics",
"price:100-500",
"availability:in-stock"
);
searchClient.search("laptop", filters, "price", 20, 0, customHeaders, Context.NONE);@ServiceInterface(name = "MultiRegionService")
@Host("https://{accountName}.{region}.example.com")
interface MultiRegionServiceClient {
@Get("/status")
@ExpectedResponses({200})
Mono<Response<ServiceStatus>> getStatus(
@HostParam("accountName") String accountName,
@HostParam("region") String region,
Context context);
@Get("/data/{dataId}")
@ExpectedResponses({200})
Mono<Response<Data>> getData(
@HostParam("accountName") String accountName,
@HostParam("region") String region,
@PathParam("dataId") String dataId,
Context context);
}
// Usage - different regions and accounts
client.getStatus("myaccount", "us-west-2", Context.NONE);
client.getData("myaccount", "eu-west-1", "data123", Context.NONE);@ServiceInterface(name = "FileService")
interface FileServiceClient {
@Post("/upload")
@ExpectedResponses({200, 201})
Mono<Response<FileMetadata>> uploadFile(
@FormParam("filename") String filename,
@FormParam("description") String description,
@FormParam("tags") List<String> tags,
@BodyParam("application/octet-stream") BinaryData fileData,
Context context);
@Post("/forms/submit")
@ExpectedResponses({200})
@Headers({"Content-Type: application/x-www-form-urlencoded"})
Mono<Response<FormResult>> submitForm(
@FormParam("name") String name,
@FormParam("email") String email,
@FormParam("message") String message,
Context context);
}@ServiceInterface(name = "ProcessingService")
interface ProcessingServiceClient {
@Post("/process")
@ExpectedResponses({202})
@ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION)
Mono<Response<ProcessingOperation>> startProcessing(
@BodyParam("application/json") ProcessingRequest request,
Context context);
@Get("/operations/{operationId}")
@ExpectedResponses({200})
@ResumeOperation
Mono<Response<ProcessingOperation>> getOperation(
@PathParam("operationId") String operationId,
Context context);
@Delete("/operations/{operationId}")
@ExpectedResponses({204})
Mono<Response<Void>> cancelOperation(
@PathParam("operationId") String operationId,
Context context);
}@Generated("AutoRest")
@Fluent
@JsonFlatten
class User {
private String id;
private String name;
private String email;
private Map<String, Object> additionalProperties;
// Getters and setters...
}
@Generated("AutoRest")
@Immutable
class UserList {
private final List<User> users;
private final String continuationToken;
UserList(List<User> users, String continuationToken) {
this.users = users;
this.continuationToken = continuationToken;
}
// Getters only (immutable)...
}Install with Tessl CLI
npx tessl i tessl/maven-com-azure--azure-core