Migrate endpoints to return OperationResponseBody types

Update types returned from endpoints to implement the
`OperationResponseBody` interface. This ensures that they will be
serialized using the isolated actuator `ObjectMapper`.

See gh-20291
pull/33098/head
Phillip Webb 2 years ago
parent 1f8493fb29
commit 3d2071d044

@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
@ -81,7 +82,7 @@ public class ConditionsReportEndpoint {
/**
* A description of an application's condition evaluation.
*/
public static final class ConditionsDescriptor {
public static final class ConditionsDescriptor implements OperationResponseBody {
private final Map<String, ContextConditionsDescriptor> contexts;

@ -20,6 +20,7 @@ import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.List;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.lang.Nullable;
@ -55,7 +56,7 @@ public class AuditEventsEndpoint {
/**
* Description of an application's {@link AuditEvent audit events}.
*/
public static final class AuditEventsDescriptor {
public static final class AuditEventsDescriptor implements OperationResponseBody {
private final List<AuditEvent> events;

@ -22,6 +22,7 @@ import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.context.ApplicationContext;
@ -73,7 +74,7 @@ public class BeansEndpoint {
/**
* Description of an application's beans.
*/
public static final class BeansDescriptor {
public static final class BeansDescriptor implements OperationResponseBody {
private final Map<String, ContextBeansDescriptor> contexts;

@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
@ -148,7 +149,7 @@ public class CachesEndpoint {
/**
* Description of the caches.
*/
public static final class CachesDescriptor {
public static final class CachesDescriptor implements OperationResponseBody {
private final Map<String, CacheManagerDescriptor> cacheManagers;
@ -182,7 +183,7 @@ public class CachesEndpoint {
/**
* Description of a {@link Cache}.
*/
public static class CacheDescriptor {
public static class CacheDescriptor implements OperationResponseBody {
private final String target;

@ -17,6 +17,7 @@
package org.springframework.boot.actuate.context;
import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.context.ApplicationContext;
@ -71,7 +72,7 @@ public class ShutdownEndpoint implements ApplicationContextAware {
/**
* Description of the shutdown.
*/
public static class ShutdownDescriptor {
public static class ShutdownDescriptor implements OperationResponseBody {
private static final ShutdownDescriptor DEFAULT = new ShutdownDescriptor("Shutting down, bye...");

@ -54,6 +54,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.SanitizableData;
import org.springframework.boot.actuate.endpoint.Sanitizer;
import org.springframework.boot.actuate.endpoint.SanitizingFunction;
@ -564,7 +565,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
* Description of an application's
* {@link ConfigurationProperties @ConfigurationProperties} beans.
*/
public static final class ConfigurationPropertiesDescriptor {
public static final class ConfigurationPropertiesDescriptor implements OperationResponseBody {
private final Map<String, ContextConfigurationPropertiesDescriptor> contexts;

@ -43,6 +43,7 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -323,7 +324,8 @@ public class JerseyEndpointResourceFactory {
public Response apply(ContainerRequestContext request) {
Map<String, Link> links = this.linksResolver
.resolveLinks(request.getUriInfo().getAbsolutePath().toString());
return Response.ok(Collections.singletonMap("_links", links)).build();
Map<String, Map<String, Link>> entity = OperationResponseBody.of(Collections.singletonMap("_links", links));
return Response.ok(entity).build();
}
}

@ -26,6 +26,7 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@ -87,8 +88,8 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
public Map<String, Map<String, Link>> links(ServerWebExchange exchange) {
String requestUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI()).replaceQuery(null)
.toUriString();
return Collections.singletonMap("_links",
WebFluxEndpointHandlerMapping.this.linksResolver.resolveLinks(requestUri));
Map<String, Link> links = WebFluxEndpointHandlerMapping.this.linksResolver.resolveLinks(requestUri);
return OperationResponseBody.of(Collections.singletonMap("_links", links));
}
@Override

@ -28,6 +28,7 @@ import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@ -84,8 +85,9 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM
@ResponseBody
@Reflective
public Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {
return Collections.singletonMap("_links",
WebMvcEndpointHandlerMapping.this.linksResolver.resolveLinks(request.getRequestURL().toString()));
Map<String, Link> links = WebMvcEndpointHandlerMapping.this.linksResolver
.resolveLinks(request.getRequestURL().toString());
return OperationResponseBody.of(Collections.singletonMap("_links", links));
}
@Override

@ -27,6 +27,7 @@ import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.SanitizableData;
import org.springframework.boot.actuate.endpoint.Sanitizer;
import org.springframework.boot.actuate.endpoint.SanitizingFunction;
@ -203,7 +204,7 @@ public class EnvironmentEndpoint {
/**
* Description of an {@link Environment}.
*/
public static final class EnvironmentDescriptor {
public static final class EnvironmentDescriptor implements OperationResponseBody {
private final List<String> activeProfiles;

@ -28,6 +28,7 @@ import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.MigrationState;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.context.ApplicationContext;
@ -69,7 +70,7 @@ public class FlywayEndpoint {
/**
* Description of an application's {@link Flyway} beans.
*/
public static final class FlywayBeansDescriptor {
public static final class FlywayBeansDescriptor implements OperationResponseBody {
private final Map<String, ContextFlywayBeansDescriptor> contexts;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +18,8 @@ package org.springframework.boot.actuate.health;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
/**
* A component that contributes data to results returned from the {@link HealthEndpoint}.
*
@ -26,7 +28,7 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
* @see Health
* @see CompositeHealth
*/
public abstract class HealthComponent {
public abstract class HealthComponent implements OperationResponseBody {
HealthComponent() {
}

@ -19,6 +19,7 @@ package org.springframework.boot.actuate.info;
import java.util.List;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.util.Assert;
@ -51,7 +52,7 @@ public class InfoEndpoint {
for (InfoContributor contributor : this.infoContributors) {
contributor.contribute(builder);
}
return builder.build().getDetails();
return OperationResponseBody.of(builder.build().getDetails());
}
}

@ -22,6 +22,7 @@ import java.util.Map;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
@ -99,7 +100,7 @@ public class IntegrationGraphEndpoint {
/**
* Description of a {@link Graph}.
*/
public static class GraphDescriptor {
public static class GraphDescriptor implements OperationResponseBody {
private final Map<String, Object> contentDescriptor;

@ -32,6 +32,7 @@ import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.integration.spring.SpringLiquibase;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.context.ApplicationContext;
@ -106,7 +107,7 @@ public class LiquibaseEndpoint {
/**
* Description of an application's {@link SpringLiquibase} beans.
*/
public static final class LiquibaseBeansDescriptor {
public static final class LiquibaseBeansDescriptor implements OperationResponseBody {
private final Map<String, ContextLiquibaseBeansDescriptor> contexts;

@ -25,6 +25,7 @@ import java.util.Set;
import java.util.TreeSet;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
@ -121,7 +122,7 @@ public class LoggersEndpoint {
/**
* Description of loggers.
*/
public static class LoggersDescriptor {
public static class LoggersDescriptor implements OperationResponseBody {
/**
* Empty description.
@ -158,7 +159,7 @@ public class LoggersEndpoint {
/**
* Description of levels configured for a given logger.
*/
public static class LoggerLevelsDescriptor {
public static class LoggerLevelsDescriptor implements OperationResponseBody {
private String configuredLevel;

@ -22,6 +22,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
@ -54,7 +55,7 @@ public class ThreadDumpEndpoint {
/**
* Description of a thread dump.
*/
public static final class ThreadDumpDescriptor {
public static final class ThreadDumpDescriptor implements OperationResponseBody {
private final List<ThreadInfo> threads;

@ -34,6 +34,7 @@ import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
@ -159,7 +160,7 @@ public class MetricsEndpoint {
/**
* Description of metric names.
*/
public static final class MetricNamesDescriptor {
public static final class MetricNamesDescriptor implements OperationResponseBody {
private final Set<String> names;
@ -176,7 +177,7 @@ public class MetricsEndpoint {
/**
* Description of a metric.
*/
public static final class MetricDescriptor {
public static final class MetricDescriptor implements OperationResponseBody {
private final String name;

@ -47,6 +47,7 @@ import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.SanitizableData;
import org.springframework.boot.actuate.endpoint.Sanitizer;
import org.springframework.boot.actuate.endpoint.SanitizingFunction;
@ -236,8 +237,9 @@ public class QuartzEndpoint {
return null;
}
TriggerState triggerState = this.scheduler.getTriggerState(triggerKey);
return TriggerDescriptor.of(trigger).buildDetails(triggerState,
sanitizeJobDataMap(trigger.getJobDataMap(), showUnsanitized));
TriggerDescriptor triggerDescriptor = TriggerDescriptor.of(trigger);
Map<String, Object> jobDataMap = sanitizeJobDataMap(trigger.getJobDataMap(), showUnsanitized);
return OperationResponseBody.of(triggerDescriptor.buildDetails(triggerState, jobDataMap));
}
private static Duration getIntervalDuration(long amount, IntervalUnit unit) {
@ -279,7 +281,7 @@ public class QuartzEndpoint {
/**
* Description of available job and trigger group names.
*/
public static final class QuartzDescriptor {
public static final class QuartzDescriptor implements OperationResponseBody {
private final GroupNamesDescriptor jobs;
@ -320,7 +322,7 @@ public class QuartzEndpoint {
/**
* Description of each group identified by name.
*/
public static class QuartzGroupsDescriptor {
public static class QuartzGroupsDescriptor implements OperationResponseBody {
private final Map<String, Object> groups;
@ -337,7 +339,7 @@ public class QuartzEndpoint {
/**
* Description of the {@link JobDetail jobs} in a given group.
*/
public static final class QuartzJobGroupSummaryDescriptor {
public static final class QuartzJobGroupSummaryDescriptor implements OperationResponseBody {
private final String group;
@ -382,7 +384,7 @@ public class QuartzEndpoint {
/**
* Description of a {@link Job Quartz Job}.
*/
public static final class QuartzJobDetailsDescriptor {
public static final class QuartzJobDetailsDescriptor implements OperationResponseBody {
private final String group;
@ -449,7 +451,7 @@ public class QuartzEndpoint {
/**
* Description of the {@link Trigger triggers} in a given group.
*/
public static final class QuartzTriggerGroupSummaryDescriptor {
public static final class QuartzTriggerGroupSummaryDescriptor implements OperationResponseBody {
private final String group;

@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksEndpointRuntimeHints;
@ -75,7 +76,7 @@ public class ScheduledTasksEndpoint {
/**
* Description of an application's scheduled {@link Task Tasks}.
*/
public static final class ScheduledTasksDescriptor {
public static final class ScheduledTasksDescriptor implements OperationResponseBody {
private final List<TaskDescriptor> cron;

@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
@ -70,7 +71,7 @@ public class SessionsEndpoint {
/**
* Description of user's {@link Session sessions}.
*/
public static final class SessionsDescriptor {
public static final class SessionsDescriptor implements OperationResponseBody {
private final List<SessionDescriptor> sessions;
@ -87,7 +88,7 @@ public class SessionsEndpoint {
/**
* Description of user's {@link Session session}.
*/
public static final class SessionDescriptor {
public static final class SessionDescriptor implements OperationResponseBody {
private final String id;

@ -21,6 +21,7 @@ import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
@ -68,7 +69,7 @@ public class StartupEndpoint {
/**
* Description of an application startup.
*/
public static final class StartupDescriptor {
public static final class StartupDescriptor implements OperationResponseBody {
private final String springBootVersion;

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.web.exchanges;
import java.util.List;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.util.Assert;
@ -51,7 +52,7 @@ public class HttpExchangesEndpoint {
/**
* Description of an application's {@link HttpExchange} entries.
*/
public static final class HttpExchangesDescriptor {
public static final class HttpExchangesDescriptor implements OperationResponseBody {
private final List<HttpExchange> exchanges;

@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.context.ApplicationContext;
@ -64,7 +65,7 @@ public class MappingsEndpoint {
/**
* Description of an application's request mappings.
*/
public static final class ApplicationMappingsDescriptor {
public static final class ApplicationMappingsDescriptor implements OperationResponseBody {
private final Map<String, ContextMappingsDescriptor> contextMappings;

@ -68,19 +68,19 @@ class IntegrationGraphEndpointTests {
@Test
void readOperationShouldReturnGraph() {
Graph mockedGraph = mock(Graph.class);
Graph graph = mock(Graph.class);
Map<String, Object> contentDescriptor = new LinkedHashMap<>();
Collection<IntegrationNode> nodes = new ArrayList<>();
Collection<LinkNode> links = new ArrayList<>();
given(mockedGraph.getContentDescriptor()).willReturn(contentDescriptor);
given(mockedGraph.getNodes()).willReturn(nodes);
given(mockedGraph.getLinks()).willReturn(links);
given(this.server.getGraph()).willReturn(mockedGraph);
GraphDescriptor graph = this.endpoint.graph();
given(graph.getContentDescriptor()).willReturn(contentDescriptor);
given(graph.getNodes()).willReturn(nodes);
given(graph.getLinks()).willReturn(links);
given(this.server.getGraph()).willReturn(graph);
GraphDescriptor descriptor = this.endpoint.graph();
then(this.server).should().getGraph();
assertThat(graph.getContentDescriptor()).isSameAs(contentDescriptor);
assertThat(graph.getNodes()).isSameAs(nodes);
assertThat(graph.getLinks()).isSameAs(links);
assertThat(descriptor.getContentDescriptor()).isSameAs(contentDescriptor);
assertThat(descriptor.getNodes()).isSameAs(nodes);
assertThat(descriptor.getLinks()).isSameAs(links);
}
@Test

Loading…
Cancel
Save