Fix package tangle in endpoint package

Fix package tangle in the actuator endpoint package by relocating a
few classes.

The `Producible` and `ProducibleOperationArgumentResolver` classes have
been moved from `endpoint.annotation` to `endpoint` since they aren't
directly tied to annotations.

The `ApiVersion` class has been moved from `endpoint.http` to
`endpoint` since it needs to implement `Producible` and isn't really
tied to HTTP.

Closes gh-25914
pull/25943/head
Phillip Webb 4 years ago
parent e766c8b3a7
commit e4164d0143

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,12 +19,12 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.EndpointCloudFoundryExtension; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.EndpointCloudFoundryExtension;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.HealthComponent; import org.springframework.boot.actuate.health.HealthComponent;
import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthEndpoint;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,12 +17,12 @@
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet; package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.EndpointCloudFoundryExtension; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.EndpointCloudFoundryExtension;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.HealthComponent; import org.springframework.boot.actuate.health.HealthComponent;
import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthEndpoint;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.health.CompositeHealth; import org.springframework.boot.actuate.health.CompositeHealth;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthComponent; import org.springframework.boot.actuate.health.HealthComponent;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,10 +37,10 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoC
import org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.WebOperation;
@ -80,6 +80,10 @@ import static org.mockito.Mockito.mock;
*/ */
class ReactiveCloudFoundryActuatorAutoConfigurationTests { class ReactiveCloudFoundryActuatorAutoConfigurationTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class,
ReactiveUserDetailsServiceAutoConfiguration.class, WebFluxAutoConfiguration.class, ReactiveUserDetailsServiceAutoConfiguration.class, WebFluxAutoConfiguration.class,
@ -120,7 +124,7 @@ class ReactiveCloudFoundryActuatorAutoConfigurationTests {
"vcap.application.cf_api:https://my-cloud-controller.com").run((context) -> { "vcap.application.cf_api:https://my-cloud-controller.com").run((context) -> {
WebTestClient webTestClient = WebTestClient.bindToApplicationContext(context).build(); WebTestClient webTestClient = WebTestClient.bindToApplicationContext(context).build();
webTestClient.get().uri("/cloudfoundryapplication").header("Content-Type", webTestClient.get().uri("/cloudfoundryapplication").header("Content-Type",
ActuatorMediaType.V2_JSON + ";charset=UTF-8"); V2_JSON + ";charset=UTF-8");
}); });
} }
@ -301,8 +305,7 @@ class ReactiveCloudFoundryActuatorAutoConfigurationTests {
private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) { private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) {
for (WebOperation operation : endpoint.getOperations()) { for (WebOperation operation : endpoint.getOperations()) {
WebOperationRequestPredicate predicate = operation.getRequestPredicate(); WebOperationRequestPredicate predicate = operation.getRequestPredicate();
if (predicate.getPath().equals(requestPath) if (predicate.getPath().equals(requestPath) && predicate.getProduces().contains(V3_JSON)) {
&& predicate.getProduces().contains(ActuatorMediaType.V3_JSON)) {
return operation; return operation;
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,10 +27,10 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAu
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.WebOperation;
@ -67,6 +67,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/ */
class CloudFoundryActuatorAutoConfigurationTests { class CloudFoundryActuatorAutoConfigurationTests {
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class, WebMvcAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class, WebMvcAutoConfiguration.class,
JacksonAutoConfiguration.class, DispatcherServletAutoConfiguration.class, JacksonAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
@ -99,7 +101,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
"vcap.application.cf_api:https://my-cloud-controller.com").run((context) -> { "vcap.application.cf_api:https://my-cloud-controller.com").run((context) -> {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
mockMvc.perform(get("/cloudfoundryapplication")) mockMvc.perform(get("/cloudfoundryapplication"))
.andExpect(header().string("Content-Type", ActuatorMediaType.V3_JSON)); .andExpect(header().string("Content-Type", V3_JSON));
}); });
} }
@ -244,8 +246,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) { private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) {
for (WebOperation operation : endpoint.getOperations()) { for (WebOperation operation : endpoint.getOperations()) {
WebOperationRequestPredicate predicate = operation.getRequestPredicate(); WebOperationRequestPredicate predicate = operation.getRequestPredicate();
if (predicate.getPath().equals(requestPath) if (predicate.getPath().equals(requestPath) && predicate.getProduces().contains(V3_JSON)) {
&& predicate.getProduces().contains(ActuatorMediaType.V3_JSON)) {
return operation; return operation;
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,7 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAu
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.health.CompositeHealth; import org.springframework.boot.actuate.health.CompositeHealth;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthComponent; import org.springframework.boot.actuate.health.HealthComponent;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,9 +25,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter; import org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint; import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
@ -51,6 +51,10 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class WebEndpointAutoConfigurationTests { class WebEndpointAutoConfigurationTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
private static final AutoConfigurations CONFIGURATIONS = AutoConfigurations.of(EndpointAutoConfiguration.class, private static final AutoConfigurations CONFIGURATIONS = AutoConfigurations.of(EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class); WebEndpointAutoConfiguration.class);
@ -61,8 +65,7 @@ class WebEndpointAutoConfigurationTests {
void webApplicationConfiguresEndpointMediaTypes() { void webApplicationConfiguresEndpointMediaTypes() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
EndpointMediaTypes endpointMediaTypes = context.getBean(EndpointMediaTypes.class); EndpointMediaTypes endpointMediaTypes = context.getBean(EndpointMediaTypes.class);
assertThat(endpointMediaTypes.getConsumed()).containsExactly(ActuatorMediaType.V3_JSON, assertThat(endpointMediaTypes.getConsumed()).containsExactly(V3_JSON, V2_JSON, "application/json");
ActuatorMediaType.V2_JSON, "application/json");
}); });
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,8 +22,8 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry; import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry; import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry;

@ -0,0 +1,57 @@
/*
* Copyright 2012-2021 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
/**
* API versions supported for the actuator API. This enum may be injected into actuator
* endpoints in order to return a response compatible with the requested version.
*
* @author Phillip Webb
* @since 2.4.0
*/
public enum ApiVersion implements Producible<ApiVersion> {
/**
* Version 2 (supported by Spring Boot 2.0+).
*/
V2("application/vnd.spring-boot.actuator.v2+json"),
/**
* Version 3 (supported by Spring Boot 2.2+).
*/
V3("application/vnd.spring-boot.actuator.v3+json");
/**
* The latest API version.
*/
public static final ApiVersion LATEST = ApiVersion.V3;
private final MimeType mimeType;
ApiVersion(String mimeType) {
this.mimeType = MimeTypeUtils.parseMimeType(mimeType);
}
@Override
public MimeType getProducedMimeType() {
return this.mimeType;
}
}

@ -22,7 +22,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -60,8 +59,10 @@ public class InvocationContext {
* {@link #InvocationContext(SecurityContext, Map, OperationArgumentResolver[])} * {@link #InvocationContext(SecurityContext, Map, OperationArgumentResolver[])}
*/ */
@Deprecated @Deprecated
public InvocationContext(ApiVersion apiVersion, SecurityContext securityContext, Map<String, Object> arguments) { public InvocationContext(org.springframework.boot.actuate.endpoint.http.ApiVersion apiVersion,
this(securityContext, arguments, OperationArgumentResolver.of(ApiVersion.class, () -> apiVersion)); SecurityContext securityContext, Map<String, Object> arguments) {
this(securityContext, arguments, OperationArgumentResolver.of(ApiVersion.class,
() -> (apiVersion != null) ? ApiVersion.valueOf(apiVersion.name()) : null));
} }
/** /**
@ -90,9 +91,16 @@ public class InvocationContext {
* Return the API version in use. * Return the API version in use.
* @return the apiVersion the API version * @return the apiVersion the API version
* @since 2.2.0 * @since 2.2.0
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of
* {@link #resolveArgument(Class)} using
* {@link org.springframework.boot.actuate.endpoint.ApiVersion}
*/ */
public ApiVersion getApiVersion() { @Deprecated
return resolveArgument(ApiVersion.class); public org.springframework.boot.actuate.endpoint.http.ApiVersion getApiVersion() {
ApiVersion version = resolveArgument(ApiVersion.class);
System.out.println(version);
return (version != null) ? org.springframework.boot.actuate.endpoint.http.ApiVersion.valueOf(version.name())
: org.springframework.boot.actuate.endpoint.http.ApiVersion.LATEST;
} }
/** /**

@ -14,8 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.endpoint.annotation; package org.springframework.boot.actuate.endpoint;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
/** /**

@ -14,15 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.endpoint.http; package org.springframework.boot.actuate.endpoint;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.function.Supplier;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.annotation.Producible;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;
@ -35,10 +33,14 @@ import org.springframework.util.MimeTypeUtils;
*/ */
public class ProducibleOperationArgumentResolver implements OperationArgumentResolver { public class ProducibleOperationArgumentResolver implements OperationArgumentResolver {
private final Map<String, List<String>> headers; private final Supplier<List<String>> accepts;
public ProducibleOperationArgumentResolver(Map<String, List<String>> headers) { /**
this.headers = headers; * Create a new {@link ProducibleOperationArgumentResolver} instance.
* @param accepts supplier that returns accepted mime types
*/
public ProducibleOperationArgumentResolver(Supplier<List<String>> accepts) {
this.accepts = accepts;
} }
@Override @Override
@ -53,7 +55,7 @@ public class ProducibleOperationArgumentResolver implements OperationArgumentRes
} }
private Enum<? extends Producible<?>> resolveProducible(Class<Enum<? extends Producible<?>>> type) { private Enum<? extends Producible<?>> resolveProducible(Class<Enum<? extends Producible<?>>> type) {
List<String> accepts = this.headers.get("Accept"); List<String> accepts = this.accepts.get();
List<Enum<? extends Producible<?>>> values = Arrays.asList(type.getEnumConstants()); List<Enum<? extends Producible<?>>> values = Arrays.asList(type.getEnumConstants());
Collections.reverse(values); Collections.reverse(values);
if (CollectionUtils.isEmpty(accepts)) { if (CollectionUtils.isEmpty(accepts)) {

@ -22,6 +22,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.Producible;
/** /**
* Identifies a method on an {@link Endpoint @Endpoint} as being a delete operation. * Identifies a method on an {@link Endpoint @Endpoint} as being a delete operation.
* *

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.Producible;
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod; import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.Assert; import org.springframework.util.Assert;

@ -22,6 +22,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.Producible;
/** /**
* Identifies a method on an {@link Endpoint @Endpoint} as being a read operation. * Identifies a method on an {@link Endpoint @Endpoint} as being a read operation.
* *

@ -22,6 +22,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.Producible;
/** /**
* Identifies a method on an {@link Endpoint @Endpoint} as being a write operation. * Identifies a method on an {@link Endpoint @Endpoint} as being a write operation.
* *

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,10 @@ package org.springframework.boot.actuate.endpoint.http;
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Madhura Bhave * @author Madhura Bhave
* @since 2.0.0 * @since 2.0.0
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of
* {@link org.springframework.boot.actuate.endpoint.ApiVersion#getProducedMimeType()}
*/ */
@Deprecated
public final class ActuatorMediaType { public final class ActuatorMediaType {
/** /**

@ -19,9 +19,8 @@ package org.springframework.boot.actuate.endpoint.http;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.boot.actuate.endpoint.annotation.Producible; import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;
/** /**
@ -30,18 +29,21 @@ import org.springframework.util.MimeTypeUtils;
* *
* @author Phillip Webb * @author Phillip Webb
* @since 2.2.0 * @since 2.2.0
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of
* {@link org.springframework.boot.actuate.endpoint.ApiVersion}
*/ */
public enum ApiVersion implements Producible<ApiVersion> { @Deprecated
public enum ApiVersion {
/** /**
* Version 2 (supported by Spring Boot 2.0+). * Version 2 (supported by Spring Boot 2.0+).
*/ */
V2(ActuatorMediaType.V2_JSON), V2,
/** /**
* Version 3 (supported by Spring Boot 2.2+). * Version 3 (supported by Spring Boot 2.2+).
*/ */
V3(ActuatorMediaType.V3_JSON); V3;
private static final String MEDIA_TYPE_PREFIX = "application/vnd.spring-boot.actuator."; private static final String MEDIA_TYPE_PREFIX = "application/vnd.spring-boot.actuator.";
@ -50,17 +52,6 @@ public enum ApiVersion implements Producible<ApiVersion> {
*/ */
public static final ApiVersion LATEST = ApiVersion.V3; public static final ApiVersion LATEST = ApiVersion.V3;
private final MimeType mimeType;
ApiVersion(String mimeType) {
this.mimeType = MimeTypeUtils.parseMimeType(mimeType);
}
@Override
public MimeType getProducedMimeType() {
return this.mimeType;
}
/** /**
* Return the {@link ApiVersion} to use based on the HTTP request headers. The version * Return the {@link ApiVersion} to use based on the HTTP request headers. The version
* will be deduced based on the {@code Accept} header. * will be deduced based on the {@code Accept} header.

@ -25,8 +25,8 @@ import java.util.concurrent.ConcurrentHashMap;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -78,7 +78,7 @@ public class CachingOperationInvoker implements OperationInvoker {
return this.invoker.invoke(context); return this.invoker.invoke(context);
} }
long accessTime = System.currentTimeMillis(); long accessTime = System.currentTimeMillis();
ApiVersion contextApiVersion = context.getApiVersion(); ApiVersion contextApiVersion = context.resolveArgument(ApiVersion.class);
Principal principal = context.resolveArgument(Principal.class); Principal principal = context.resolveArgument(Principal.class);
CacheKey cacheKey = new CacheKey(contextApiVersion, principal); CacheKey cacheKey = new CacheKey(contextApiVersion, principal);
CachedResponse cached = this.cachedResponses.get(cacheKey); CachedResponse cached = this.cachedResponses.get(cacheKey);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,10 +18,10 @@ package org.springframework.boot.actuate.endpoint.invoker.cache;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter; import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -31,13 +31,12 @@ import org.springframework.util.Assert;
*/ */
public class EndpointMediaTypes { public class EndpointMediaTypes {
private static final String JSON_MEDIA_TYPE = "application/json";
/** /**
* Default {@link EndpointMediaTypes} for this version of Spring Boot. * Default {@link EndpointMediaTypes} for this version of Spring Boot.
*/ */
public static final EndpointMediaTypes DEFAULT = new EndpointMediaTypes(ActuatorMediaType.V3_JSON, public static final EndpointMediaTypes DEFAULT = new EndpointMediaTypes(
ActuatorMediaType.V2_JSON, JSON_MEDIA_TYPE); ApiVersion.V3.getProducedMimeType().toString(), ApiVersion.V2.getProducedMimeType().toString(),
"application/json");
private final List<String> produced; private final List<String> produced;

@ -16,7 +16,7 @@
package org.springframework.boot.actuate.endpoint.web; package org.springframework.boot.actuate.endpoint.web;
import org.springframework.boot.actuate.endpoint.annotation.Producible; import org.springframework.boot.actuate.endpoint.Producible;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;

@ -42,8 +42,8 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException; import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@ -153,7 +153,7 @@ public class JerseyEndpointResourceFactory {
try { try {
JerseySecurityContext securityContext = new JerseySecurityContext(data.getSecurityContext()); JerseySecurityContext securityContext = new JerseySecurityContext(data.getSecurityContext());
InvocationContext invocationContext = new InvocationContext(securityContext, arguments, InvocationContext invocationContext = new InvocationContext(securityContext, arguments,
new ProducibleOperationArgumentResolver(data.getHeaders())); new ProducibleOperationArgumentResolver(() -> data.getHeaders().get("Accept")));
Object response = this.operation.invoke(invocationContext); Object response = this.operation.invoke(invocationContext);
return convertToJaxRsResponse(response, data.getRequest().getMethod()); return convertToJaxRsResponse(response, data.getRequest().getMethod());
} }

@ -32,8 +32,8 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException; import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@ -307,7 +307,8 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
} }
return this.securityContextSupplier.get() return this.securityContextSupplier.get()
.map((securityContext) -> new InvocationContext(securityContext, arguments, .map((securityContext) -> new InvocationContext(securityContext, arguments,
new ProducibleOperationArgumentResolver(exchange.getRequest().getHeaders()))) new ProducibleOperationArgumentResolver(
() -> exchange.getRequest().getHeaders().get("Accept"))))
.flatMap((invocationContext) -> handleResult((Publisher<?>) this.invoker.invoke(invocationContext), .flatMap((invocationContext) -> handleResult((Publisher<?>) this.invoker.invoke(invocationContext),
exchange.getRequest().getMethod())); exchange.getRequest().getMethod()));
} }

@ -32,8 +32,8 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException; import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@ -287,7 +287,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
try { try {
ServletSecurityContext securityContext = new ServletSecurityContext(request); ServletSecurityContext securityContext = new ServletSecurityContext(request);
InvocationContext invocationContext = new InvocationContext(securityContext, arguments, InvocationContext invocationContext = new InvocationContext(securityContext, arguments,
new ProducibleOperationArgumentResolver(headers)); new ProducibleOperationArgumentResolver(() -> headers.get("Accept")));
return handleResult(this.operation.invoke(invocationContext), HttpMethod.resolve(request.getMethod())); return handleResult(this.operation.invoke(invocationContext), HttpMethod.resolve(request.getMethod()));
} }
catch (InvalidEndpointRequestException ex) { catch (InvalidEndpointRequestException ex) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,12 +19,12 @@ package org.springframework.boot.actuate.health;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
/** /**
* {@link Endpoint @Endpoint} to expose application health information. * {@link Endpoint @Endpoint} to expose application health information.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,8 +21,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,11 +20,11 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,11 +23,11 @@ import java.util.Set;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match; import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import java.util.TreeSet;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
/** /**
* A {@link HealthComponent} that represents the overall system health and the available * A {@link HealthComponent} that represents the overall system health and the available

@ -23,7 +23,7 @@ import java.util.Enumeration;
import io.prometheus.client.Collector.MetricFamilySamples; import io.prometheus.client.Collector.MetricFamilySamples;
import io.prometheus.client.exporter.common.TextFormat; import io.prometheus.client.exporter.common.TextFormat;
import org.springframework.boot.actuate.endpoint.annotation.Producible; import org.springframework.boot.actuate.endpoint.Producible;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;

@ -21,8 +21,6 @@ import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -42,13 +40,14 @@ class InvocationContextTests {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
void createWhenApiVersionIsNullUsesLatestVersion() { void createWhenApiVersionIsNullUsesLatestVersion() {
InvocationContext context = new InvocationContext(null, this.securityContext, this.arguments); InvocationContext context = new InvocationContext(null, this.securityContext, this.arguments);
assertThat(context.getApiVersion()).isEqualTo(ApiVersion.LATEST); assertThat(context.getApiVersion()).isEqualTo(org.springframework.boot.actuate.endpoint.http.ApiVersion.LATEST);
} }
@Test @Test
@Deprecated
void whenCreatedWithoutApiVersionThenGetApiVersionReturnsLatestVersion() { void whenCreatedWithoutApiVersionThenGetApiVersionReturnsLatestVersion() {
InvocationContext context = new InvocationContext(this.securityContext, this.arguments); InvocationContext context = new InvocationContext(this.securityContext, this.arguments);
assertThat(context.getApiVersion()).isEqualTo(ApiVersion.LATEST); assertThat(context.getApiVersion()).isEqualTo(org.springframework.boot.actuate.endpoint.http.ApiVersion.LATEST);
} }
@Test @Test
@ -72,8 +71,9 @@ class InvocationContextTests {
@Test @Test
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
void getApiVersionReturnsApiVersion() { void getApiVersionReturnsApiVersion() {
InvocationContext context = new InvocationContext(ApiVersion.V2, this.securityContext, this.arguments); InvocationContext context = new InvocationContext(org.springframework.boot.actuate.endpoint.http.ApiVersion.V2,
assertThat(context.getApiVersion()).isEqualTo(ApiVersion.V2); this.securityContext, this.arguments);
assertThat(context.getApiVersion()).isEqualTo(org.springframework.boot.actuate.endpoint.http.ApiVersion.V2);
} }
@Test @Test

@ -14,12 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.endpoint.http; package org.springframework.boot.actuate.endpoint;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.function.Supplier;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -32,6 +31,10 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class ProducibleOperationArgumentResolverTests { class ProducibleOperationArgumentResolverTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
@Test @Test
void whenAcceptHeaderIsEmptyThenHighestOrdinalIsReturned() { void whenAcceptHeaderIsEmptyThenHighestOrdinalIsReturned() {
assertThat(resolve(acceptHeader())).isEqualTo(ApiVersion.V3); assertThat(resolve(acceptHeader())).isEqualTo(ApiVersion.V3);
@ -49,31 +52,29 @@ class ProducibleOperationArgumentResolverTests {
@Test @Test
void whenSingleValueIsAcceptableThenMatchingEnumValueIsReturned() { void whenSingleValueIsAcceptableThenMatchingEnumValueIsReturned() {
assertThat(new ProducibleOperationArgumentResolver(acceptHeader(ActuatorMediaType.V2_JSON)) assertThat(new ProducibleOperationArgumentResolver(acceptHeader(V2_JSON)).resolve(ApiVersion.class))
.resolve(ApiVersion.class)).isEqualTo(ApiVersion.V2); .isEqualTo(ApiVersion.V2);
assertThat(new ProducibleOperationArgumentResolver(acceptHeader(ActuatorMediaType.V3_JSON)) assertThat(new ProducibleOperationArgumentResolver(acceptHeader(V3_JSON)).resolve(ApiVersion.class))
.resolve(ApiVersion.class)).isEqualTo(ApiVersion.V3); .isEqualTo(ApiVersion.V3);
} }
@Test @Test
void whenMultipleValuesAreAcceptableThenHighestOrdinalIsReturned() { void whenMultipleValuesAreAcceptableThenHighestOrdinalIsReturned() {
assertThat(resolve(acceptHeader(ActuatorMediaType.V2_JSON, ActuatorMediaType.V3_JSON))) assertThat(resolve(acceptHeader(V2_JSON, V3_JSON))).isEqualTo(ApiVersion.V3);
.isEqualTo(ApiVersion.V3);
} }
@Test @Test
void whenMultipleValuesAreAcceptableAsSingleHeaderThenHighestOrdinalIsReturned() { void whenMultipleValuesAreAcceptableAsSingleHeaderThenHighestOrdinalIsReturned() {
assertThat(resolve(acceptHeader(ActuatorMediaType.V2_JSON + "," + ActuatorMediaType.V3_JSON))) assertThat(resolve(acceptHeader(V2_JSON + "," + V3_JSON))).isEqualTo(ApiVersion.V3);
.isEqualTo(ApiVersion.V3);
} }
private Map<String, List<String>> acceptHeader(String... types) { private Supplier<List<String>> acceptHeader(String... types) {
List<String> value = Arrays.asList(types); List<String> value = Arrays.asList(types);
return value.isEmpty() ? Collections.emptyMap() : Collections.singletonMap("Accept", value); return () -> (value.isEmpty() ? null : value);
} }
private ApiVersion resolve(Map<String, List<String>> httpHeaders) { private ApiVersion resolve(Supplier<List<String>> accepts) {
return new ProducibleOperationArgumentResolver(httpHeaders).resolve(ApiVersion.class); return new ProducibleOperationArgumentResolver(accepts).resolve(ApiVersion.class);
} }
} }

@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.Producible;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;

@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.Producible;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;

@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
@Deprecated
class ApiVersionTests { class ApiVersionTests {
@Test @Test

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,10 @@ import java.util.Collections;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.MissingParametersException; import org.springframework.boot.actuate.endpoint.invoke.MissingParametersException;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,10 +25,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod; import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;

@ -27,10 +27,10 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver; import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.invoke.MissingParametersException; import org.springframework.boot.actuate.endpoint.invoke.MissingParametersException;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.ApiVersion;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@ -34,12 +34,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
*/ */
class EndpointMediaTypesTests { class EndpointMediaTypesTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
@Test @Test
void defaultReturnsExpectedProducedAndConsumedTypes() { void defaultReturnsExpectedProducedAndConsumedTypes() {
assertThat(EndpointMediaTypes.DEFAULT.getProduced()).containsExactly(ActuatorMediaType.V3_JSON, assertThat(EndpointMediaTypes.DEFAULT.getProduced()).containsExactly(V3_JSON, V2_JSON, "application/json");
ActuatorMediaType.V2_JSON, "application/json"); assertThat(EndpointMediaTypes.DEFAULT.getConsumed()).containsExactly(V3_JSON, V2_JSON, "application/json");
assertThat(EndpointMediaTypes.DEFAULT.getConsumed()).containsExactly(ActuatorMediaType.V3_JSON,
ActuatorMediaType.V2_JSON, "application/json");
} }
@Test @Test

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,8 +22,8 @@ import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult; import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,8 +21,8 @@ import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult; import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import java.util.Map;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest; import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
@ -45,6 +45,10 @@ import org.springframework.util.ReflectionUtils;
*/ */
class HealthEndpointWebIntegrationTests { class HealthEndpointWebIntegrationTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
@WebEndpointTest @WebEndpointTest
void whenHealthIsUp200ResponseIsReturned(WebTestClient client) { void whenHealthIsUp200ResponseIsReturned(WebTestClient client) {
client.get().uri("/actuator/health").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk() client.get().uri("/actuator/health").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk()
@ -54,8 +58,7 @@ class HealthEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void whenHealthIsUpAndAcceptsV3Request200ResponseIsReturned(WebTestClient client) { void whenHealthIsUpAndAcceptsV3Request200ResponseIsReturned(WebTestClient client) {
client.get().uri("/actuator/health") client.get().uri("/actuator/health").headers((headers) -> headers.set(HttpHeaders.ACCEPT, V3_JSON)).exchange()
.headers((headers) -> headers.set(HttpHeaders.ACCEPT, ActuatorMediaType.V3_JSON)).exchange()
.expectStatus().isOk().expectBody().jsonPath("status").isEqualTo("UP") .expectStatus().isOk().expectBody().jsonPath("status").isEqualTo("UP")
.jsonPath("components.alpha.status").isEqualTo("UP").jsonPath("components.bravo.status") .jsonPath("components.alpha.status").isEqualTo("UP").jsonPath("components.bravo.status")
.isEqualTo("UP"); .isEqualTo("UP");
@ -71,8 +74,7 @@ class HealthEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void whenHealthIsUpAndV2Request200ResponseIsReturnedInV2Format(WebTestClient client) { void whenHealthIsUpAndV2Request200ResponseIsReturnedInV2Format(WebTestClient client) {
client.get().uri("/actuator/health") client.get().uri("/actuator/health").headers((headers) -> headers.set(HttpHeaders.ACCEPT, V2_JSON)).exchange()
.headers((headers) -> headers.set(HttpHeaders.ACCEPT, ActuatorMediaType.V2_JSON)).exchange()
.expectStatus().isOk().expectBody().jsonPath("status").isEqualTo("UP").jsonPath("details.alpha.status") .expectStatus().isOk().expectBody().jsonPath("status").isEqualTo("UP").jsonPath("details.alpha.status")
.isEqualTo("UP").jsonPath("details.bravo.status").isEqualTo("UP"); .isEqualTo("UP").jsonPath("details.bravo.status").isEqualTo("UP");
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,8 +22,8 @@ import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult; import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,7 @@ import java.util.Set;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.http.ApiVersion; import org.springframework.boot.actuate.endpoint.ApiVersion;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,7 +30,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest; import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration; import org.springframework.boot.logging.LoggerConfiguration;
@ -61,6 +61,10 @@ import static org.mockito.Mockito.verifyNoInteractions;
*/ */
class LoggersEndpointWebIntegrationTests { class LoggersEndpointWebIntegrationTests {
private static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();
private static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();
private WebTestClient client; private WebTestClient client;
private LoggingSystem loggingSystem; private LoggingSystem loggingSystem;
@ -125,8 +129,7 @@ class LoggersEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void setLoggerUsingActuatorV2JsonShouldSetLogLevel() { void setLoggerUsingActuatorV2JsonShouldSetLogLevel() {
this.client.post().uri("/actuator/loggers/ROOT") this.client.post().uri("/actuator/loggers/ROOT").contentType(MediaType.parseMediaType(V2_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V2_JSON))
.bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus() .bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus()
.isNoContent(); .isNoContent();
verify(this.loggingSystem).setLogLevel("ROOT", LogLevel.DEBUG); verify(this.loggingSystem).setLogLevel("ROOT", LogLevel.DEBUG);
@ -134,8 +137,7 @@ class LoggersEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void setLoggerUsingActuatorV3JsonShouldSetLogLevel() { void setLoggerUsingActuatorV3JsonShouldSetLogLevel() {
this.client.post().uri("/actuator/loggers/ROOT") this.client.post().uri("/actuator/loggers/ROOT").contentType(MediaType.parseMediaType(V3_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V3_JSON))
.bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus() .bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus()
.isNoContent(); .isNoContent();
verify(this.loggingSystem).setLogLevel("ROOT", LogLevel.DEBUG); verify(this.loggingSystem).setLogLevel("ROOT", LogLevel.DEBUG);
@ -143,8 +145,7 @@ class LoggersEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void setLoggerGroupUsingActuatorV2JsonShouldSetLogLevel() { void setLoggerGroupUsingActuatorV2JsonShouldSetLogLevel() {
this.client.post().uri("/actuator/loggers/test") this.client.post().uri("/actuator/loggers/test").contentType(MediaType.parseMediaType(V2_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V2_JSON))
.bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus() .bodyValue(Collections.singletonMap("configuredLevel", "debug")).exchange().expectStatus()
.isNoContent(); .isNoContent();
verify(this.loggingSystem).setLogLevel("test.member1", LogLevel.DEBUG); verify(this.loggingSystem).setLogLevel("test.member1", LogLevel.DEBUG);
@ -170,24 +171,21 @@ class LoggersEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void setLoggerWithNullLogLevel() { void setLoggerWithNullLogLevel() {
this.client.post().uri("/actuator/loggers/ROOT") this.client.post().uri("/actuator/loggers/ROOT").contentType(MediaType.parseMediaType(V3_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V3_JSON))
.bodyValue(Collections.singletonMap("configuredLevel", null)).exchange().expectStatus().isNoContent(); .bodyValue(Collections.singletonMap("configuredLevel", null)).exchange().expectStatus().isNoContent();
verify(this.loggingSystem).setLogLevel("ROOT", null); verify(this.loggingSystem).setLogLevel("ROOT", null);
} }
@WebEndpointTest @WebEndpointTest
void setLoggerWithNoLogLevel() { void setLoggerWithNoLogLevel() {
this.client.post().uri("/actuator/loggers/ROOT") this.client.post().uri("/actuator/loggers/ROOT").contentType(MediaType.parseMediaType(V3_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V3_JSON)).bodyValue(Collections.emptyMap()) .bodyValue(Collections.emptyMap()).exchange().expectStatus().isNoContent();
.exchange().expectStatus().isNoContent();
verify(this.loggingSystem).setLogLevel("ROOT", null); verify(this.loggingSystem).setLogLevel("ROOT", null);
} }
@WebEndpointTest @WebEndpointTest
void setLoggerGroupWithNullLogLevel() { void setLoggerGroupWithNullLogLevel() {
this.client.post().uri("/actuator/loggers/test") this.client.post().uri("/actuator/loggers/test").contentType(MediaType.parseMediaType(V3_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V3_JSON))
.bodyValue(Collections.singletonMap("configuredLevel", null)).exchange().expectStatus().isNoContent(); .bodyValue(Collections.singletonMap("configuredLevel", null)).exchange().expectStatus().isNoContent();
verify(this.loggingSystem).setLogLevel("test.member1", null); verify(this.loggingSystem).setLogLevel("test.member1", null);
verify(this.loggingSystem).setLogLevel("test.member2", null); verify(this.loggingSystem).setLogLevel("test.member2", null);
@ -195,9 +193,8 @@ class LoggersEndpointWebIntegrationTests {
@WebEndpointTest @WebEndpointTest
void setLoggerGroupWithNoLogLevel() { void setLoggerGroupWithNoLogLevel() {
this.client.post().uri("/actuator/loggers/test") this.client.post().uri("/actuator/loggers/test").contentType(MediaType.parseMediaType(V3_JSON))
.contentType(MediaType.parseMediaType(ActuatorMediaType.V3_JSON)).bodyValue(Collections.emptyMap()) .bodyValue(Collections.emptyMap()).exchange().expectStatus().isNoContent();
.exchange().expectStatus().isNoContent();
verify(this.loggingSystem).setLogLevel("test.member1", null); verify(this.loggingSystem).setLogLevel("test.member1", null);
verify(this.loggingSystem).setLogLevel("test.member2", null); verify(this.loggingSystem).setLogLevel("test.member2", null);
} }

Loading…
Cancel
Save