or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

audit.mdbuiltin-endpoints.mdendpoint-framework.mdhttp-exchanges.mdindex.mdinfo-contributors.mdjmx-integration.mdmanagement-operations.mdoperation-invocation.mdsanitization.mdsecurity.mdweb-integration.md
tile.json

endpoint-framework.mddocs/

Endpoint Framework

QUICK REFERENCE

Key Classes and Packages

// Core Annotations
org.springframework.boot.actuate.endpoint.annotation.Endpoint
org.springframework.boot.actuate.endpoint.annotation.WebEndpoint
org.springframework.boot.actuate.endpoint.annotation.JmxEndpoint
org.springframework.boot.actuate.endpoint.annotation.ReadOperation
org.springframework.boot.actuate.endpoint.annotation.WriteOperation
org.springframework.boot.actuate.endpoint.annotation.DeleteOperation
org.springframework.boot.actuate.endpoint.annotation.Selector

// Extension Annotations
org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension
org.springframework.boot.actuate.endpoint.jmx.annotation.EndpointJmxExtension

// Deprecated Web Annotations (for removal in 4.x)
org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint
org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint

// Access Control
org.springframework.boot.actuate.endpoint.Access
org.springframework.boot.actuate.endpoint.Show
org.springframework.boot.actuate.endpoint.SecurityContext

// Core Interfaces
org.springframework.boot.actuate.endpoint.ExposableEndpoint
org.springframework.boot.actuate.endpoint.Operation
org.springframework.boot.actuate.endpoint.EndpointId
org.springframework.boot.actuate.endpoint.OperationType

Endpoint Type Selection Guide

┌─ What technology should expose this endpoint?
│
├─ HTTP only (REST API, Web UI)
│  └─ Use @WebEndpoint
│     Example: Log file download, heap dump
│
├─ JMX only (JConsole, VisualVM)
│  └─ Use @JmxEndpoint
│     Example: MBean operations, JMX monitoring
│
├─ Both HTTP and JMX (technology-agnostic)
│  └─ Use @Endpoint
│     Example: Health, Info, Metrics
│
└─ Need technology-specific features for existing endpoint?
   ├─ HTTP features (status codes, headers)
   │  └─ Use @EndpointWebExtension
   │
   └─ JMX features (MBean operations)
      └─ Use @EndpointJmxExtension

Operation Type Decision Matrix

Operation TypeHTTP MethodJMX OperationSide EffectsCacheableUse When
@ReadOperationGETRead AttributeNoYesRetrieving data
@WriteOperationPOSTWrite OperationYesNoModifying state
@DeleteOperationDELETERemove OperationYesNoRemoving data

Common Configuration Patterns

// Basic endpoint - all technologies
@Endpoint(id = "myapp")

// Web-only endpoint
@WebEndpoint(id = "download")

// JMX-only endpoint
@JmxEndpoint(id = "monitoring")

// Restricted endpoint
@Endpoint(id = "admin", defaultAccess = Access.READ_ONLY)

// Disabled by default
@Endpoint(id = "dangerous", defaultAccess = Access.NONE)

AGENT GUIDANCE

When to Use Each Endpoint Type

Use @Endpoint (technology-agnostic):

  • Endpoint should work over HTTP, JMX, and any future protocols
  • Operations don't need technology-specific features
  • Maximum portability is desired
  • Example: Info, Environment, Beans

Use @WebEndpoint (HTTP-specific):

  • Endpoint returns binary data (files, images)
  • Needs HTTP status codes or headers
  • Only makes sense over HTTP
  • Example: Log file, heap dump, file download

Use @JmxEndpoint (JMX-specific):

  • Endpoint designed for JMX management tools
  • Uses JMX-specific types or operations
  • Example: MBean-specific operations

Use Extensions (@EndpointWebExtension, @EndpointJmxExtension):

  • Adding technology-specific behavior to existing endpoint
  • Need different response format per technology
  • Want to enhance endpoint without modifying original
  • Example: Adding HTTP status codes to generic endpoint

Pattern vs Anti-Pattern

PATTERN: Simple read operation

@Endpoint(id = "custom")
@Component
public class CustomEndpoint {

    @ReadOperation
    public Map<String, Object> getData() {  // ✓ Simple, technology-agnostic
        return Map.of("status", "OK");
    }
}

ANTI-PATTERN: HTTP-specific code in @Endpoint

@Endpoint(id = "custom")
@Component
public class BadEndpoint {

    @ReadOperation
    public ResponseEntity<Map<String, Object>> getData() {  // ❌ HTTP-specific
        return ResponseEntity.ok(Map.of("status", "OK"));
    }
}

PATTERN: Use web extension for HTTP features

@EndpointWebExtension(endpoint = CustomEndpoint.class)
@Component
public class CustomWebExtension {

    private final CustomEndpoint delegate;

    @ReadOperation
    public WebEndpointResponse<Map<String, Object>> getData() {  // ✓ HTTP-specific
        Map<String, Object> data = delegate.getData();
        return new WebEndpointResponse<>(data, 200);
    }
}

PATTERN: Parameter with @Selector

@ReadOperation
public LoggerLevel getLogger(@Selector String name) {  // ✓ Path variable
    // GET /actuator/loggers/{name}
}

ANTI-PATTERN: Multiple selectors without ALL_REMAINING

@ReadOperation
public Data get(@Selector String a, @Selector String b) {  // ❌ Ambiguous
    // How does this map to URL?
}

PATTERN: Use ALL_REMAINING for path captures

@ReadOperation
public Resource getFile(
    @Selector(match = Match.ALL_REMAINING) String path) {  // ✓ Captures full path
    // GET /actuator/files/path/to/file.txt
}

The endpoint framework provides the core abstractions for creating and managing actuator endpoints with support for multiple exposure technologies (HTTP, JMX), different operation types (read, write, delete), and integrated security.

Capabilities

Endpoint Declaration Annotations

Annotations for declaring endpoints and their exposure technologies.

/**
 * Identifies a type as an actuator endpoint that can be exposed over
 * multiple technologies (HTTP, JMX).
 *
 * Thread-safe: Endpoint beans must be thread-safe
 * Nullability: id() must return non-null
 * Since: Spring Boot 2.0+
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective
@interface Endpoint {
    /**
     * The ID of the endpoint. Must be unique and follow endpoint naming rules.
     * Naming rules: lowercase, alphanumeric, hyphens allowed
     *
     * @return endpoint ID (non-null)
     */
    String id() default "";

    /**
     * The default access level for the endpoint.
     * Can be overridden by configuration properties.
     *
     * @return default access level (non-null, defaults to UNRESTRICTED)
     */
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies an endpoint exposed only over HTTP (Spring MVC/WebFlux).
 * Use when endpoint needs HTTP-specific features or only makes sense over HTTP.
 *
 * Thread-safe: Endpoint beans must be thread-safe
 * Since: Spring Boot 2.0+
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(WebEndpointFilter.class)
@interface WebEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies an endpoint exposed only over JMX.
 * Use when endpoint is designed specifically for JMX management tools.
 *
 * Thread-safe: Endpoint beans must be thread-safe
 * Since: Spring Boot 2.0+
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(JmxEndpointFilter.class)
@interface JmxEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id() default "";

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a controller-based endpoint that uses standard Spring MVC or WebFlux.
 * Methods must use @GetMapping, @PostMapping, etc. instead of @ReadOperation.
 * Provides deeper Spring integration but at the expense of portability.
 *
 * NOTE: This annotation is in the web.annotation package, not the base endpoint.annotation package.
 *
 * @deprecated since 3.3.0, scheduled for removal. Use @Endpoint or @WebEndpoint instead.
 * @since 2.0.0
 */
// Package: org.springframework.boot.actuate.endpoint.web.annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ControllerEndpointFilter.class)
@Deprecated(since = "3.3.0", forRemoval = true)
@interface ControllerEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a REST controller-based endpoint that uses standard Spring MVC or WebFlux.
 * Similar to @ControllerEndpoint but adds @ResponseBody behavior.
 * Methods must use @GetMapping, @PostMapping, etc. instead of @ReadOperation.
 *
 * NOTE: This annotation is in the web.annotation package, not the base endpoint.annotation package.
 *
 * @deprecated since 3.3.0, scheduled for removal. Use @Endpoint or @WebEndpoint instead.
 * @since 2.0.0
 */
// Package: org.springframework.boot.actuate.endpoint.web.annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ControllerEndpointFilter.class)
@ResponseBody
@Deprecated(since = "3.3.0", forRemoval = true)
@interface RestControllerEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a type as a servlet-based endpoint that supplies a servlet to expose.
 * Implementations must also implement Supplier<EndpointServlet> and return a valid EndpointServlet.
 * This annotation can be used when existing servlets need to be exposed as actuator endpoints,
 * but it is at the expense of portability.
 *
 * NOTE: This annotation is in the web.annotation package, not the base endpoint.annotation package.
 *
 * @deprecated since 3.3.0, scheduled for removal. Use @Endpoint or @WebEndpoint instead.
 * @since 2.0.0
 */
// Package: org.springframework.boot.actuate.endpoint.web.annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ServletEndpointFilter.class)
@Deprecated(since = "3.3.0", forRemoval = true)
@interface ServletEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Annotation used to mark a type as an endpoint filter.
 * Filters determine when endpoints or extensions apply.
 *
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FilteredEndpoint {
    /**
     * The filter class to use.
     * @return the filter class (non-null)
     */
    Class<? extends EndpointFilter<?>> value();
}

/**
 * Meta-annotation for endpoint extensions.
 * Can be used to create custom extension annotations.
 *
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective
@interface EndpointExtension {
    /**
     * The filter class used to determine when the extension applies.
     * @return the filter class (non-null)
     */
    Class<? extends EndpointFilter<?>> filter();

    /**
     * The class of the endpoint to extend.
     * @return the endpoint class (non-null, or Void.class if not specified)
     */
    Class<?> endpoint() default Void.class;
}

/**
 * Annotation used to qualify endpoint parameter converters.
 *
 * @since 2.2.0
 */
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
@interface EndpointConverter {
    // Marker annotation - no attributes
}

COMPLETE WORKING EXAMPLES

Example 1: Basic Technology-Agnostic Endpoint

package com.example.actuator;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.stereotype.Component;
import org.jspecify.annotations.Nullable;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Custom cache management endpoint.
 *
 * Thread-safe: Yes (uses ConcurrentHashMap)
 * Nullability: All operations return non-null (except when cache entry not found)
 * Since: Application 1.0
 *
 * Exposes cache statistics and management operations.
 * Available via HTTP at /actuator/cache and JMX at org.springframework.boot:type=Endpoint,name=Cache
 */
@Endpoint(id = "cache", defaultAccess = Access.UNRESTRICTED)
@Component
public class CacheEndpoint {

    private final Map<String, CacheStats> cacheStats = new ConcurrentHashMap<>();

    /**
     * Get statistics for all caches.
     *
     * @return Map of cache names to statistics (never null, may be empty)
     */
    @ReadOperation
    public Map<String, CacheStats> getAllStats() {
        return Map.copyOf(cacheStats);
    }

    /**
     * Get statistics for specific cache.
     *
     * @param name Cache name (path variable)
     * @return Cache statistics or null if cache not found
     */
    @ReadOperation
    public @Nullable CacheStats getCacheStats(@Selector String name) {
        return cacheStats.get(name);
    }

    /**
     * Clear specific cache.
     *
     * @param name Cache name to clear
     */
    @DeleteOperation
    public void clearCache(@Selector String name) {
        cacheStats.remove(name);
    }

    /**
     * Update cache statistics.
     *
     * @param name Cache name
     * @param hits Hit count
     * @param misses Miss count
     */
    @WriteOperation
    public void updateStats(String name, long hits, long misses) {
        cacheStats.put(name, new CacheStats(hits, misses));
    }

    /**
     * Cache statistics record.
     */
    public record CacheStats(long hits, long misses) {
        public double hitRatio() {
            long total = hits + misses;
            return total == 0 ? 0.0 : (double) hits / total;
        }
    }
}

Example 2: Web-Specific Endpoint with Status Codes

package com.example.actuator;

import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.core.io.Resource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Component;
import org.jspecify.annotations.Nullable;

import java.io.File;
import java.util.Map;

/**
 * File download endpoint (HTTP-only).
 *
 * Thread-safe: Yes
 * Since: Application 1.0
 *
 * Provides file download capabilities via HTTP.
 * Not available via JMX (files don't make sense over JMX).
 */
@WebEndpoint(id = "files", defaultAccess = Access.READ_ONLY)
@Component
public class FileDownloadEndpoint {

    private final File baseDirectory;

    public FileDownloadEndpoint() {
        this.baseDirectory = new File("/var/app/files");
    }

    /**
     * List available files.
     *
     * @return Map with file list (never null)
     */
    @ReadOperation
    public WebEndpointResponse<Map<String, Object>> listFiles() {
        File[] files = baseDirectory.listFiles();

        if (files == null) {
            return new WebEndpointResponse<>(
                Map.of("error", "Directory not accessible"),
                WebEndpointResponse.STATUS_INTERNAL_SERVER_ERROR
            );
        }

        return new WebEndpointResponse<>(
            Map.of("files", files.length, "directory", baseDirectory.getAbsolutePath()),
            WebEndpointResponse.STATUS_OK
        );
    }

    /**
     * Download specific file.
     *
     * @param filename File name to download
     * @return File resource or error response
     */
    @ReadOperation
    public WebEndpointResponse<Resource> downloadFile(@Selector String filename) {
        File file = new File(baseDirectory, filename);

        // Security check
        if (!file.getAbsolutePath().startsWith(baseDirectory.getAbsolutePath())) {
            return new WebEndpointResponse<>(
                WebEndpointResponse.STATUS_BAD_REQUEST
            );
        }

        if (!file.exists() || !file.isFile()) {
            return new WebEndpointResponse<>(
                WebEndpointResponse.STATUS_NOT_FOUND
            );
        }

        return new WebEndpointResponse<>(
            new FileSystemResource(file),
            WebEndpointResponse.STATUS_OK
        );
    }
}

Example 3: Endpoint with Web Extension

package com.example.actuator;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * Application status endpoint (technology-agnostic).
 */
@Endpoint(id = "appstatus")
@Component
public class AppStatusEndpoint {

    @ReadOperation
    public Map<String, Object> getStatus() {
        return Map.of(
            "status", "running",
            "version", "1.0.0"
        );
    }
}

/**
 * Web extension adding HTTP-specific features.
 *
 * Adds security context awareness and HTTP status codes.
 */
@EndpointWebExtension(endpoint = AppStatusEndpoint.class)
@Component
public class AppStatusWebExtension {

    private final AppStatusEndpoint delegate;

    public AppStatusWebExtension(AppStatusEndpoint delegate) {
        this.delegate = delegate;
    }

    /**
     * Get application status with security context.
     *
     * Returns 503 if application is not ready.
     * Returns 200 with full details if user is authenticated.
     * Returns 200 with basic details if user is anonymous.
     *
     * @param securityContext Security context for authorization
     * @return Web response with appropriate status code
     */
    @ReadOperation
    public WebEndpointResponse<Map<String, Object>> getStatus(
            SecurityContext securityContext) {

        Map<String, Object> status = delegate.getStatus();

        // Check if app is ready
        if (!"running".equals(status.get("status"))) {
            return new WebEndpointResponse<>(
                Map.of("status", "not ready"),
                WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE
            );
        }

        // Filter data based on authentication
        if (securityContext.getPrincipal() == null) {
            // Anonymous user - basic info only
            return new WebEndpointResponse<>(
                Map.of("status", status.get("status")),
                WebEndpointResponse.STATUS_OK
            );
        }

        // Authenticated user - full details
        return new WebEndpointResponse<>(
            status,
            WebEndpointResponse.STATUS_OK
        );
    }
}

TESTING EXAMPLES

Test 1: Basic Endpoint Operations

package com.example.actuator;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.assertj.core.api.Assertions.*;

class CacheEndpointTest {

    private CacheEndpoint endpoint;

    @BeforeEach
    void setUp() {
        endpoint = new CacheEndpoint();
    }

    @Test
    void getAllStats_WhenEmpty_ReturnsEmptyMap() {
        assertThat(endpoint.getAllStats()).isEmpty();
    }

    @Test
    void updateStats_AddsCacheStatistics() {
        endpoint.updateStats("users", 100, 10);

        CacheEndpoint.CacheStats stats = endpoint.getCacheStats("users");

        assertThat(stats).isNotNull();
        assertThat(stats.hits()).isEqualTo(100);
        assertThat(stats.misses()).isEqualTo(10);
        assertThat(stats.hitRatio()).isEqualTo(0.909, within(0.001));
    }

    @Test
    void getCacheStats_WithNonExistent_ReturnsNull() {
        CacheEndpoint.CacheStats stats = endpoint.getCacheStats("nonexistent");

        assertThat(stats).isNull();
    }

    @Test
    void clearCache_RemovesCache() {
        endpoint.updateStats("temp", 50, 5);
        endpoint.clearCache("temp");

        assertThat(endpoint.getCacheStats("temp")).isNull();
    }

    @Test
    void operations_AreThreadSafe() throws Exception {
        // Test concurrent updates
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                endpoint.updateStats("cache1", i, i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                endpoint.updateStats("cache2", i, i);
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        // Both caches should exist
        assertThat(endpoint.getAllStats()).hasSize(2);
    }
}

Test 2: Web Extension with Security

package com.example.actuator;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import java.security.Principal;
import java.util.Map;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

class AppStatusWebExtensionTest {

    private AppStatusEndpoint endpoint;
    private AppStatusWebExtension extension;

    @BeforeEach
    void setUp() {
        endpoint = new AppStatusEndpoint();
        extension = new AppStatusWebExtension(endpoint);
    }

    @Test
    void getStatus_WithAuthenticatedUser_ReturnsFullDetails() {
        SecurityContext securityContext = createAuthenticatedContext();

        WebEndpointResponse<Map<String, Object>> response =
            extension.getStatus(securityContext);

        assertThat(response.getStatus()).isEqualTo(200);
        assertThat(response.getBody()).containsKeys("status", "version");
    }

    @Test
    void getStatus_WithAnonymousUser_ReturnsBasicInfo() {
        SecurityContext securityContext = SecurityContext.NONE;

        WebEndpointResponse<Map<String, Object>> response =
            extension.getStatus(securityContext);

        assertThat(response.getStatus()).isEqualTo(200);
        assertThat(response.getBody()).containsKey("status");
        assertThat(response.getBody()).doesNotContainKey("version");
    }

    private SecurityContext createAuthenticatedContext() {
        return new SecurityContext() {
            @Override
            public Principal getPrincipal() {
                return () -> "testuser";
            }

            @Override
            public boolean isUserInRole(String role) {
                return true;
            }
        };
    }
}

TROUBLESHOOTING

Common Error: Endpoint Not Discovered

Problem: Endpoint class not found by Spring Boot

Causes:

  1. Missing @Component annotation
  2. Class not in component scan path
  3. Wrong annotation used

Solutions:

// Solution 1: Add @Component
@Endpoint(id = "custom")
@Component  // <-- Required
public class CustomEndpoint { }

// Solution 2: Enable component scanning
@SpringBootApplication
@ComponentScan(basePackages = "com.example.actuator")
public class Application { }

// Solution 3: Register as explicit bean
@Configuration
public class EndpointConfiguration {
    @Bean
    public CustomEndpoint customEndpoint() {
        return new CustomEndpoint();
    }
}

Common Error: Method Not Recognized as Operation

Problem: Method not exposed as endpoint operation

Causes:

  1. Missing operation annotation
  2. Wrong annotation (e.g., @GetMapping instead of @ReadOperation)
  3. Method signature incompatible

Solutions:

// ❌ Wrong - missing annotation
public Map<String, Object> getData() { }

// ✓ Correct - has @ReadOperation
@ReadOperation
public Map<String, Object> getData() { }

// ❌ Wrong - using Spring MVC annotation
@GetMapping
public Map<String, Object> getData() { }

// ✓ Correct - use operation annotation
@ReadOperation
public Map<String, Object> getData() { }

Common Error: Parameter Not Mapped

Problem: @Selector parameter not working

Causes:

  1. Missing @Selector annotation
  2. Parameter name doesn't match
  3. Multiple selectors without proper configuration

Solutions:

// ❌ Wrong - missing @Selector
@ReadOperation
public Data getById(String id) { }

// ✓ Correct - has @Selector
@ReadOperation
public Data getById(@Selector String id) { }

// ✓ Correct - captures full path
@ReadOperation
public Resource getFile(
    @Selector(match = Match.ALL_REMAINING) String path) { }

PERFORMANCE NOTES

Endpoint Bean Lifecycle

// Endpoints are singleton beans by default
@Endpoint(id = "stats")
@Component  // Singleton scope
public class StatsEndpoint {
    // Single instance shared across all requests
    // MUST be thread-safe
}

// For request-scoped data, use method parameters
@ReadOperation
public Data getData(SecurityContext securityContext) {
    // securityContext is request-scoped
    // endpoint bean is singleton
}

Operation Caching

// Read operations with no parameters can be cached
@ReadOperation  // Cacheable if configured
public Map<String, Object> getStatus() {
    // Expensive operation
    return computeStatus();
}

// Operations with parameters are not cached
@ReadOperation  // Not cacheable (has parameters)
public Data getById(@Selector String id) {
    return findById(id);
}

// Write/Delete operations are never cached
@WriteOperation  // Never cached
public void update(String key, String value) { }

Memory Considerations

// Avoid storing large objects in endpoint fields
@Endpoint(id = "data")
@Component
public class DataEndpoint {

    // ❌ Bad - stores all data in memory
    private final List<Data> allData = new ArrayList<>();

    // ✓ Good - uses repository/service
    private final DataRepository repository;

    @ReadOperation
    public List<Data> getData() {
        return repository.findRecent(100); // Limit results
    }
}

COMPLETE API REFERENCE

Operation Annotations (Full Signatures)

Complete type-safe annotations for endpoint operations with all parameters and options.

/**
 * Identifies a read operation on an endpoint.
 * Read operations are exposed via GET requests in HTTP and read attributes in JMX.
 *
 * Thread-safe: Methods must be thread-safe
 * Nullability: Return value can be @Nullable
 * Cacheable: Yes, if no parameters present
 *
 * @since 2.0.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective(OperationReflectiveProcessor.class)
@interface ReadOperation {
    /**
     * The media types produced by the operation.
     *
     * @return produced media types (empty means default)
     */
    String[] produces() default {};

    /**
     * The source of the media types produced by the operation.
     * Alternative to produces() when using Producible enum.
     *
     * @return producible class
     */
    Class<? extends Producible> producesFrom() default Producible.class;
}

/**
 * Identifies a write operation on an endpoint.
 * Write operations are exposed via POST requests in HTTP and write operations in JMX.
 *
 * Thread-safe: Methods must be thread-safe
 * Nullability: Return value can be @Nullable (often void)
 * Cacheable: No
 *
 * @since 2.0.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective(OperationReflectiveProcessor.class)
@interface WriteOperation {
    /**
     * The media types produced by the operation.
     *
     * @return produced media types (empty means default)
     */
    String[] produces() default {};

    /**
     * The source of the media types produced by the operation.
     *
     * @return producible class
     */
    Class<? extends Producible> producesFrom() default Producible.class;
}

/**
 * Identifies a delete operation on an endpoint.
 * Delete operations are exposed via DELETE requests in HTTP and remove operations in JMX.
 *
 * Thread-safe: Methods must be thread-safe
 * Nullability: Return value can be @Nullable (often void)
 * Cacheable: No
 *
 * @since 2.0.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective(OperationReflectiveProcessor.class)
@interface DeleteOperation {
    /**
     * The media types produced by the operation.
     *
     * @return produced media types (empty means default)
     */
    String[] produces() default {};

    /**
     * The source of the media types produced by the operation.
     *
     * @return producible class
     */
    Class<? extends Producible> producesFrom() default Producible.class;
}

/**
 * Annotation used to identify a parameter that represents a selector component
 * from the path of the request.
 *
 * Nullability: Parameter value is never null
 *
 * @since 2.0.0
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface Selector {
    /**
     * The match type for the selector.
     * SINGLE: matches one path segment (default)
     * ALL_REMAINING: matches all remaining path segments
     *
     * @return match type (never null)
     */
    Match match() default Match.SINGLE;

    enum Match {
        /**
         * Matches a single path segment.
         * Example: /actuator/endpoint/{segment}
         */
        SINGLE,

        /**
         * Matches all remaining path segments.
         * Example: /actuator/endpoint/{all}/{remaining}/{segments}
         */
        ALL_REMAINING
    }
}

Access Control Types (Full Signatures)

Complete type information for access control and security integration.

/**
 * Access levels for endpoint operations.
 * Controls what operations are available based on configuration.
 *
 * Thread-safe: Yes (enum)
 * Immutable: Yes
 *
 * @since 2.0.0
 */
public enum Access {
    /**
     * No operations are permitted.
     * Endpoint is completely disabled.
     */
    NONE,

    /**
     * Only read operations are permitted.
     * Write and delete operations are disabled.
     */
    READ_ONLY,

    /**
     * All operations (read, write, delete) are permitted.
     * This is the default access level.
     */
    UNRESTRICTED;

    /**
     * Returns the most restrictive access level between this access
     * and the given maximum permitted access.
     *
     * @param maxPermitted the maximum permitted access (never null)
     * @return the capped access level (never null)
     */
    public Access cap(Access maxPermitted);
}

/**
 * Options for showing endpoint data.
 * Controls visibility of sensitive information based on authorization.
 *
 * Thread-safe: Yes (enum)
 * Immutable: Yes
 *
 * @since 3.0.0
 */
public enum Show {
    /**
     * Never show the item in the result.
     * Always sanitized/hidden.
     */
    NEVER,

    /**
     * Show the item when the user is authorized.
     * Requires authentication and optionally specific roles.
     */
    WHEN_AUTHORIZED,

    /**
     * Always show the item in the result.
     * Never sanitized/hidden.
     */
    ALWAYS;

    /**
     * Check if value should be shown for unauthorized result.
     *
     * @param unauthorizedResult the result for unauthorized access
     * @return true if should be shown (never null)
     */
    public boolean isShown(boolean unauthorizedResult);

    /**
     * Check if value should be shown based on security context and roles.
     *
     * @param securityContext the security context (never null)
     * @param roles the required roles (never null, may be empty)
     * @return true if should be shown
     */
    public boolean isShown(SecurityContext securityContext,
                          Collection<String> roles);
}

/**
 * Security context for an endpoint invocation.
 * Provides access to authentication and authorization information.
 *
 * Thread-safe: Implementations must be thread-safe
 *
 * @since 2.0.0
 */
public interface SecurityContext {

    /**
     * Empty security context with no principal and no roles.
     * Used for unauthenticated access.
     */
    SecurityContext NONE = /* empty implementation */;

    /**
     * Get the principal associated with the request.
     *
     * @return the principal, or null if not authenticated
     */
    @Nullable Principal getPrincipal();

    /**
     * Check if the principal has the specified role.
     *
     * @param role the role to check (never null)
     * @return true if principal has role, false otherwise or if not authenticated
     */
    boolean isUserInRole(String role);
}

Extension Annotations (Full Signatures)

Complete annotations for creating technology-specific endpoint extensions.

/**
 * Identifies a type as a web endpoint extension.
 * Provides HTTP-specific functionality for an existing endpoint.
 *
 * Thread-safe: Extension beans must be thread-safe
 * Since: 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface EndpointWebExtension {
    /**
     * The class of the endpoint being extended.
     * Must be annotated with @Endpoint, @WebEndpoint, or @JmxEndpoint.
     *
     * @return endpoint class (never null)
     */
    Class<?> endpoint();
}

/**
 * Identifies a type as a JMX endpoint extension.
 * Provides JMX-specific functionality for an existing endpoint.
 *
 * Thread-safe: Extension beans must be thread-safe
 * Since: 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface EndpointJmxExtension {
    /**
     * The class of the endpoint being extended.
     * Must be annotated with @Endpoint, @WebEndpoint, or @JmxEndpoint.
     *
     * @return endpoint class (never null)
     */
    Class<?> endpoint();
}

/**
 * Identifies a type as a servlet endpoint.
 *
 * @deprecated since 3.3.0 for removal in 3.5.0
 * Use @WebEndpoint instead
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Deprecated(since = "3.3.0", forRemoval = true)
@interface ServletEndpoint {
    /**
     * The ID of the endpoint.
     *
     * @return endpoint ID (never null)
     */
    String id();

    /**
     * The default access level.
     *
     * @return default access (never null)
     */
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a type as a controller endpoint.
 *
 * @deprecated since 3.3.0 for removal in 3.5.0
 * Use @WebEndpoint instead
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ControllerEndpointFilter.class)
@Deprecated(since = "3.3.0", forRemoval = true)
@interface ControllerEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a type as a REST controller endpoint.
 *
 * @deprecated since 3.3.0 for removal in 3.5.0
 * Use @WebEndpoint instead
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ControllerEndpointFilter.class)
@ResponseBody
@Deprecated(since = "3.3.0", forRemoval = true)
@interface RestControllerEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

/**
 * Identifies a type as a servlet-based endpoint.
 *
 * @deprecated since 3.3.0 for removal in 3.5.0
 * Use @WebEndpoint instead
 * @since 2.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ServletEndpointFilter.class)
@Deprecated(since = "3.3.0", forRemoval = true)
@interface ServletEndpoint {
    @AliasFor(annotation = Endpoint.class)
    String id();

    @AliasFor(annotation = Endpoint.class)
    Access defaultAccess() default Access.UNRESTRICTED;
}

Core Infrastructure Types (Full Signatures)

Complete type information for endpoint infrastructure and discovery.

/**
 * Identifier for an endpoint.
 * Provides normalized representation of endpoint IDs.
 *
 * Thread-safe: Yes (immutable)
 * Nullability: Never null
 *
 * @since 2.0.0
 */
public final class EndpointId {

    /**
     * Create an endpoint ID from a value.
     * Normalizes the value (lowercase, validates format).
     *
     * @param value the endpoint ID value (never null)
     * @return the endpoint ID (never null)
     * @throws IllegalArgumentException if value is invalid
     */
    public static EndpointId of(String value);

    /**
     * Create an endpoint ID from a value with environment placeholders.
     * Resolves ${...} placeholders before normalization.
     *
     * @param environment the environment for placeholder resolution (never null)
     * @param value the endpoint ID value with possible placeholders (never null)
     * @return the endpoint ID (never null)
     * @throws IllegalArgumentException if value is invalid
     */
    public static EndpointId of(Environment environment, String value);

    /**
     * Create an endpoint ID from a property value.
     * More lenient than of() - allows dots and underscores.
     *
     * @param value the property value (never null)
     * @return the endpoint ID (never null)
     * @throws IllegalArgumentException if value is invalid
     */
    public static EndpointId fromPropertyValue(String value);

    /**
     * Get lowercase string representation.
     *
     * @return lowercase ID (never null)
     */
    public String toLowerCaseString();

    /**
     * Get string representation (lowercase).
     *
     * @return string representation (never null)
     */
    @Override
    public String toString();

    @Override
    public boolean equals(@Nullable Object obj);

    @Override
    public int hashCode();
}

/**
 * Types of operations that can be performed on an endpoint.
 *
 * Thread-safe: Yes (enum)
 * Immutable: Yes
 *
 * @since 2.0.0
 */
public enum OperationType {
    /**
     * Read operation - retrieves data without side effects.
     * Maps to HTTP GET and JMX read attribute.
     */
    READ,

    /**
     * Write operation - modifies data or triggers action.
     * Maps to HTTP POST and JMX write operation.
     */
    WRITE,

    /**
     * Delete operation - removes data or resources.
     * Maps to HTTP DELETE and JMX remove operation.
     */
    DELETE
}

/**
 * Interface implemented by types that produce a specific MIME type.
 * Used for content negotiation in operations.
 *
 * @param <E> enum type that implements this interface
 * @since 2.5.0
 */
public interface Producible<E extends Enum<E> & Producible<E>> {

    /**
     * Get the MIME type produced.
     *
     * @return the MIME type (never null)
     */
    MimeType getProducedMimeType();

    /**
     * Return if this enum value should be used as the default value when an accept
     * header of &#42;&#47;&#42; is provided, or if the {@code Accept} header is missing.
     * Only one value can be marked as default. If no value is marked, then the value
     * with the highest {@link Enum#ordinal() ordinal} is used as the default.
     *
     * @return if this value should be used as the default value
     * @since 2.5.6
     */
    default boolean isDefault() {
        return false;
    }
}

/**
 * Marker interface for operation response bodies.
 * Indicates that a type is designed to be returned from operations.
 *
 * @since 3.0.0
 */
public interface OperationResponseBody {

    /**
     * Create operation response body from map, handling null.
     *
     * @param <K> key type
     * @param <V> value type
     * @param map the map (may be null)
     * @return the map or null (preserves null)
     */
    static <K, V> @Nullable Map<K, V> of(@Nullable Map<K, V> map);
}

Operation Parameter Interfaces

Complete interfaces for operation parameter introspection and resolution.

/**
 * Information about an operation parameter.
 *
 * Thread-safe: Implementations should be thread-safe
 * Since: Spring Boot 2.0+
 */
public interface OperationParameter {

    /**
     * Returns the parameter name.
     *
     * @return the name (never null)
     */
    String getName();

    /**
     * Returns the parameter type.
     *
     * @return the type (never null)
     */
    Class<?> getType();

    /**
     * Return if the parameter is mandatory (does not accept null values).
     *
     * @return if the parameter is mandatory
     */
    boolean isMandatory();

    /**
     * Returns this element's annotation for the specified type if such an
     * annotation is present, else null.
     *
     * @param annotation class of the annotation
     * @return annotation value (nullable)
     * @param <T> type of the annotation
     * @since 2.7.8
     */
    <T extends Annotation> @Nullable T getAnnotation(Class<T> annotation);
}

/**
 * Collection of operation parameters.
 *
 * Thread-safe: Implementations should be thread-safe
 * Since: Spring Boot 2.0+
 */
public interface OperationParameters extends Iterable<OperationParameter> {

    /**
     * Return {@code true} if there is at least one parameter.
     *
     * @return if there are parameters
     */
    default boolean hasParameters() {
        return getParameterCount() > 0;
    }

    /**
     * Return the total number of parameters.
     *
     * @return the total number of parameters
     */
    int getParameterCount();

    /**
     * Return if any of the contained parameters are
     * {@link OperationParameter#isMandatory() mandatory}.
     *
     * @return if any parameters are mandatory
     */
    default boolean hasMandatoryParameter() {
        return stream().anyMatch(OperationParameter::isMandatory);
    }

    /**
     * Return the parameter at the specified index.
     *
     * @param index the parameter index
     * @return the parameter (never null)
     */
    OperationParameter get(int index);

    /**
     * Return a stream of the contained parameters.
     *
     * @return a stream of the parameters (never null)
     */
    Stream<OperationParameter> stream();
}

/**
 * Resolves arguments for operation invocations.
 *
 * Thread-safe: Implementations should be thread-safe
 * Since: Spring Boot 2.0+
 */
public interface OperationArgumentResolver {

    /**
     * Return whether an argument of the given {@code type} can be resolved.
     *
     * @param type argument type (non-null)
     * @return {@code true} if an argument of the required type can be resolved,
     * otherwise {@code false}
     */
    boolean canResolve(Class<?> type);

    /**
     * Resolves an argument of the given {@code type}.
     *
     * @param <T> required type of the argument
     * @param type argument type (non-null)
     * @return an argument of the required type, or {@code null}
     */
    <T> @Nullable T resolve(Class<T> type);

    /**
     * Factory method that creates an {@link OperationArgumentResolver} for a
     * specific type using a {@link Supplier}.
     *
     * @param <T> the resolvable type
     * @param type the resolvable type (non-null)
     * @param supplier the value supplier (non-null)
     * @return an {@link OperationArgumentResolver} instance (never null)
     */
    static <T> OperationArgumentResolver of(Class<T> type,
                                            Supplier<? extends @Nullable T> supplier) {
        return new OperationArgumentResolver() {
            @Override
            public boolean canResolve(Class<?> candidateType) {
                return type.equals(candidateType);
            }

            @Override
            @SuppressWarnings("unchecked")
            public <R> @Nullable R resolve(Class<R> candidateType) {
                return canResolve(candidateType) ? (R) supplier.get() : null;
            }
        };
    }
}

Endpoint Discovery Infrastructure

Core abstractions for discovering and creating endpoint instances from annotated beans.

/**
 * Base class for {@link EndpointsSupplier} implementations that discover
 * {@link Endpoint @Endpoint} beans and {@link EndpointExtension @EndpointExtension}
 * beans in an application context.
 *
 * Discovers endpoints by scanning the application context for beans annotated with
 * {@code @Endpoint} and its variants, then creates operations from methods annotated
 * with {@code @ReadOperation}, {@code @WriteOperation}, and {@code @DeleteOperation}.
 *
 * Thread-safe: Yes
 * Package: org.springframework.boot.actuate.endpoint.annotation
 * @param <E> the endpoint type
 * @param <O> the operation type
 * @since 2.0.0
 */
public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O extends Operation>
		implements EndpointsSupplier<E> {

	/**
	 * Create a new {@link EndpointDiscoverer} instance.
	 *
	 * @param applicationContext the source application context (never null)
	 * @param parameterValueMapper the parameter value mapper (never null)
	 * @param invokerAdvisors invoker advisors to apply (never null)
	 * @param endpointFilters endpoint filters to apply (never null)
	 * @param operationFilters operation filters to apply (never null)
	 * @since 3.4.0
	 */
	public EndpointDiscoverer(ApplicationContext applicationContext,
			ParameterValueMapper parameterValueMapper,
			Collection<OperationInvokerAdvisor> invokerAdvisors,
			Collection<EndpointFilter<E>> endpointFilters,
			Collection<OperationFilter<O>> operationFilters);

	/**
	 * Return the discovered endpoints.
	 * Results are cached after first invocation.
	 *
	 * @return the endpoints (never null)
	 */
	@Override
	public final Collection<E> getEndpoints();

	/**
	 * Returns whether the endpoint is invocable and should be included in the
	 * discovered endpoints. The default implementation returns {@code true} if the
	 * endpoint has any operations, otherwise {@code false}.
	 *
	 * @param endpoint the endpoint to assess (never null)
	 * @return {@code true} if the endpoint is invocable, otherwise {@code false}
	 * @since 3.4.0
	 */
	protected boolean isInvocable(E endpoint);

	/**
	 * Determine if an extension bean should be exposed. Subclasses can override this
	 * method to provide additional logic.
	 *
	 * @param extensionBeanType the extension bean type (never null)
	 * @return {@code true} if the extension is exposed
	 */
	protected boolean isExtensionTypeExposed(Class<?> extensionBeanType);

	/**
	 * Determine if an endpoint bean should be exposed. Subclasses can override this
	 * method to provide additional logic.
	 *
	 * @param beanType the endpoint bean type (never null)
	 * @return {@code true} if the endpoint is exposed
	 */
	protected boolean isEndpointTypeExposed(Class<?> beanType);

	/**
	 * Get the endpoint type that this discoverer creates.
	 *
	 * @return the endpoint type (never null)
	 */
	protected Class<? extends E> getEndpointType();

	/**
	 * Factory method called to create the {@link ExposableEndpoint endpoint}.
	 * Implementations typically return a {@link DiscoveredEndpoint} instance.
	 *
	 * @param endpointBean the source endpoint bean (never null)
	 * @param id the ID of the endpoint (never null)
	 * @param defaultAccess access to the endpoint that is permitted by default (never null)
	 * @param operations the endpoint operations (never null)
	 * @return a created endpoint (a {@link DiscoveredEndpoint} is recommended, never null)
	 */
	protected abstract E createEndpoint(Object endpointBean, EndpointId id,
			Access defaultAccess, Collection<O> operations);

	/**
	 * Factory method to create an {@link Operation endpoint operation}.
	 *
	 * @param endpointId the endpoint id (never null)
	 * @param operationMethod the operation method (never null)
	 * @param invoker the invoker to use (never null)
	 * @return a created operation (never null)
	 */
	protected abstract O createOperation(EndpointId endpointId,
			DiscoveredOperationMethod operationMethod,
			OperationInvoker invoker);

	/**
	 * Create an {@link OperationKey} for the given operation.
	 * Used to detect duplicate operations.
	 *
	 * @param operation the source operation (never null)
	 * @return the operation key (never null)
	 */
	protected abstract OperationKey createOperationKey(O operation);

	/**
	 * A key generated for an {@link Operation} based on specific criteria from the
	 * actual operation implementation. Used to detect and prevent duplicate operations.
	 *
	 * Thread-safe: Yes (immutable)
	 */
	protected static final class OperationKey {

		/**
		 * Create a new {@link OperationKey} instance.
		 *
		 * @param key the underlying key for the operation (never null)
		 * @param description a human-readable description of the key (never null)
		 */
		public OperationKey(Object key, Supplier<String> description);

		@Override
		public boolean equals(@Nullable Object obj);

		@Override
		public int hashCode();

		/**
		 * Returns human-readable description of the key.
		 *
		 * @return the description (never null)
		 */
		@Override
		public String toString();
	}
}

/**
 * An {@link OperationMethod} discovered by an {@link EndpointDiscoverer}.
 * Extends {@link OperationMethod} with additional information about produced media types.
 *
 * Thread-safe: Yes (immutable after construction)
 * Package: org.springframework.boot.actuate.endpoint.annotation
 * @since 2.0.0
 */
public class DiscoveredOperationMethod extends OperationMethod {

	/**
	 * Create a new {@link DiscoveredOperationMethod} instance.
	 *
	 * @param method the source method (never null)
	 * @param operationType the operation type (never null)
	 * @param annotationAttributes attributes from the operation annotation (never null)
	 */
	public DiscoveredOperationMethod(Method method, OperationType operationType,
			AnnotationAttributes annotationAttributes);

	/**
	 * Return the media types that this operation produces.
	 * Media types are determined from the {@code produces} and {@code producesFrom}
	 * attributes of the operation annotation.
	 *
	 * @return unmodifiable list of produced media types (never null, may be empty)
	 */
	public List<String> getProducesMediaTypes();
}

Endpoint Discovery and Filtering

Interfaces for filtering which endpoints and operations are exposed.

/**
 * Filter for endpoints.
 * Determines which endpoints should be exposed through a particular technology.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @param <E> the type of endpoint to filter
 * @since 2.0.0
 */
@FunctionalInterface
public interface EndpointFilter<E extends ExposableEndpoint<?>> {

    /**
     * Return {@code true} if the filter matches the given endpoint.
     * Only matching endpoints will be exposed.
     *
     * @param endpoint the endpoint to check (never null)
     * @return {@code true} if the endpoint matches and should be exposed
     */
    boolean match(E endpoint);
}

/**
 * Filter for operations within an endpoint.
 * Determines which operations should be exposed based on access control rules.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @param <O> the type of operation to filter
 * @since 3.4.0
 */
@FunctionalInterface
public interface OperationFilter<O extends Operation> {

    /**
     * Return {@code true} if the filter matches the given operation.
     * Only matching operations will be exposed.
     *
     * @param operation the operation to check (never null)
     * @param endpointId the ID of the endpoint to which the operation belongs (never null)
     * @param defaultAccess the default permitted level of access to the endpoint (never null)
     * @return {@code true} if the operation matches and should be exposed
     */
    boolean match(O operation, EndpointId endpointId, Access defaultAccess);

    /**
     * Return an {@link OperationFilter} that filters based on the allowed {@link Access}
     * as determined by an {@link EndpointAccessResolver}.
     *
     * The returned filter:
     * - Returns {@code false} for NONE access (no operations exposed)
     * - Returns {@code true} only for READ operations when READ_ONLY access
     * - Returns {@code true} for all operations when UNRESTRICTED access
     *
     * @param <O> the operation type
     * @param accessResolver the access resolver (never null)
     * @return a new {@link OperationFilter} (never null)
     */
    static <O extends Operation> OperationFilter<O> byAccess(EndpointAccessResolver accessResolver) {
        return (operation, endpointId, defaultAccess) -> {
            Access access = accessResolver.accessFor(endpointId, defaultAccess);
            return switch (access) {
                case NONE -> false;
                case READ_ONLY -> operation.getType() == OperationType.READ;
                case UNRESTRICTED -> true;
            };
        };
    }
}

/**
 * Resolver for the permitted level of {@link Access access} to an endpoint.
 * Determines which operations can be invoked based on configuration and security rules.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @since 3.4.0
 */
public interface EndpointAccessResolver {

    /**
     * Resolves the permitted level of access for the endpoint with the given
     * {@code endpointId} and {@code defaultAccess}.
     *
     * Implementations typically check configuration properties like
     * {@code management.endpoint.<id>.access} and return the appropriate access level.
     *
     * @param endpointId the ID of the endpoint (never null)
     * @param defaultAccess the default access level of the endpoint (never null)
     * @return the permitted level of access (never null)
     */
    Access accessFor(EndpointId endpointId, Access defaultAccess);
}

/**
 * Supplier of endpoints.
 * Typically implemented by {@link EndpointDiscoverer} to provide discovered endpoints.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @param <E> the type of endpoint
 * @since 2.0.0
 */
@FunctionalInterface
public interface EndpointsSupplier<E extends ExposableEndpoint<?>> {

    /**
     * Return the endpoints supplied by this instance.
     *
     * @return the endpoints (never null)
     */
    Collection<E> getEndpoints();
}

/**
 * An {@link ExposableEndpoint endpoint} discovered by an {@link EndpointDiscoverer}.
 * Provides access to the original source bean and discovery metadata.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.annotation
 * @param <O> the type of operations the endpoint has
 * @since 2.0.0
 */
public interface DiscoveredEndpoint<O extends Operation> extends ExposableEndpoint<O> {

    /**
     * Return {@code true} if the endpoint was discovered by the specified discoverer.
     * Useful when multiple discoverers are used and you need to know which one
     * discovered a particular endpoint.
     *
     * @param discoverer the discoverer type (never null)
     * @return {@code true} if discovered using the specified discoverer
     */
    boolean wasDiscoveredBy(Class<? extends EndpointDiscoverer<?, ?>> discoverer);

    /**
     * Return the source bean that was used to construct the {@link DiscoveredEndpoint}.
     * This is the original bean instance annotated with {@code @Endpoint} or one of
     * its variants.
     *
     * @return the source endpoint bean (never null)
     */
    Object getEndpointBean();
}

/**
 * Abstract base class for {@link ExposableEndpoint} implementations.
 * Provides core functionality for managing endpoint ID, access control, and operations.
 *
 * This class is the foundation for all endpoint implementations in the actuator framework.
 * Subclasses only need to provide endpoint-specific behavior while inheriting the basic
 * endpoint structure.
 *
 * Thread-safe: Yes (immutable after construction)
 * Package: org.springframework.boot.actuate.endpoint
 * @param <O> the type of operations the endpoint has
 * @since 2.0.0
 */
public abstract class AbstractExposableEndpoint<O extends Operation> implements ExposableEndpoint<O> {

    /**
     * Create a new {@link AbstractExposableEndpoint} instance.
     *
     * @param id the endpoint id (never null)
     * @param defaultAccess access to the endpoint that is permitted by default (never null)
     * @param operations the endpoint operations (never null, immutable copy is created)
     * @since 3.4.0
     */
    public AbstractExposableEndpoint(EndpointId id, Access defaultAccess, Collection<? extends O> operations);

    /**
     * {@inheritDoc}
     */
    @Override
    public EndpointId getEndpointId();

    /**
     * {@inheritDoc}
     */
    @Override
    public Access getDefaultAccess();

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<O> getOperations();
}

/**
 * Abstract base class for {@link ExposableEndpoint} endpoints discovered by a
 * {@link EndpointDiscoverer}. Provides a convenient base implementation for
 * custom discovered endpoints.
 *
 * Thread-safe: Yes
 * Package: org.springframework.boot.actuate.endpoint.annotation
 * @param <O> the type of operations the endpoint has
 * @since 2.0.0
 */
public abstract class AbstractDiscoveredEndpoint<O extends Operation> extends AbstractExposableEndpoint<O>
        implements DiscoveredEndpoint<O> {

    /**
     * Create a new {@link AbstractDiscoveredEndpoint} instance.
     *
     * @param discoverer the discoverer that discovered the endpoint (never null)
     * @param endpointBean the primary source bean (never null)
     * @param id the ID of the endpoint (never null)
     * @param defaultAccess access to the endpoint that is permitted by default (never null)
     * @param operations the endpoint operations (never null)
     * @since 3.4.0
     */
    protected AbstractDiscoveredEndpoint(EndpointDiscoverer<?, ?> discoverer,
                                        Object endpointBean,
                                        EndpointId id,
                                        Access defaultAccess,
                                        Collection<? extends O> operations);

    /**
     * {@inheritDoc}
     */
    Object getEndpointBean();

    /**
     * {@inheritDoc}
     */
    boolean wasDiscoveredBy(Class<? extends EndpointDiscoverer<?, ?>> discoverer);

    /**
     * Hook for subclasses to append additional fields to the toString output.
     * Called during toString() generation.
     *
     * @param creator the ToStringCreator to append fields to (never null)
     */
    protected void appendFields(ToStringCreator creator);
}

Endpoint Interfaces

Core interfaces representing endpoints and operations.

/**
 * Information about an endpoint that can be exposed.
 *
 * Thread-safe: Implementations should be thread-safe
 * @param <O> the type of operation
 * @since 2.0.0
 */
public interface ExposableEndpoint<O extends Operation> {

    /**
     * Return the endpoint ID.
     *
     * @return the endpoint ID (never null)
     */
    EndpointId getEndpointId();

    /**
     * Return the default access level for the endpoint.
     *
     * @return the default access level (never null)
     * @since 3.4.0
     */
    Access getDefaultAccess();

    /**
     * Return the operations on the endpoint.
     *
     * @return the operations (never null)
     */
    Collection<O> getOperations();
}

/**
 * Information describing an endpoint that can be exposed over the web.
 *
 * @since 2.0.0
 */
public interface ExposableWebEndpoint extends ExposableEndpoint<WebOperation>, PathMappedEndpoint {
}

/**
 * Information describing an endpoint that can be exposed over JMX.
 *
 * @since 2.0.0
 */
public interface ExposableJmxEndpoint extends ExposableEndpoint<JmxOperation> {
}

/**
 * An operation on an endpoint.
 *
 * Thread-safe: Implementations should be thread-safe
 * @since 2.0.0
 */
public interface Operation {

    /**
     * Return the type of operation.
     *
     * @return the operation type (never null)
     */
    OperationType getType();

    /**
     * Invoke the operation with the given invocation context.
     *
     * @param context the invocation context (never null)
     * @return the result of the invocation (may be null)
     */
    @Nullable Object invoke(InvocationContext context);
}

/**
 * An operation on a web endpoint.
 * Extends base Operation with web-specific metadata.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.web
 * @since 2.0.0
 */
public interface WebOperation extends Operation {

    /**
     * Return the ID of the operation.
     *
     * @return the operation ID (never null)
     */
    String getId();

    /**
     * Return if the operation is blocking.
     *
     * @return {@code true} if the operation blocks
     */
    boolean isBlocking();

    /**
     * Return the request predicate for the operation.
     *
     * @return the request predicate (never null)
     */
    WebOperationRequestPredicate getRequestPredicate();
}

/**
 * An operation on a JMX endpoint.
 * Extends base Operation with JMX-specific metadata.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jmx
 * @since 2.0.0
 */
public interface JmxOperation extends Operation {

    /**
     * Return the name of the operation.
     *
     * @return the operation name (never null)
     */
    String getName();

    /**
     * Return the output type of the operation.
     *
     * @return the output type (never null)
     */
    Class<?> getOutputType();

    /**
     * Return the description of the operation.
     *
     * @return the operation description (never null)
     */
    String getDescription();

    /**
     * Return the parameters of the operation.
     *
     * @return the operation parameters (never null)
     */
    List<JmxOperationParameter> getParameters();
}

/**
 * A parameter of a JMX operation.
 * Provides metadata about JMX operation parameters for introspection.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jmx
 * @since 2.0.0
 */
public interface JmxOperationParameter {

    /**
     * Return the name of the parameter.
     *
     * @return the parameter name (never null)
     */
    String getName();

    /**
     * Return the type of the parameter.
     *
     * @return the parameter type (never null)
     */
    Class<?> getType();

    /**
     * Return the description of the parameter, if available.
     *
     * @return the parameter description (may be null)
     */
    @Nullable String getDescription();
}

/**
 * A predicate for matching requests to a web operation.
 * Specifies the path, HTTP method, and content types for web endpoint operations.
 *
 * Thread-safe: Yes (immutable)
 * Package: org.springframework.boot.actuate.endpoint.web
 * @since 2.0.0
 */
public final class WebOperationRequestPredicate {

    /**
     * Create a new request predicate.
     *
     * @param path the path (never null)
     * @param httpMethod the HTTP method (never null)
     * @param consumes the consumed media types (never null)
     * @param produces the produced media types (never null)
     */
    public WebOperationRequestPredicate(String path, WebEndpointHttpMethod httpMethod,
                                       Collection<String> consumes, Collection<String> produces);

    /**
     * Return the path of the operation.
     *
     * @return the path (never null)
     */
    public String getPath();

    /**
     * Return the variable name for matching all remaining path segments, if any.
     *
     * @return the variable name (may be null)
     * @since 2.2.0
     */
    public @Nullable String getMatchAllRemainingPathSegmentsVariable();

    /**
     * Return the HTTP method of the operation.
     *
     * @return the HTTP method (never null)
     */
    public WebEndpointHttpMethod getHttpMethod();

    /**
     * Return the consumed media types.
     *
     * @return the consumed media types (never null, may be empty)
     */
    public Collection<String> getConsumes();

    /**
     * Return the produced media types.
     *
     * @return the produced media types (never null, may be empty)
     */
    public Collection<String> getProduces();
}

Argument Resolvers

Resolvers for operation arguments and content negotiation.

/**
 * Resolver for arguments that are Producible types.
 * Resolves content negotiation for operations.
 *
 * Thread-safe: Yes
 * @since 2.2.0
 */
public final class ProducibleOperationArgumentResolver implements OperationArgumentResolver {

    /**
     * Create a new instance.
     *
     * @param accepts supplier that provides the list of accepted media types from request
     */
    public ProducibleOperationArgumentResolver(Supplier<@Nullable List<String>> accepts);

    @Override
    public boolean canResolve(Class<?> type);

    @Override
    public <T> @Nullable T resolve(Class<T> type);
}

Core Infrastructure Interfaces

Core interfaces that underpin the endpoint framework, providing abstractions for operations, exposable endpoints, and technology-specific extensions.

/**
 * An operation on an endpoint.
 * Base interface for all endpoint operations (read, write, delete).
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @since 2.0.0
 */
public interface Operation {

    /**
     * Returns the type of the operation.
     *
     * @return the operation type (never null)
     */
    OperationType getType();

    /**
     * Invoke the underlying operation using the given context.
     * Results intended to be returned in the body of the response
     * should additionally implement OperationResponseBody.
     *
     * @param context the context to use when invoking the operation (never null)
     * @return the result of the operation, may be null
     */
    @Nullable Object invoke(InvocationContext context);
}

/**
 * An operation on a web endpoint.
 * Extends Operation with web-specific properties like HTTP method and request predicate.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.web
 * @since 2.0.0
 */
public interface WebOperation extends Operation {

    /**
     * Returns the ID of the operation that uniquely identifies it within its endpoint.
     *
     * @return the operation ID (never null)
     */
    String getId();

    /**
     * Returns if the underlying operation is blocking.
     *
     * @return true if the operation is blocking
     */
    boolean isBlocking();

    /**
     * Returns the predicate for requests that can be handled by this operation.
     *
     * @return the request predicate (never null)
     */
    WebOperationRequestPredicate getRequestPredicate();
}

/**
 * An operation on a JMX endpoint.
 * Extends Operation with JMX-specific properties like operation name and parameters.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jmx
 * @since 2.0.0
 */
public interface JmxOperation extends Operation {

    /**
     * Returns the name of the operation.
     *
     * @return the operation name (never null)
     */
    String getName();

    /**
     * Returns the type of the output of the operation.
     *
     * @return the output type (never null)
     */
    Class<?> getOutputType();

    /**
     * Returns the description of the operation.
     *
     * @return the operation description (never null)
     */
    String getDescription();

    /**
     * Returns the parameters the operation expects in the order that they should be provided.
     *
     * @return the operation parameters (never null, may be empty)
     */
    List<JmxOperationParameter> getParameters();
}

/**
 * Describes a parameter of a JMX operation.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jmx
 * @since 2.0.0
 */
public interface JmxOperationParameter {

    /**
     * Return the name of the operation parameter.
     *
     * @return the name of the parameter (never null)
     */
    String getName();

    /**
     * Return the type of the operation parameter.
     *
     * @return the parameter type (never null)
     */
    Class<?> getType();

    /**
     * Return the description of the parameter or null if none is available.
     *
     * @return the description or null
     */
    @Nullable String getDescription();
}

/**
 * Information describing an endpoint that can be exposed in some technology specific way.
 * Base interface for all exposable endpoints.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint
 * @param <O> the type of the endpoint's operations
 * @since 2.0.0
 */
public interface ExposableEndpoint<O extends Operation> {

    /**
     * Return the endpoint ID.
     *
     * @return the endpoint ID (never null)
     */
    EndpointId getEndpointId();

    /**
     * Returns the access to the endpoint that is permitted by default.
     *
     * @return access that is permitted by default (never null)
     * @since 3.4.0
     */
    Access getDefaultAccess();

    /**
     * Returns the operations of the endpoint.
     *
     * @return the operations (never null, may be empty)
     */
    Collection<O> getOperations();
}

/**
 * Information describing an endpoint that can be exposed over the web.
 * Combines ExposableEndpoint with PathMappedEndpoint for HTTP exposure.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.web
 * @since 2.0.0
 */
public interface ExposableWebEndpoint extends ExposableEndpoint<WebOperation>, PathMappedEndpoint {
    // Inherits all methods from ExposableEndpoint<WebOperation> and PathMappedEndpoint
    // No additional methods defined
}

/**
 * Information describing an endpoint that can be exposed over JMX.
 *
 * Thread-safe: Implementations must be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jmx
 * @since 2.0.0
 */
public interface ExposableJmxEndpoint extends ExposableEndpoint<JmxOperation> {
    // Inherits all methods from ExposableEndpoint<JmxOperation>
    // No additional methods defined
}

/**
 * A predicate for a request to an operation on a web endpoint.
 * Encapsulates HTTP method, path, and content negotiation details.
 *
 * Thread-safe: Yes (immutable)
 * Package: org.springframework.boot.actuate.endpoint.web
 * @since 2.0.0
 */
public final class WebOperationRequestPredicate {

    /**
     * Creates a new OperationRequestPredicate.
     *
     * @param path the path for the operation (never null)
     * @param httpMethod the HTTP method that the operation supports (never null)
     * @param consumes the media types that the operation consumes (never null)
     * @param produces the media types that the operation produces (never null)
     */
    public WebOperationRequestPredicate(String path,
                                       WebEndpointHttpMethod httpMethod,
                                       Collection<String> consumes,
                                       Collection<String> produces);

    /**
     * Returns the path for the operation.
     *
     * @return the path (never null)
     */
    public String getPath();

    /**
     * Returns the name of the variable used to catch all remaining path segments or null.
     *
     * @return the variable name or null
     * @since 2.2.0
     */
    public @Nullable String getMatchAllRemainingPathSegmentsVariable();

    /**
     * Returns the HTTP method for the operation.
     *
     * @return the HTTP method (never null)
     */
    public WebEndpointHttpMethod getHttpMethod();

    /**
     * Returns the media types that the operation consumes.
     *
     * @return the consumed media types (never null, unmodifiable)
     */
    public Collection<String> getConsumes();

    /**
     * Returns the media types that the operation produces.
     *
     * @return the produced media types (never null, unmodifiable)
     */
    public Collection<String> getProduces();
}

Exception Types (Full Signatures)

Complete exception types for endpoint error handling.

/**
 * Exception thrown when an endpoint request is invalid.
 *
 * Thread-safe: Yes (immutable after construction)
 *
 * @since 2.0.0
 */
public class InvalidEndpointRequestException extends RuntimeException {

    /**
     * Create exception with message and reason.
     *
     * @param message the exception message (never null)
     * @param reason the reason for the invalid request (never null)
     */
    public InvalidEndpointRequestException(String message, String reason);

    /**
     * Create exception with message, reason, and cause.
     *
     * @param message the exception message (never null)
     * @param reason the reason for the invalid request (never null)
     * @param cause the cause (may be null)
     */
    public InvalidEndpointRequestException(String message, String reason,
                                          @Nullable Throwable cause);

    /**
     * Get the reason for the invalid request.
     *
     * @return the reason (never null)
     */
    public String getReason();
}

/**
 * Exception thrown when required parameters are missing.
 *
 * Thread-safe: Yes (immutable after construction)
 *
 * @since 2.0.0
 */
public class MissingParametersException extends RuntimeException {

    /**
     * Create exception with missing parameters.
     *
     * @param missingParameters the missing parameters (never null, never empty)
     */
    public MissingParametersException(Set<OperationParameter> missingParameters);

    /**
     * Get the missing parameters.
     *
     * @return unmodifiable set of missing parameters (never null, never empty)
     */
    public Set<OperationParameter> getMissingParameters();
}

/**
 * Exception thrown when parameter value mapping fails.
 *
 * Thread-safe: Yes (immutable after construction)
 *
 * @since 2.0.0
 */
public class ParameterMappingException extends RuntimeException {

    /**
     * Create exception for parameter mapping failure.
     *
     * @param parameter the parameter that failed mapping (never null)
     * @param value the value that failed to map (may be null)
     * @param cause the cause of the mapping failure (never null)
     */
    public ParameterMappingException(OperationParameter parameter,
                                    @Nullable Object value,
                                    Throwable cause);

    /**
     * Get the parameter that failed mapping.
     *
     * @return the parameter (never null)
     */
    public OperationParameter getParameter();

    /**
     * Get the value that failed to map.
     *
     * @return the value (may be null)
     */
    public @Nullable Object getValue();
}

Jackson Integration

Interfaces for customizing Jackson serialization of endpoint responses.

/**
 * Interface used to supply the JsonMapper for endpoint result serialization.
 * Used when serializing OperationResponseBody types.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jackson
 * @since 4.0.0
 */
@FunctionalInterface
public interface EndpointJsonMapper {

    /**
     * Return the JsonMapper for serializing endpoint results.
     *
     * @return the JSON mapper (never null)
     */
    JsonMapper get();
}

/**
 * Interface used to supply the Jackson 2 ObjectMapper for endpoint result serialization.
 * Used when serializing OperationResponseBody types.
 *
 * Thread-safe: Implementations should be thread-safe
 * Package: org.springframework.boot.actuate.endpoint.jackson
 * @since 4.0.0
 * @deprecated since 4.0.0 for removal in 4.2.0 in favor of Jackson 3
 */
@FunctionalInterface
@Deprecated(since = "4.0.0", forRemoval = true)
public interface EndpointJackson2ObjectMapper {

    /**
     * Return the ObjectMapper for serializing endpoint results.
     *
     * @return the object mapper (never null)
     */
    ObjectMapper get();
}

Cross-References

  • For HTTP-specific features: Web Integration
  • For JMX-specific features: JMX Integration
  • For security: Security Integration
  • For data protection: Data Sanitization
  • For operation invocation: Operation Invocation
  • For built-in endpoints: Built-in Endpoints