Remove deprecated code that was to be removed in 3.2

Closes gh-36034
pull/36062/head
Andy Wilkinson 1 year ago
parent 50d8b20d6c
commit b645eb32ac

@ -16,12 +16,9 @@
package org.springframework.boot.actuate.autoconfigure.health; package org.springframework.boot.actuate.autoconfigure.health;
import java.lang.reflect.Constructor;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ResolvableType;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -39,18 +36,6 @@ public abstract class AbstractCompositeHealthContributorConfiguration<C, I exten
private final Function<B, I> indicatorFactory; private final Function<B, I> indicatorFactory;
/**
* Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use
* reflection to create health indicator instances.
* @deprecated since 3.0.0 in favor of
* {@link #AbstractCompositeHealthContributorConfiguration(Function)}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
protected AbstractCompositeHealthContributorConfiguration() {
this.indicatorFactory = new ReflectionIndicatorFactory(
ResolvableType.forClass(AbstractCompositeHealthContributorConfiguration.class, getClass()));
}
/** /**
* Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use the * Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use the
* given {@code indicatorFactory} to create health indicator instances. * given {@code indicatorFactory} to create health indicator instances.
@ -75,34 +60,4 @@ public abstract class AbstractCompositeHealthContributorConfiguration<C, I exten
return this.indicatorFactory.apply(bean); return this.indicatorFactory.apply(bean);
} }
private class ReflectionIndicatorFactory implements Function<B, I> {
private final Class<?> indicatorType;
private final Class<?> beanType;
ReflectionIndicatorFactory(ResolvableType type) {
this.indicatorType = type.resolveGeneric(1);
this.beanType = type.resolveGeneric(2);
}
@Override
public I apply(B bean) {
try {
return BeanUtils.instantiateClass(getConstructor(), bean);
}
catch (Exception ex) {
throw new IllegalStateException("Unable to create health indicator %s for bean type %s"
.formatted(this.indicatorType, this.beanType), ex);
}
}
@SuppressWarnings("unchecked")
private Constructor<I> getConstructor() throws NoSuchMethodException {
return (Constructor<I>) this.indicatorType.getDeclaredConstructor(this.beanType);
}
}
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 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.
@ -36,18 +36,6 @@ import org.springframework.boot.actuate.health.HealthIndicator;
public abstract class CompositeHealthContributorConfiguration<I extends HealthIndicator, B> public abstract class CompositeHealthContributorConfiguration<I extends HealthIndicator, B>
extends AbstractCompositeHealthContributorConfiguration<HealthContributor, I, B> { extends AbstractCompositeHealthContributorConfiguration<HealthContributor, I, B> {
/**
* Creates a {@code CompositeHealthContributorConfiguration} that will use reflection
* to create {@link HealthIndicator} instances.
* @deprecated since 3.0.0 in favor of
* {@link #CompositeHealthContributorConfiguration(Function)}
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
public CompositeHealthContributorConfiguration() {
super();
}
/** /**
* Creates a {@code CompositeHealthContributorConfiguration} that will use the given * Creates a {@code CompositeHealthContributorConfiguration} that will use the given
* {@code indicatorFactory} to create {@link HealthIndicator} instances. * {@code indicatorFactory} to create {@link HealthIndicator} instances.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 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.
@ -36,18 +36,6 @@ import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
public abstract class CompositeReactiveHealthContributorConfiguration<I extends ReactiveHealthIndicator, B> public abstract class CompositeReactiveHealthContributorConfiguration<I extends ReactiveHealthIndicator, B>
extends AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, I, B> { extends AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, I, B> {
/**
* Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use
* reflection to create {@link ReactiveHealthIndicator} instances.
* @deprecated since 3.0.0 in favor of
* {@link #CompositeReactiveHealthContributorConfiguration(Function)}
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
public CompositeReactiveHealthContributorConfiguration() {
super();
}
/** /**
* Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use the * Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use the
* given {@code indicatorFactory} to create {@link ReactiveHealthIndicator} instances. * given {@code indicatorFactory} to create {@link ReactiveHealthIndicator} instances.

@ -116,8 +116,6 @@ public class MetricsProperties {
public static class Client { public static class Client {
private final ClientRequest request = new ClientRequest();
/** /**
* Maximum number of unique URI tag values allowed. After the max number of * Maximum number of unique URI tag values allowed. After the max number of
* tag values is reached, metrics with additional tag values are denied by * tag values is reached, metrics with additional tag values are denied by
@ -125,10 +123,6 @@ public class MetricsProperties {
*/ */
private int maxUriTags = 100; private int maxUriTags = 100;
public ClientRequest getRequest() {
return this.request;
}
public int getMaxUriTags() { public int getMaxUriTags() {
return this.maxUriTags; return this.maxUriTags;
} }
@ -137,32 +131,10 @@ public class MetricsProperties {
this.maxUriTags = maxUriTags; this.maxUriTags = maxUriTags;
} }
public static class ClientRequest {
/**
* Name of the metric for sent requests.
*/
private String metricName = "http.client.requests";
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(replacement = "management.observations.http.client.requests.name")
public String getMetricName() {
return this.metricName;
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setMetricName(String metricName) {
this.metricName = metricName;
}
}
} }
public static class Server { public static class Server {
private final ServerRequest request = new ServerRequest();
/** /**
* Maximum number of unique URI tag values allowed. After the max number of * Maximum number of unique URI tag values allowed. After the max number of
* tag values is reached, metrics with additional tag values are denied by * tag values is reached, metrics with additional tag values are denied by
@ -170,10 +142,6 @@ public class MetricsProperties {
*/ */
private int maxUriTags = 100; private int maxUriTags = 100;
public ServerRequest getRequest() {
return this.request;
}
public int getMaxUriTags() { public int getMaxUriTags() {
return this.maxUriTags; return this.maxUriTags;
} }
@ -182,27 +150,6 @@ public class MetricsProperties {
this.maxUriTags = maxUriTags; this.maxUriTags = maxUriTags;
} }
public static class ServerRequest {
/**
* Name of the metric for received requests.
*/
private String metricName = "http.server.requests";
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(replacement = "management.observations.http.server.requests.name")
public String getMetricName() {
return this.metricName;
}
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(replacement = "management.observations.http.server.requests.name")
public void setMetricName(String metricName) {
this.metricName = metricName;
}
}
} }
} }

@ -29,9 +29,9 @@ import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Web.Server;
import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -57,13 +57,12 @@ import org.springframework.core.annotation.Order;
@ConditionalOnClass({ ResourceConfig.class, MetricsApplicationEventListener.class }) @ConditionalOnClass({ ResourceConfig.class, MetricsApplicationEventListener.class })
@ConditionalOnBean({ MeterRegistry.class, ResourceConfig.class }) @ConditionalOnBean({ MeterRegistry.class, ResourceConfig.class })
@EnableConfigurationProperties(MetricsProperties.class) @EnableConfigurationProperties(MetricsProperties.class)
@SuppressWarnings("removal")
public class JerseyServerMetricsAutoConfiguration { public class JerseyServerMetricsAutoConfiguration {
private final MetricsProperties properties; private final ObservationProperties observationProperties;
public JerseyServerMetricsAutoConfiguration(MetricsProperties properties) { public JerseyServerMetricsAutoConfiguration(ObservationProperties observationProperties) {
this.properties = properties; this.observationProperties = observationProperties;
} }
@Bean @Bean
@ -75,19 +74,19 @@ public class JerseyServerMetricsAutoConfiguration {
@Bean @Bean
public ResourceConfigCustomizer jerseyServerMetricsResourceConfigCustomizer(MeterRegistry meterRegistry, public ResourceConfigCustomizer jerseyServerMetricsResourceConfigCustomizer(MeterRegistry meterRegistry,
JerseyTagsProvider tagsProvider) { JerseyTagsProvider tagsProvider) {
Server server = this.properties.getWeb().getServer(); String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry, tagsProvider, return (config) -> config.register(new MetricsApplicationEventListener(meterRegistry, tagsProvider, metricName,
server.getRequest().getMetricName(), true, new AnnotationUtilsAnnotationFinder())); true, new AnnotationUtilsAnnotationFinder()));
} }
@Bean @Bean
@Order(0) @Order(0)
public MeterFilter jerseyMetricsUriTagFilter() { public MeterFilter jerseyMetricsUriTagFilter(MetricsProperties metricsProperties) {
String metricName = this.properties.getWeb().getServer().getRequest().getMetricName(); String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> String.format("Reached the maximum number of URI tags for '%s'.", metricName)); () -> String.format("Reached the maximum number of URI tags for '%s'.", metricName));
return MeterFilter.maximumAllowableTags(metricName, "uri", this.properties.getWeb().getServer().getMaxUriTags(), return MeterFilter.maximumAllowableTags(metricName, "uri",
filter); metricsProperties.getWeb().getServer().getMaxUriTags(), filter);
} }
/** /**

@ -91,10 +91,9 @@ public class ObservationProperties {
public static class ClientRequests { public static class ClientRequests {
/** /**
* Name of the observation for client requests. If empty, will use the * Name of the observation for client requests.
* default "http.client.requests".
*/ */
private String name; private String name = "http.client.requests";
public String getName() { public String getName() {
return this.name; return this.name;
@ -125,10 +124,9 @@ public class ObservationProperties {
public static class ServerRequests { public static class ServerRequests {
/** /**
* Name of the observation for server requests. If empty, will use the * Name of the observation for server requests.
* default "http.server.requests".
*/ */
private String name; private String name = "http.server.requests";
public String getName() { public String getName() {
return this.name; return this.name;

@ -43,7 +43,6 @@ import org.springframework.graphql.observation.GraphQlObservationInstrumentation
@AutoConfiguration(after = ObservationAutoConfiguration.class) @AutoConfiguration(after = ObservationAutoConfiguration.class)
@ConditionalOnBean(ObservationRegistry.class) @ConditionalOnBean(ObservationRegistry.class)
@ConditionalOnClass({ GraphQL.class, GraphQlSource.class, Observation.class }) @ConditionalOnClass({ GraphQL.class, GraphQlSource.class, Observation.class })
@SuppressWarnings("removal")
public class GraphQlObservationAutoConfiguration { public class GraphQlObservationAutoConfiguration {
@Bean @Bean

@ -1,62 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.client;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider;
import org.springframework.http.client.observation.ClientRequestObservationContext;
import org.springframework.http.client.observation.ClientRequestObservationConvention;
/**
* Adapter class that applies {@link RestTemplateExchangeTagsProvider} tags as a
* {@link ClientRequestObservationConvention}.
*
* @author Brian Clozel
*/
@SuppressWarnings({ "removal" })
class ClientHttpObservationConventionAdapter implements ClientRequestObservationConvention {
private final String metricName;
private final RestTemplateExchangeTagsProvider tagsProvider;
ClientHttpObservationConventionAdapter(String metricName, RestTemplateExchangeTagsProvider tagsProvider) {
this.metricName = metricName;
this.tagsProvider = tagsProvider;
}
@Override
@SuppressWarnings("deprecation")
public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {
Iterable<Tag> tags = this.tagsProvider.getTags(context.getUriTemplate(), context.getCarrier(),
context.getResponse());
return KeyValues.of(tags, Tag::getKey, Tag::getValue);
}
@Override
public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) {
return KeyValues.empty();
}
@Override
public String getName() {
return this.metricName;
}
}

@ -1,76 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.client;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import io.micrometer.observation.Observation;
import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider;
import org.springframework.core.Conventions;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientRequestObservationContext;
import org.springframework.web.reactive.function.client.ClientRequestObservationConvention;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Adapter class that applies {@link WebClientExchangeTagsProvider} tags as a
* {@link ClientRequestObservationConvention}.
*
* @author Brian Clozel
*/
@SuppressWarnings("removal")
class ClientObservationConventionAdapter implements ClientRequestObservationConvention {
private static final String URI_TEMPLATE_ATTRIBUTE = Conventions.getQualifiedAttributeName(WebClient.class,
"uriTemplate");
private final String metricName;
private final WebClientExchangeTagsProvider tagsProvider;
ClientObservationConventionAdapter(String metricName, WebClientExchangeTagsProvider tagsProvider) {
this.metricName = metricName;
this.tagsProvider = tagsProvider;
}
@Override
public boolean supportsContext(Observation.Context context) {
return context instanceof ClientRequestObservationContext;
}
@Override
public KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {
ClientRequest request = context.getRequest();
if (request == null) {
request = context.getCarrier().attribute(URI_TEMPLATE_ATTRIBUTE, context.getUriTemplate()).build();
}
Iterable<Tag> tags = this.tagsProvider.tags(request, context.getResponse(), context.getError());
return KeyValues.of(tags, Tag::getKey, Tag::getValue);
}
@Override
public KeyValues getHighCardinalityKeyValues(ClientRequestObservationContext context) {
return KeyValues.empty();
}
@Override
public String getName() {
return this.metricName;
}
}

@ -65,13 +65,10 @@ public class HttpClientObservationsAutoConfiguration {
@Bean @Bean
@Order(0) @Order(0)
@SuppressWarnings("removal")
MeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties, MeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties,
MetricsProperties metricsProperties) { MetricsProperties metricsProperties) {
Client clientProperties = metricsProperties.getWeb().getClient(); Client clientProperties = metricsProperties.getWeb().getClient();
String metricName = clientProperties.getRequest().getMetricName(); String name = observationProperties.getHttp().getClient().getRequests().getName();
String observationName = observationProperties.getHttp().getClient().getRequests().getName();
String name = (observationName != null) ? observationName : metricName;
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(
() -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?" () -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?"
.formatted(name)); .formatted(name));

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 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,6 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
import org.springframework.boot.actuate.metrics.web.client.ObservationRestTemplateCustomizer; import org.springframework.boot.actuate.metrics.web.client.ObservationRestTemplateCustomizer;
import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateBuilder;
@ -40,39 +39,16 @@ import org.springframework.web.client.RestTemplate;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class) @ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(RestTemplateBuilder.class) @ConditionalOnBean(RestTemplateBuilder.class)
@SuppressWarnings("removal")
class RestTemplateObservationConfiguration { class RestTemplateObservationConfiguration {
@Bean @Bean
ObservationRestTemplateCustomizer observationRestTemplateCustomizer(ObservationRegistry observationRegistry, ObservationRestTemplateCustomizer observationRestTemplateCustomizer(ObservationRegistry observationRegistry,
ObjectProvider<ClientRequestObservationConvention> customConvention, ObjectProvider<ClientRequestObservationConvention> customConvention,
ObservationProperties observationProperties, MetricsProperties metricsProperties, ObservationProperties observationProperties, MetricsProperties metricsProperties) {
ObjectProvider<RestTemplateExchangeTagsProvider> optionalTagsProvider) { String name = observationProperties.getHttp().getClient().getRequests().getName();
String name = observationName(observationProperties, metricsProperties); ClientRequestObservationConvention observationConvention = customConvention
ClientRequestObservationConvention observationConvention = createConvention(customConvention.getIfAvailable(), .getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));
name, optionalTagsProvider.getIfAvailable());
return new ObservationRestTemplateCustomizer(observationRegistry, observationConvention); return new ObservationRestTemplateCustomizer(observationRegistry, observationConvention);
} }
private static String observationName(ObservationProperties observationProperties,
MetricsProperties metricsProperties) {
String metricName = metricsProperties.getWeb().getClient().getRequest().getMetricName();
String observationName = observationProperties.getHttp().getClient().getRequests().getName();
return (observationName != null) ? observationName : metricName;
}
private static ClientRequestObservationConvention createConvention(
ClientRequestObservationConvention customConvention, String name,
RestTemplateExchangeTagsProvider tagsProvider) {
if (customConvention != null) {
return customConvention;
}
else if (tagsProvider != null) {
return new ClientHttpObservationConventionAdapter(name, tagsProvider);
}
else {
return new DefaultClientRequestObservationConvention(name);
}
}
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 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,6 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
import org.springframework.boot.actuate.metrics.web.reactive.client.ObservationWebClientCustomizer; import org.springframework.boot.actuate.metrics.web.reactive.client.ObservationWebClientCustomizer;
import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -37,39 +36,16 @@ import org.springframework.web.reactive.function.client.WebClient;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebClient.class) @ConditionalOnClass(WebClient.class)
@SuppressWarnings("removal")
class WebClientObservationConfiguration { class WebClientObservationConfiguration {
@Bean @Bean
ObservationWebClientCustomizer observationWebClientCustomizer(ObservationRegistry observationRegistry, ObservationWebClientCustomizer observationWebClientCustomizer(ObservationRegistry observationRegistry,
ObjectProvider<ClientRequestObservationConvention> customConvention, ObjectProvider<ClientRequestObservationConvention> customConvention,
ObservationProperties observationProperties, ObjectProvider<WebClientExchangeTagsProvider> tagsProvider, ObservationProperties observationProperties, MetricsProperties metricsProperties) {
MetricsProperties metricsProperties) { String name = observationProperties.getHttp().getClient().getRequests().getName();
String name = observationName(observationProperties, metricsProperties); ClientRequestObservationConvention observationConvention = customConvention
ClientRequestObservationConvention observationConvention = createConvention(customConvention.getIfAvailable(), .getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));
tagsProvider.getIfAvailable(), name);
return new ObservationWebClientCustomizer(observationRegistry, observationConvention); return new ObservationWebClientCustomizer(observationRegistry, observationConvention);
} }
private static ClientRequestObservationConvention createConvention(
ClientRequestObservationConvention customConvention, WebClientExchangeTagsProvider tagsProvider,
String name) {
if (customConvention != null) {
return customConvention;
}
else if (tagsProvider != null) {
return new ClientObservationConventionAdapter(name, tagsProvider);
}
else {
return new DefaultClientRequestObservationConvention(name);
}
}
private static String observationName(ObservationProperties observationProperties,
MetricsProperties metricsProperties) {
String metricName = metricsProperties.getWeb().getClient().getRequest().getMetricName();
String observationName = observationProperties.getHttp().getClient().getRequests().getName();
return (observationName != null) ? observationName : metricName;
}
} }

@ -1,79 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.reactive;
import java.util.List;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;
import org.springframework.web.server.i18n.LocaleContextResolver;
import org.springframework.web.server.session.DefaultWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
/**
* Adapter class that applies {@link WebFluxTagsProvider} tags as a
* {@link ServerRequestObservationConvention}.
*
* @author Brian Clozel
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class ServerRequestObservationConventionAdapter implements ServerRequestObservationConvention {
private final WebSessionManager webSessionManager = new DefaultWebSessionManager();
private final ServerCodecConfigurer serverCodecConfigurer = ServerCodecConfigurer.create();
private final LocaleContextResolver localeContextResolver = new AcceptHeaderLocaleContextResolver();
private final String name;
private final WebFluxTagsProvider tagsProvider;
ServerRequestObservationConventionAdapter(String name, WebFluxTagsProvider tagsProvider) {
this.name = name;
this.tagsProvider = tagsProvider;
}
ServerRequestObservationConventionAdapter(String name, List<WebFluxTagsContributor> contributors) {
this(name, new DefaultWebFluxTagsProvider(contributors));
}
@Override
public String getName() {
return this.name;
}
@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
DefaultServerWebExchange serverWebExchange = new DefaultServerWebExchange(context.getCarrier(),
context.getResponse(), this.webSessionManager, this.serverCodecConfigurer, this.localeContextResolver);
serverWebExchange.getAttributes().putAll(context.getAttributes());
Iterable<Tag> tags = this.tagsProvider.httpRequestTags(serverWebExchange, context.getError());
return KeyValues.of(tags, Tag::getKey, Tag::getValue);
}
}

@ -16,8 +16,6 @@
package org.springframework.boot.actuate.autoconfigure.observation.web.reactive; package org.springframework.boot.actuate.autoconfigure.observation.web.reactive;
import java.util.List;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
@ -31,8 +29,6 @@ import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDen
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -66,48 +62,23 @@ import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
@SuppressWarnings("removal") @SuppressWarnings("removal")
public class WebFluxObservationAutoConfiguration { public class WebFluxObservationAutoConfiguration {
private final MetricsProperties metricsProperties;
private final ObservationProperties observationProperties; private final ObservationProperties observationProperties;
public WebFluxObservationAutoConfiguration(MetricsProperties metricsProperties, public WebFluxObservationAutoConfiguration(ObservationProperties observationProperties) {
ObservationProperties observationProperties) {
this.metricsProperties = metricsProperties;
this.observationProperties = observationProperties; this.observationProperties = observationProperties;
} }
@Bean @Bean
@ConditionalOnMissingBean(ServerHttpObservationFilter.class) @ConditionalOnMissingBean(ServerHttpObservationFilter.class)
public OrderedServerHttpObservationFilter webfluxObservationFilter(ObservationRegistry registry, public OrderedServerHttpObservationFilter webfluxObservationFilter(ObservationRegistry registry,
ObjectProvider<ServerRequestObservationConvention> customConvention, ObjectProvider<ServerRequestObservationConvention> customConvention) {
ObjectProvider<WebFluxTagsProvider> tagConfigurer, String name = this.observationProperties.getHttp().getServer().getRequests().getName();
ObjectProvider<WebFluxTagsContributor> contributorsProvider) { ServerRequestObservationConvention convention = customConvention
String observationName = this.observationProperties.getHttp().getServer().getRequests().getName(); .getIfAvailable(() -> new DefaultServerRequestObservationConvention(name));
String metricName = this.metricsProperties.getWeb().getServer().getRequest().getMetricName();
String name = (observationName != null) ? observationName : metricName;
WebFluxTagsProvider tagsProvider = tagConfigurer.getIfAvailable();
List<WebFluxTagsContributor> tagsContributors = contributorsProvider.orderedStream().toList();
ServerRequestObservationConvention convention = createConvention(customConvention.getIfAvailable(), name,
tagsProvider, tagsContributors);
int order = this.observationProperties.getHttp().getServer().getFilter().getOrder(); int order = this.observationProperties.getHttp().getServer().getFilter().getOrder();
return new OrderedServerHttpObservationFilter(registry, convention, order); return new OrderedServerHttpObservationFilter(registry, convention, order);
} }
private static ServerRequestObservationConvention createConvention(
ServerRequestObservationConvention customConvention, String name, WebFluxTagsProvider tagsProvider,
List<WebFluxTagsContributor> tagsContributors) {
if (customConvention != null) {
return customConvention;
}
if (tagsProvider != null) {
return new ServerRequestObservationConventionAdapter(name, tagsProvider);
}
if (!tagsContributors.isEmpty()) {
return new ServerRequestObservationConventionAdapter(name, tagsContributors);
}
return new DefaultServerRequestObservationConvention(name);
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MeterRegistry.class) @ConditionalOnClass(MeterRegistry.class)
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
@ -117,9 +88,7 @@ public class WebFluxObservationAutoConfiguration {
@Order(0) @Order(0)
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties, MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties,
ObservationProperties observationProperties) { ObservationProperties observationProperties) {
String observationName = observationProperties.getHttp().getServer().getRequests().getName(); String name = observationProperties.getHttp().getServer().getRequests().getName();
String name = (observationName != null) ? observationName
: metricsProperties.getWeb().getServer().getRequest().getMetricName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> "Reached the maximum number of URI tags for '%s'.".formatted(name)); () -> "Reached the maximum number of URI tags for '%s'.".formatted(name));
return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(), return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),

@ -1,76 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.servlet;
import java.util.List;
import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.Tag;
import io.micrometer.observation.Observation;
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;
import org.springframework.http.server.observation.ServerRequestObservationContext;
import org.springframework.http.server.observation.ServerRequestObservationConvention;
import org.springframework.util.Assert;
import org.springframework.web.servlet.HandlerMapping;
/**
* Adapter class that applies {@link WebMvcTagsProvider} tags as a
* {@link ServerRequestObservationConvention}.
*
* @author Brian Clozel
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class ServerRequestObservationConventionAdapter implements ServerRequestObservationConvention {
private final String observationName;
private final WebMvcTagsProvider tagsProvider;
ServerRequestObservationConventionAdapter(String observationName, WebMvcTagsProvider tagsProvider,
List<WebMvcTagsContributor> contributors) {
Assert.state((tagsProvider != null) || (contributors != null),
"adapter should adapt to a WebMvcTagsProvider or a list of contributors");
this.observationName = observationName;
this.tagsProvider = (tagsProvider != null) ? tagsProvider : new DefaultWebMvcTagsProvider(contributors);
}
@Override
public String getName() {
return this.observationName;
}
@Override
public boolean supportsContext(Observation.Context context) {
return context instanceof ServerRequestObservationContext;
}
@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
Iterable<Tag> tags = this.tagsProvider.getTags(context.getCarrier(), context.getResponse(), getHandler(context),
context.getError());
return KeyValues.of(tags, Tag::getKey, Tag::getValue);
}
private Object getHandler(ServerRequestObservationContext context) {
return context.getCarrier().getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
}
}

@ -16,8 +16,6 @@
package org.springframework.boot.actuate.autoconfigure.observation.web.servlet; package org.springframework.boot.actuate.autoconfigure.observation.web.servlet;
import java.util.List;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
@ -32,8 +30,6 @@ import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDen
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -66,56 +62,23 @@ import org.springframework.web.servlet.DispatcherServlet;
@ConditionalOnClass({ DispatcherServlet.class, Observation.class }) @ConditionalOnClass({ DispatcherServlet.class, Observation.class })
@ConditionalOnBean(ObservationRegistry.class) @ConditionalOnBean(ObservationRegistry.class)
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class }) @EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
@SuppressWarnings("removal")
public class WebMvcObservationAutoConfiguration { public class WebMvcObservationAutoConfiguration {
private final MetricsProperties metricsProperties;
private final ObservationProperties observationProperties;
public WebMvcObservationAutoConfiguration(ObservationProperties observationProperties,
MetricsProperties metricsProperties) {
this.observationProperties = observationProperties;
this.metricsProperties = metricsProperties;
}
@Bean @Bean
@ConditionalOnMissingFilterBean @ConditionalOnMissingFilterBean
public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(ObservationRegistry registry, public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(ObservationRegistry registry,
ObjectProvider<ServerRequestObservationConvention> customConvention, ObjectProvider<ServerRequestObservationConvention> customConvention,
ObjectProvider<WebMvcTagsProvider> customTagsProvider, ObservationProperties observationProperties) {
ObjectProvider<WebMvcTagsContributor> contributorsProvider) { String name = observationProperties.getHttp().getServer().getRequests().getName();
String name = httpRequestsMetricName(this.observationProperties, this.metricsProperties); ServerRequestObservationConvention convention = customConvention
ServerRequestObservationConvention convention = createConvention(customConvention.getIfAvailable(), name, .getIfAvailable(() -> new DefaultServerRequestObservationConvention(name));
customTagsProvider.getIfAvailable(), contributorsProvider.orderedStream().toList());
ServerHttpObservationFilter filter = new ServerHttpObservationFilter(registry, convention); ServerHttpObservationFilter filter = new ServerHttpObservationFilter(registry, convention);
FilterRegistrationBean<ServerHttpObservationFilter> registration = new FilterRegistrationBean<>(filter); FilterRegistrationBean<ServerHttpObservationFilter> registration = new FilterRegistrationBean<>(filter);
registration.setOrder(this.observationProperties.getHttp().getServer().getFilter().getOrder()); registration.setOrder(observationProperties.getHttp().getServer().getFilter().getOrder());
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC); registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
return registration; return registration;
} }
private static ServerRequestObservationConvention createConvention(
ServerRequestObservationConvention customConvention, String name, WebMvcTagsProvider tagsProvider,
List<WebMvcTagsContributor> contributors) {
if (customConvention != null) {
return customConvention;
}
else if (tagsProvider != null || contributors.size() > 0) {
return new ServerRequestObservationConventionAdapter(name, tagsProvider, contributors);
}
else {
return new DefaultServerRequestObservationConvention(name);
}
}
private static String httpRequestsMetricName(ObservationProperties observationProperties,
MetricsProperties metricsProperties) {
String observationName = observationProperties.getHttp().getServer().getRequests().getName();
return (observationName != null) ? observationName
: metricsProperties.getWeb().getServer().getRequest().getMetricName();
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MeterRegistry.class) @ConditionalOnClass(MeterRegistry.class)
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
@ -123,9 +86,9 @@ public class WebMvcObservationAutoConfiguration {
@Bean @Bean
@Order(0) @Order(0)
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties, MeterFilter metricsHttpServerUriTagFilter(ObservationProperties observationProperties,
ObservationProperties observationProperties) { MetricsProperties metricsProperties) {
String name = httpRequestsMetricName(observationProperties, metricsProperties); String name = observationProperties.getHttp().getServer().getRequests().getName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> String.format("Reached the maximum number of URI tags for '%s'.", name)); () -> String.format("Reached the maximum number of URI tags for '%s'.", name));
return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(), return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),

@ -1980,11 +1980,19 @@
"reason": "Should be applied at the ObservationRegistry level." "reason": "Should be applied at the ObservationRegistry level."
} }
}, },
{
"name": "management.metrics.web.client.request.metric-name",
"type": "java.lang.String",
"deprecation": {
"replacement": "management.observations.http.client.requests.name",
"level": "error"
}
},
{ {
"name": "management.metrics.web.client.requests-metric-name", "name": "management.metrics.web.client.requests-metric-name",
"type": "java.lang.String", "type": "java.lang.String",
"deprecation": { "deprecation": {
"replacement": "management.metrics.web.client.request.metric-name", "replacement": "management.observations.http.client.requests.name",
"level": "error" "level": "error"
} }
}, },
@ -2030,11 +2038,19 @@
"reason": "Not needed anymore, direct instrumentation in Spring MVC." "reason": "Not needed anymore, direct instrumentation in Spring MVC."
} }
}, },
{
"name": "management.metrics.web.server.request.metric-name",
"type": "java.lang.String",
"deprecation": {
"replacement": "management.observations.http.server.requests.name",
"level": "error"
}
},
{ {
"name": "management.metrics.web.server.requests-metric-name", "name": "management.metrics.web.server.requests-metric-name",
"type": "java.lang.String", "type": "java.lang.String",
"deprecation": { "deprecation": {
"replacement": "management.metrics.web.server.request.metric-name", "replacement": "management.observations.http.server.requests.name",
"level": "error" "level": "error"
} }
}, },

@ -1,57 +0,0 @@
/*
* 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.
* 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.autoconfigure.health;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfigurationReflectionTests.TestHealthIndicator;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.actuate.health.HealthContributor;
/**
* Tests for {@link CompositeHealthContributorConfiguration} using reflection to create
* indicator instances.
*
* @author Phillip Webb
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class CompositeHealthContributorConfigurationReflectionTests
extends AbstractCompositeHealthContributorConfigurationTests<HealthContributor, TestHealthIndicator> {
@Override
protected AbstractCompositeHealthContributorConfiguration<HealthContributor, TestHealthIndicator, TestBean> newComposite() {
return new ReflectiveTestCompositeHealthContributorConfiguration();
}
static class ReflectiveTestCompositeHealthContributorConfiguration
extends CompositeHealthContributorConfiguration<TestHealthIndicator, TestBean> {
}
static class TestHealthIndicator extends AbstractHealthIndicator {
TestHealthIndicator(TestBean testBean) {
}
@Override
protected void doHealthCheck(Builder builder) throws Exception {
builder.up();
}
}
}

@ -1,60 +0,0 @@
/*
* 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.
* 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.autoconfigure.health;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfigurationReflectionTests.TestReactiveHealthIndicator;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
/**
* Tests for {@link CompositeReactiveHealthContributorConfiguration} using reflection to
* create indicator instances.
*
* @author Phillip Webb
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class CompositeReactiveHealthContributorConfigurationReflectionTests extends
AbstractCompositeHealthContributorConfigurationTests<ReactiveHealthContributor, TestReactiveHealthIndicator> {
@Override
protected AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, TestReactiveHealthIndicator, TestBean> newComposite() {
return new TestCompositeReactiveHealthContributorConfiguration();
}
static class TestCompositeReactiveHealthContributorConfiguration
extends CompositeReactiveHealthContributorConfiguration<TestReactiveHealthIndicator, TestBean> {
}
static class TestReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
TestReactiveHealthIndicator(TestBean testBean) {
}
@Override
protected Mono<Health> doHealthCheck(Builder builder) {
return Mono.just(builder.up().build());
}
}
}

@ -1,90 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.client;
import java.net.URI;
import io.micrometer.common.KeyValue;
import io.micrometer.observation.Observation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.observation.ClientRequestObservationContext;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.mock.http.client.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ClientHttpObservationConventionAdapter}.
*
* @author Brian Clozel
*/
@SuppressWarnings({ "deprecation", "removal" })
class ClientHttpObservationConventionAdapterTests {
private static final String TEST_METRIC_NAME = "test.metric.name";
private final ClientHttpObservationConventionAdapter convention = new ClientHttpObservationConventionAdapter(
TEST_METRIC_NAME, new DefaultRestTemplateExchangeTagsProvider());
private final ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/resource/test"));
private final ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.OK);
private ClientRequestObservationContext context;
@BeforeEach
void setup() {
this.context = new ClientRequestObservationContext(this.request);
this.context.setResponse(this.response);
this.context.setUriTemplate("/resource/{name}");
}
@Test
void shouldUseConfiguredName() {
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME);
}
@Test
void shouldOnlySupportClientHttpObservationContext() {
assertThat(this.convention.supportsContext(this.context)).isTrue();
assertThat(this.convention.supportsContext(new OtherContext())).isFalse();
}
@Test
void shouldPushTagsAsLowCardinalityKeyValues() {
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"),
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"),
KeyValue.of("method", "GET"));
}
@Test
void shouldNotPushAnyHighCardinalityKeyValue() {
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty();
}
static class OtherContext extends Observation.Context {
}
}

@ -1,100 +0,0 @@
/*
* Copyright 2012-2023 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.autoconfigure.observation.web.client;
import java.net.URI;
import io.micrometer.common.KeyValue;
import io.micrometer.observation.Observation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientRequestObservationContext;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ClientObservationConventionAdapter}.
*
* @author Brian Clozel
*/
@SuppressWarnings({ "deprecation", "removal" })
class ClientObservationConventionAdapterTests {
private static final String TEST_METRIC_NAME = "test.metric.name";
private final ClientObservationConventionAdapter convention = new ClientObservationConventionAdapter(
TEST_METRIC_NAME, new DefaultWebClientExchangeTagsProvider());
private final ClientRequest.Builder requestBuilder = ClientRequest
.create(HttpMethod.GET, URI.create("/resource/test"))
.attribute(WebClient.class.getName() + ".uriTemplate", "/resource/{name}");
private final ClientResponse response = ClientResponse.create(HttpStatus.OK).body("foo").build();
private ClientRequestObservationContext context;
@BeforeEach
void setup() {
this.context = new ClientRequestObservationContext();
this.context.setCarrier(this.requestBuilder);
this.context.setResponse(this.response);
this.context.setUriTemplate("/resource/{name}");
}
@Test
void shouldUseConfiguredName() {
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME);
}
@Test
void shouldOnlySupportClientObservationContext() {
assertThat(this.convention.supportsContext(this.context)).isTrue();
assertThat(this.convention.supportsContext(new OtherContext())).isFalse();
}
@Test
void shouldPushTagsAsLowCardinalityKeyValues() {
this.context.setRequest(this.requestBuilder.build());
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"),
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"),
KeyValue.of("method", "GET"));
}
@Test
void doesNotFailWithEmptyRequest() {
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"),
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"),
KeyValue.of("method", "GET"));
}
@Test
void shouldNotPushAnyHighCardinalityKeyValue() {
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty();
}
static class OtherContext extends Observation.Context {
}
}

@ -18,8 +18,6 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client;
import io.micrometer.common.KeyValues; import io.micrometer.common.KeyValues;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert; import io.micrometer.observation.tck.TestObservationRegistryAssert;
@ -28,9 +26,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider;
import org.springframework.boot.actuate.metrics.web.client.ObservationRestTemplateCustomizer; import org.springframework.boot.actuate.metrics.web.client.ObservationRestTemplateCustomizer;
import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
@ -40,9 +36,7 @@ import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.observation.ClientRequestObservationContext; import org.springframework.http.client.observation.ClientRequestObservationContext;
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention; import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.test.web.client.MockRestServiceServer;
@ -58,7 +52,6 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
* @author Brian Clozel * @author Brian Clozel
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@SuppressWarnings("removal")
class RestTemplateObservationConfigurationTests { class RestTemplateObservationConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
@ -68,8 +61,7 @@ class RestTemplateObservationConfigurationTests {
@Test @Test
void contributesCustomizerBean() { void contributesCustomizerBean() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationRestTemplateCustomizer.class) this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationRestTemplateCustomizer.class));
.doesNotHaveBean(DefaultRestTemplateExchangeTagsProvider.class));
} }
@Test @Test
@ -96,32 +88,6 @@ class RestTemplateObservationConfigurationTests {
}); });
} }
@Test
void restTemplateCreatedWithBuilderUsesCustomMetricName() {
final String metricName = "test.metric.name";
this.contextRunner.withPropertyValues("management.metrics.web.client.request.metric-name=" + metricName)
.run((context) -> {
RestTemplate restTemplate = buildRestTemplate(context);
restTemplate.getForEntity("/projects/{project}", Void.class, "spring-boot");
TestObservationRegistry registry = context.getBean(TestObservationRegistry.class);
TestObservationRegistryAssert.assertThat(registry)
.hasObservationWithNameEqualToIgnoringCase(metricName);
});
}
@Test
void restTemplateCreatedWithBuilderUsesCustomTagsProvider() {
this.contextRunner.withUserConfiguration(CustomTagsConfiguration.class).run((context) -> {
RestTemplate restTemplate = buildRestTemplate(context);
restTemplate.getForEntity("/projects/{project}", Void.class, "spring-boot");
TestObservationRegistry registry = context.getBean(TestObservationRegistry.class);
TestObservationRegistryAssert.assertThat(registry)
.hasObservationWithNameEqualTo("http.client.requests")
.that()
.hasLowCardinalityKeyValue("project", "spring-boot");
});
}
@Test @Test
void restTemplateCreatedWithBuilderUsesCustomConvention() { void restTemplateCreatedWithBuilderUsesCustomConvention() {
this.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> { this.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> {
@ -163,8 +129,7 @@ class RestTemplateObservationConfigurationTests {
new ApplicationContextRunner().with(MetricsRun.simple()) new ApplicationContextRunner().with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
HttpClientObservationsAutoConfiguration.class)) HttpClientObservationsAutoConfiguration.class))
.run((context) -> assertThat(context).doesNotHaveBean(DefaultRestTemplateExchangeTagsProvider.class) .run((context) -> assertThat(context).doesNotHaveBean(ObservationRestTemplateCustomizer.class));
.doesNotHaveBean(ObservationRestTemplateCustomizer.class));
} }
private RestTemplate buildRestTemplate(AssertableApplicationContext context) { private RestTemplate buildRestTemplate(AssertableApplicationContext context) {
@ -174,26 +139,6 @@ class RestTemplateObservationConfigurationTests {
return restTemplate; return restTemplate;
} }
@Configuration(proxyBeanMethods = false)
static class CustomTagsConfiguration {
@Bean
CustomTagsProvider customTagsProvider() {
return new CustomTagsProvider();
}
}
@Deprecated(since = "3.0.0", forRemoval = true)
static class CustomTagsProvider implements RestTemplateExchangeTagsProvider {
@Override
public Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) {
return Tags.of("project", "spring-boot");
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomConventionConfiguration { static class CustomConventionConfiguration {

@ -29,9 +29,7 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider;
import org.springframework.boot.actuate.metrics.web.reactive.client.ObservationWebClientCustomizer; import org.springframework.boot.actuate.metrics.web.reactive.client.ObservationWebClientCustomizer;
import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
@ -59,7 +57,6 @@ import static org.mockito.Mockito.mock;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@SuppressWarnings("removal")
class WebClientObservationConfigurationTests { class WebClientObservationConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple()) private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
@ -69,8 +66,7 @@ class WebClientObservationConfigurationTests {
@Test @Test
void contributesCustomizerBean() { void contributesCustomizerBean() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationWebClientCustomizer.class) this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationWebClientCustomizer.class));
.doesNotHaveBean(DefaultWebClientExchangeTagsProvider.class));
} }
@Test @Test
@ -82,14 +78,6 @@ class WebClientObservationConfigurationTests {
}); });
} }
@Test
void shouldNotOverrideCustomTagsProvider() {
this.contextRunner.withUserConfiguration(CustomTagsProviderConfig.class)
.run((context) -> assertThat(context).getBeans(WebClientExchangeTagsProvider.class)
.hasSize(1)
.containsKey("customTagsProvider"));
}
@Test @Test
void shouldUseCustomConventionIfAvailable() { void shouldUseCustomConventionIfAvailable() {
this.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> { this.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> {
@ -170,16 +158,6 @@ class WebClientObservationConfigurationTests {
return builder.clientConnector(connector).build(); return builder.clientConnector(connector).build();
} }
@Configuration(proxyBeanMethods = false)
static class CustomTagsProviderConfig {
@Bean
WebClientExchangeTagsProvider customTagsProvider() {
return mock(WebClientExchangeTagsProvider.class);
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomConventionConfig { static class CustomConventionConfig {

@ -1,64 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.reactive;
import java.util.Map;
import io.micrometer.common.KeyValue;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ServerRequestObservationConventionAdapter}.
*
* @author Brian Clozel
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class ServerRequestObservationConventionAdapterTests {
private static final String TEST_METRIC_NAME = "test.metric.name";
private final ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter(
TEST_METRIC_NAME, new DefaultWebFluxTagsProvider());
@Test
void shouldUseConfiguredName() {
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME);
}
@Test
void shouldPushTagsAsLowCardinalityKeyValues() {
MockServerHttpRequest request = MockServerHttpRequest.get("/resource/test").build();
MockServerHttpResponse response = new MockServerHttpResponse();
ServerRequestObservationContext context = new ServerRequestObservationContext(request, response,
Map.of(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE,
PathPatternParser.defaultInstance.parse("/resource/{name}")));
assertThat(this.convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("status", "200"),
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"),
KeyValue.of("method", "GET"));
}
}

@ -19,8 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.reactive;
import java.util.List; import java.util.List;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -29,9 +27,6 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfigu
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
@ -83,28 +78,6 @@ class WebFluxObservationAutoConfigurationTests {
}); });
} }
@Test
void shouldUseConventionAdapterWhenCustomTagsProvider() {
this.contextRunner.withUserConfiguration(CustomTagsProviderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ServerHttpObservationFilter.class);
assertThat(context).hasSingleBean(WebFluxTagsProvider.class);
assertThat(context).getBean(ServerHttpObservationFilter.class)
.extracting("observationConvention")
.isInstanceOf(ServerRequestObservationConventionAdapter.class);
});
}
@Test
void shouldUseConventionAdapterWhenCustomTagsContributor() {
this.contextRunner.withUserConfiguration(CustomTagsContributorConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ServerHttpObservationFilter.class);
assertThat(context).hasSingleBean(WebFluxTagsContributor.class);
assertThat(context).getBean(ServerHttpObservationFilter.class)
.extracting("observationConvention")
.isInstanceOf(ServerRequestObservationConventionAdapter.class);
});
}
@Test @Test
void shouldUseCustomConventionWhenAvailable() { void shouldUseCustomConventionWhenAvailable() {
this.contextRunner.withUserConfiguration(CustomConventionConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(CustomConventionConfiguration.class).run((context) -> {
@ -128,21 +101,6 @@ class WebFluxObservationAutoConfigurationTests {
}); });
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomMetricName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,
WebFluxAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.metrics.web.server.request.metric-name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters()).hasSizeLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test @Test
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) { void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class) this.contextRunner.withUserConfiguration(TestController.class)
@ -194,37 +152,6 @@ class WebFluxObservationAutoConfigurationTests {
return context.getBean(MeterRegistry.class); return context.getBean(MeterRegistry.class);
} }
@Deprecated(since = "3.0.0", forRemoval = true)
@Configuration(proxyBeanMethods = false)
static class CustomTagsProviderConfiguration {
@Bean
WebFluxTagsProvider tagsProvider() {
return new DefaultWebFluxTagsProvider();
}
}
@Configuration(proxyBeanMethods = false)
static class CustomTagsContributorConfiguration {
@Bean
WebFluxTagsContributor tagsContributor() {
return new CustomTagsContributor();
}
}
@Deprecated(since = "3.0.0", forRemoval = true)
static class CustomTagsContributor implements WebFluxTagsContributor {
@Override
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
return Tags.of("custom", "testvalue");
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomConventionConfiguration { static class CustomConventionConfiguration {

@ -1,111 +0,0 @@
/*
* 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.
* 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.autoconfigure.observation.web.servlet;
import java.util.Collections;
import java.util.List;
import io.micrometer.common.KeyValue;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.observation.Observation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor;
import org.springframework.http.server.observation.ServerRequestObservationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.HandlerMapping;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ServerRequestObservationConventionAdapter}
*
* @author Brian Clozel
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class ServerRequestObservationConventionAdapterTests {
private static final String TEST_METRIC_NAME = "test.metric.name";
private final ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter(
TEST_METRIC_NAME, new DefaultWebMvcTagsProvider(), Collections.emptyList());
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/resource/test");
private final MockHttpServletResponse response = new MockHttpServletResponse();
private final ServerRequestObservationContext context = new ServerRequestObservationContext(this.request,
this.response);
@Test
void customNameIsUsed() {
assertThat(this.convention.getName()).isEqualTo(TEST_METRIC_NAME);
}
@Test
void onlySupportServerRequestObservationContext() {
assertThat(this.convention.supportsContext(this.context)).isTrue();
assertThat(this.convention.supportsContext(new OtherContext())).isFalse();
}
@Test
void pushTagsAsLowCardinalityKeyValues() {
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/resource/{name}");
this.context.setPathPattern("/resource/{name}");
assertThat(this.convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("status", "200"),
KeyValue.of("outcome", "SUCCESS"), KeyValue.of("uri", "/resource/{name}"),
KeyValue.of("method", "GET"));
}
@Test
void doesNotPushAnyHighCardinalityKeyValue() {
assertThat(this.convention.getHighCardinalityKeyValues(this.context)).isEmpty();
}
@Test
void pushTagsFromContributors() {
ServerRequestObservationConventionAdapter convention = new ServerRequestObservationConventionAdapter(
TEST_METRIC_NAME, null, List.of(new CustomWebMvcContributor()));
assertThat(convention.getLowCardinalityKeyValues(this.context)).contains(KeyValue.of("custom", "value"));
}
static class OtherContext extends Observation.Context {
}
static class CustomWebMvcContributor implements WebMvcTagsContributor {
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
return Tags.of("custom", "value");
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return Collections.emptyList();
}
}
}

@ -16,16 +16,12 @@
package org.springframework.boot.actuate.autoconfigure.observation.web.servlet; package org.springframework.boot.actuate.autoconfigure.observation.web.servlet;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.observation.tck.TestObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry;
import jakarta.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -33,9 +29,6 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfigu
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
@ -67,7 +60,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Moritz Halbritter * @author Moritz Halbritter
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@SuppressWarnings("removal")
class WebMvcObservationAutoConfigurationTests { class WebMvcObservationAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
@ -85,21 +77,12 @@ class WebMvcObservationAutoConfigurationTests {
@Test @Test
void definesFilterWhenRegistryIsPresent() { void definesFilterWhenRegistryIsPresent() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
assertThat(context).doesNotHaveBean(DefaultWebMvcTagsProvider.class);
assertThat(context).hasSingleBean(FilterRegistrationBean.class); assertThat(context).hasSingleBean(FilterRegistrationBean.class);
assertThat(context.getBean(FilterRegistrationBean.class).getFilter()) assertThat(context.getBean(FilterRegistrationBean.class).getFilter())
.isInstanceOf(ServerHttpObservationFilter.class); .isInstanceOf(ServerHttpObservationFilter.class);
}); });
} }
@Test
void adapterConventionWhenTagsProviderPresent() {
this.contextRunner.withUserConfiguration(TagsProviderConfiguration.class)
.run((context) -> assertThat(context.getBean(FilterRegistrationBean.class).getFilter())
.extracting("observationConvention")
.isInstanceOf(ServerRequestObservationConventionAdapter.class));
}
@Test @Test
void customConventionWhenPresent() { void customConventionWhenPresent() {
this.contextRunner.withUserConfiguration(CustomConventionConfiguration.class) this.contextRunner.withUserConfiguration(CustomConventionConfiguration.class)
@ -169,21 +152,6 @@ class WebMvcObservationAutoConfigurationTests {
}); });
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomMetricName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,
WebMvcAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.metrics.web.server.request.metric-name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters()).hasSizeLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test @Test
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) { void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class) this.contextRunner.withUserConfiguration(TestController.class)
@ -211,14 +179,6 @@ class WebMvcObservationAutoConfigurationTests {
}); });
} }
@Test
void whenTagContributorsAreDefinedThenTagsProviderUsesThem() {
this.contextRunner.withUserConfiguration(TagsContributorsConfiguration.class)
.run((context) -> assertThat(context.getBean(FilterRegistrationBean.class).getFilter())
.extracting("observationConvention")
.isInstanceOf(ServerRequestObservationConventionAdapter.class));
}
private MeterRegistry getInitializedMeterRegistry(AssertableWebApplicationContext context) throws Exception { private MeterRegistry getInitializedMeterRegistry(AssertableWebApplicationContext context) throws Exception {
return getInitializedMeterRegistry(context, "/test0", "/test1", "/test2"); return getInitializedMeterRegistry(context, "/test0", "/test1", "/test2");
} }
@ -235,47 +195,6 @@ class WebMvcObservationAutoConfigurationTests {
return context.getBean(MeterRegistry.class); return context.getBean(MeterRegistry.class);
} }
@Configuration(proxyBeanMethods = false)
static class TagsProviderConfiguration {
@Bean
TestWebMvcTagsProvider tagsProvider() {
return new TestWebMvcTagsProvider();
}
}
@Configuration(proxyBeanMethods = false)
static class TagsContributorsConfiguration {
@Bean
WebMvcTagsContributor tagContributorOne() {
return mock(WebMvcTagsContributor.class);
}
@Bean
WebMvcTagsContributor tagContributorTwo() {
return mock(WebMvcTagsContributor.class);
}
}
@Deprecated(since = "3.0.0", forRemoval = true)
private static final class TestWebMvcTagsProvider implements WebMvcTagsProvider {
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
return Collections.emptyList();
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return Collections.emptyList();
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class TestServerHttpObservationFilterRegistrationConfiguration { static class TestServerHttpObservationFilterRegistrationConfiguration {

@ -141,7 +141,7 @@ public class PrometheusPushGatewayManager {
} }
this.scheduled.cancel(false); this.scheduled.cancel(false);
switch (shutdownOperation) { switch (shutdownOperation) {
case PUSH, POST -> post(); case POST -> post();
case PUT -> put(); case PUT -> put();
case DELETE -> delete(); case DELETE -> delete();
} }
@ -162,13 +162,6 @@ public class PrometheusPushGatewayManager {
*/ */
POST, POST,
/**
* Perform a POST before shutdown.
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of {@link #POST}.
*/
@Deprecated(since = "3.0.0", forRemoval = true)
PUSH,
/** /**
* Perform a PUT before shutdown. * Perform a PUT before shutdown.
*/ */

@ -1,49 +0,0 @@
/*
* 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.
* 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.metrics.web.client;
import java.util.Arrays;
import io.micrometer.core.instrument.Tag;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
/**
* Default implementation of {@link RestTemplateExchangeTagsProvider}.
*
* @author Jon Schneider
* @author Nishant Raut
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.client.observation.DefaultClientRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
public class DefaultRestTemplateExchangeTagsProvider implements RestTemplateExchangeTagsProvider {
@Override
public Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) {
Tag uriTag = (StringUtils.hasText(urlTemplate) ? RestTemplateExchangeTags.uri(urlTemplate)
: RestTemplateExchangeTags.uri(request));
return Arrays.asList(RestTemplateExchangeTags.method(request), uriTag,
RestTemplateExchangeTags.status(response), RestTemplateExchangeTags.clientName(request),
RestTemplateExchangeTags.outcome(response));
}
}

@ -1,144 +0,0 @@
/*
* 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.
* 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.metrics.web.client;
import java.io.IOException;
import java.net.URI;
import java.util.regex.Pattern;
import io.micrometer.core.instrument.Tag;
import org.springframework.boot.actuate.metrics.http.Outcome;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
/**
* Factory methods for creating {@link Tag Tags} related to a request-response exchange
* performed by a {@link RestTemplate}.
*
* @author Andy Wilkinson
* @author Jon Schneider
* @author Nishant Raut
* @author Brian Clozel
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link DefaultClientRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public final class RestTemplateExchangeTags {
private static final Pattern STRIP_URI_PATTERN = Pattern.compile("^https?://[^/]+/");
private RestTemplateExchangeTags() {
}
/**
* Creates a {@code method} {@code Tag} for the {@link HttpRequest#getMethod() method}
* of the given {@code request}.
* @param request the request
* @return the method tag
*/
public static Tag method(HttpRequest request) {
return Tag.of("method", request.getMethod().name());
}
/**
* Creates a {@code uri} {@code Tag} for the URI of the given {@code request}.
* @param request the request
* @return the uri tag
*/
public static Tag uri(HttpRequest request) {
return Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().toString())));
}
/**
* Creates a {@code uri} {@code Tag} from the given {@code uriTemplate}.
* @param uriTemplate the template
* @return the uri tag
*/
public static Tag uri(String uriTemplate) {
String uri = (StringUtils.hasText(uriTemplate) ? uriTemplate : "none");
return Tag.of("uri", ensureLeadingSlash(stripUri(uri)));
}
private static String stripUri(String uri) {
return STRIP_URI_PATTERN.matcher(uri).replaceAll("");
}
private static String ensureLeadingSlash(String url) {
return (url == null || url.startsWith("/")) ? url : "/" + url;
}
/**
* Creates a {@code status} {@code Tag} derived from the
* {@link ClientHttpResponse#getStatusCode() status} of the given {@code response}.
* @param response the response
* @return the status tag
*/
public static Tag status(ClientHttpResponse response) {
return Tag.of("status", getStatusMessage(response));
}
private static String getStatusMessage(ClientHttpResponse response) {
try {
if (response == null) {
return "CLIENT_ERROR";
}
return String.valueOf(response.getStatusCode().value());
}
catch (IOException ex) {
return "IO_ERROR";
}
}
/**
* Create a {@code client.name} {@code Tag} derived from the {@link URI#getHost host}
* of the {@link HttpRequest#getURI() URI} of the given {@code request}.
* @param request the request
* @return the client.name tag
*/
public static Tag clientName(HttpRequest request) {
String host = request.getURI().getHost();
if (host == null) {
host = "none";
}
return Tag.of("client.name", host);
}
/**
* Creates an {@code outcome} {@code Tag} derived from the
* {@link ClientHttpResponse#getStatusCode() status} of the given {@code response}.
* @param response the response
* @return the outcome tag
* @since 2.2.0
*/
public static Tag outcome(ClientHttpResponse response) {
try {
if (response != null) {
return Outcome.forStatus(response.getStatusCode().value()).asTag();
}
}
catch (IOException ex) {
// Continue
}
return Outcome.UNKNOWN.asTag();
}
}

@ -1,49 +0,0 @@
/*
* 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.
* 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.metrics.web.client;
import io.micrometer.core.instrument.Tag;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.observation.ClientRequestObservationConvention;
import org.springframework.web.client.RestTemplate;
/**
* Provides {@link Tag Tags} for an exchange performed by a {@link RestTemplate}.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link ClientRequestObservationConvention}
*/
@FunctionalInterface
@Deprecated(since = "3.0.0", forRemoval = true)
public interface RestTemplateExchangeTagsProvider {
/**
* Provides the tags to be associated with metrics that are recorded for the given
* {@code request} and {@code response} exchange.
* @param urlTemplate the source URl template, if available
* @param request the request
* @param response the response (may be {@code null} if the exchange failed)
* @return the tags
*/
Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response);
}

@ -1,49 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.client;
import java.util.Arrays;
import io.micrometer.core.instrument.Tag;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
/**
* Default implementation of {@link WebClientExchangeTagsProvider}.
*
* @author Brian Clozel
* @author Nishant Raut
* @since 2.1.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.web.reactive.function.client.ClientRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
public class DefaultWebClientExchangeTagsProvider implements WebClientExchangeTagsProvider {
@Override
public Iterable<Tag> tags(ClientRequest request, ClientResponse response, Throwable throwable) {
Tag method = WebClientExchangeTags.method(request);
Tag uri = WebClientExchangeTags.uri(request);
Tag clientName = WebClientExchangeTags.clientName(request);
Tag status = WebClientExchangeTags.status(response, throwable);
Tag outcome = WebClientExchangeTags.outcome(response);
return Arrays.asList(method, uri, clientName, status, outcome);
}
}

@ -1,127 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.client;
import java.io.IOException;
import java.util.regex.Pattern;
import io.micrometer.core.instrument.Tag;
import org.springframework.boot.actuate.metrics.http.Outcome;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Factory methods for creating {@link Tag Tags} related to a request-response exchange
* performed by a {@link WebClient}.
*
* @author Brian Clozel
* @author Nishant Raut
* @since 2.1.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public final class WebClientExchangeTags {
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
private static final Tag IO_ERROR = Tag.of("status", "IO_ERROR");
private static final Tag CLIENT_ERROR = Tag.of("status", "CLIENT_ERROR");
private static final Pattern PATTERN_BEFORE_PATH = Pattern.compile("^https?://[^/]+/");
private static final Tag CLIENT_NAME_NONE = Tag.of("client.name", "none");
private WebClientExchangeTags() {
}
/**
* Creates a {@code method} {@code Tag} for the {@link ClientHttpRequest#getMethod()
* method} of the given {@code request}.
* @param request the request
* @return the method tag
*/
public static Tag method(ClientRequest request) {
return Tag.of("method", request.method().name());
}
/**
* Creates a {@code uri} {@code Tag} for the URI path of the given {@code request}.
* @param request the request
* @return the uri tag
*/
public static Tag uri(ClientRequest request) {
String uri = (String) request.attribute(URI_TEMPLATE_ATTRIBUTE).orElseGet(() -> request.url().toString());
return Tag.of("uri", extractPath(uri));
}
private static String extractPath(String url) {
String path = PATTERN_BEFORE_PATH.matcher(url).replaceFirst("");
return (path.startsWith("/") ? path : "/" + path);
}
/**
* Creates a {@code status} {@code Tag} derived from the
* {@link ClientResponse#statusCode()} of the given {@code response} if available, the
* thrown exception otherwise, or considers the request as Cancelled as a last resort.
* @param response the response
* @param throwable the exception
* @return the status tag
* @since 2.3.0
*/
public static Tag status(ClientResponse response, Throwable throwable) {
if (response != null) {
return Tag.of("status", String.valueOf(response.statusCode().value()));
}
if (throwable != null) {
return (throwable instanceof IOException) ? IO_ERROR : CLIENT_ERROR;
}
return CLIENT_ERROR;
}
/**
* Create a {@code client.name} {@code Tag} derived from the
* {@link java.net.URI#getHost host} of the {@link ClientRequest#url() URL} of the
* given {@code request}.
* @param request the request
* @return the client.name tag
*/
public static Tag clientName(ClientRequest request) {
String host = request.url().getHost();
if (host == null) {
return CLIENT_NAME_NONE;
}
return Tag.of("client.name", host);
}
/**
* Creates an {@code outcome} {@code Tag} derived from the
* {@link ClientResponse#statusCode() status} of the given {@code response}.
* @param response the response
* @return the outcome tag
* @since 2.2.0
*/
public static Tag outcome(ClientResponse response) {
Outcome outcome = (response != null) ? Outcome.forStatus(response.statusCode().value()) : Outcome.UNKNOWN;
return outcome.asTag();
}
}

@ -1,46 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.client;
import io.micrometer.core.instrument.Tag;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
/**
* {@link Tag Tags} provider for an exchange performed by a
* {@link org.springframework.web.reactive.function.client.WebClient}.
*
* @author Brian Clozel
* @since 2.1.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.web.reactive.function.client.ClientRequestObservationConvention}
*/
@FunctionalInterface
@Deprecated(since = "3.0.0", forRemoval = true)
public interface WebClientExchangeTagsProvider {
/**
* Provide tags to be associated with metrics for the client exchange.
* @param request the client request
* @param response the server response (may be {@code null})
* @param throwable the exception (may be {@code null})
* @return tags to associate with metrics for the request and response exchange
*/
Iterable<Tag> tags(ClientRequest request, ClientResponse response, Throwable throwable);
}

@ -1,89 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.server;
import java.util.Collections;
import java.util.List;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.springframework.web.server.ServerWebExchange;
/**
* Default implementation of {@link WebFluxTagsProvider}.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
public class DefaultWebFluxTagsProvider implements WebFluxTagsProvider {
private final boolean ignoreTrailingSlash;
private final List<WebFluxTagsContributor> contributors;
public DefaultWebFluxTagsProvider() {
this(false);
}
/**
* Creates a new {@link DefaultWebFluxTagsProvider} that will provide tags from the
* given {@code contributors} in addition to its own.
* @param contributors the contributors that will provide additional tags
* @since 2.3.0
*/
public DefaultWebFluxTagsProvider(List<WebFluxTagsContributor> contributors) {
this(false, contributors);
}
public DefaultWebFluxTagsProvider(boolean ignoreTrailingSlash) {
this(ignoreTrailingSlash, Collections.emptyList());
}
/**
* Creates a new {@link DefaultWebFluxTagsProvider} that will provide tags from the
* given {@code contributors} in addition to its own.
* @param ignoreTrailingSlash whether trailing slashes should be ignored when
* determining the {@code uri} tag.
* @param contributors the contributors that will provide additional tags
* @since 2.3.0
*/
public DefaultWebFluxTagsProvider(boolean ignoreTrailingSlash, List<WebFluxTagsContributor> contributors) {
this.ignoreTrailingSlash = ignoreTrailingSlash;
this.contributors = contributors;
}
@Override
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable exception) {
Tags tags = Tags.empty();
tags = tags.and(WebFluxTags.method(exchange));
tags = tags.and(WebFluxTags.uri(exchange, this.ignoreTrailingSlash));
tags = tags.and(WebFluxTags.exception(exception));
tags = tags.and(WebFluxTags.status(exchange));
tags = tags.and(WebFluxTags.outcome(exchange, exception));
for (WebFluxTagsContributor contributor : this.contributors) {
tags = tags.and(contributor.httpRequestTags(exchange, exception));
}
return tags;
}
}

@ -1,191 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.server;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import io.micrometer.core.instrument.Tag;
import org.springframework.boot.actuate.metrics.http.Outcome;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
/**
* Factory methods for {@link Tag Tags} associated with a request-response exchange that
* is handled by WebFlux.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @author Michael McFadyen
* @author Brian Clozel
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public final class WebFluxTags {
private static final Tag URI_NOT_FOUND = Tag.of("uri", "NOT_FOUND");
private static final Tag URI_REDIRECTION = Tag.of("uri", "REDIRECTION");
private static final Tag URI_ROOT = Tag.of("uri", "root");
private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN");
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");
private static final Pattern FORWARD_SLASHES_PATTERN = Pattern.compile("//+");
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS = new HashSet<>(
Arrays.asList("AbortedException", "ClientAbortException", "EOFException", "EofException"));
private WebFluxTags() {
}
/**
* Creates a {@code method} tag based on the
* {@link org.springframework.http.server.reactive.ServerHttpRequest#getMethod()
* method} of the {@link ServerWebExchange#getRequest()} request of the given
* {@code exchange}.
* @param exchange the exchange
* @return the method tag whose value is a capitalized method (e.g. GET).
*/
public static Tag method(ServerWebExchange exchange) {
return Tag.of("method", exchange.getRequest().getMethod().name());
}
/**
* Creates a {@code status} tag based on the response status of the given
* {@code exchange}.
* @param exchange the exchange
* @return the status tag derived from the response status
*/
public static Tag status(ServerWebExchange exchange) {
HttpStatusCode status = exchange.getResponse().getStatusCode();
if (status == null) {
status = HttpStatus.OK;
}
return Tag.of("status", String.valueOf(status.value()));
}
/**
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND}
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN}
* for all other requests.
* @param exchange the exchange
* @return the uri tag derived from the exchange
*/
public static Tag uri(ServerWebExchange exchange) {
return uri(exchange, false);
}
/**
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND}
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN}
* for all other requests.
* @param exchange the exchange
* @param ignoreTrailingSlash whether to ignore the trailing slash
* @return the uri tag derived from the exchange
*/
public static Tag uri(ServerWebExchange exchange, boolean ignoreTrailingSlash) {
PathPattern pathPattern = exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (pathPattern != null) {
String patternString = pathPattern.getPatternString();
if (ignoreTrailingSlash && patternString.length() > 1) {
patternString = removeTrailingSlash(patternString);
}
if (patternString.isEmpty()) {
return URI_ROOT;
}
return Tag.of("uri", patternString);
}
HttpStatusCode status = exchange.getResponse().getStatusCode();
if (status != null) {
if (status.is3xxRedirection()) {
return URI_REDIRECTION;
}
if (status == HttpStatus.NOT_FOUND) {
return URI_NOT_FOUND;
}
}
String path = getPathInfo(exchange);
if (path.isEmpty()) {
return URI_ROOT;
}
return URI_UNKNOWN;
}
private static String getPathInfo(ServerWebExchange exchange) {
String path = exchange.getRequest().getPath().value();
String uri = StringUtils.hasText(path) ? path : "/";
String singleSlashes = FORWARD_SLASHES_PATTERN.matcher(uri).replaceAll("/");
return removeTrailingSlash(singleSlashes);
}
private static String removeTrailingSlash(String text) {
if (!StringUtils.hasLength(text)) {
return text;
}
return text.endsWith("/") ? text.substring(0, text.length() - 1) : text;
}
/**
* Creates an {@code exception} tag based on the {@link Class#getSimpleName() simple
* name} of the class of the given {@code exception}.
* @param exception the exception, may be {@code null}
* @return the exception tag derived from the exception
*/
public static Tag exception(Throwable exception) {
if (exception != null) {
String simpleName = exception.getClass().getSimpleName();
return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName : exception.getClass().getName());
}
return EXCEPTION_NONE;
}
/**
* Creates an {@code outcome} tag based on the response status of the given
* {@code exchange} and the exception thrown during request processing.
* @param exchange the exchange
* @param exception the termination signal sent by the publisher
* @return the outcome tag derived from the response status
* @since 2.5.0
*/
public static Tag outcome(ServerWebExchange exchange, Throwable exception) {
if (exception != null) {
if (DISCONNECTED_CLIENT_EXCEPTIONS.contains(exception.getClass().getSimpleName())) {
return Outcome.UNKNOWN.asTag();
}
}
HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
Outcome outcome = (statusCode != null) ? Outcome.forStatus(statusCode.value()) : Outcome.SUCCESS;
return outcome.asTag();
}
}

@ -1,44 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.server;
import io.micrometer.core.instrument.Tag;
import org.springframework.web.server.ServerWebExchange;
/**
* A contributor of {@link Tag Tags} for WebFlux-based request handling. Typically used by
* a {@link WebFluxTagsProvider} to provide tags in addition to its defaults.
*
* @author Andy Wilkinson
* @since 2.3.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention}
*/
@FunctionalInterface
@Deprecated(since = "3.0.0", forRemoval = true)
public interface WebFluxTagsContributor {
/**
* Provides tags to be associated with metrics for the given {@code exchange}.
* @param exchange the exchange
* @param ex the current exception (may be {@code null})
* @return tags to associate with metrics for the request and response exchange
*/
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex);
}

@ -1,44 +0,0 @@
/*
* 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.
* 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.metrics.web.reactive.server;
import io.micrometer.core.instrument.Tag;
import org.springframework.web.server.ServerWebExchange;
/**
* Provides {@link Tag Tags} for WebFlux-based request handling.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.reactive.observation.ServerRequestObservationConvention}
*/
@FunctionalInterface
@Deprecated(since = "3.0.0", forRemoval = true)
public interface WebFluxTagsProvider {
/**
* Provides tags to be associated with metrics for the given {@code exchange}.
* @param exchange the exchange
* @param ex the current exception (may be {@code null})
* @return tags to associate with metrics for the request and response exchange
*/
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex);
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2019 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.
*/
/**
* Actuator support for WebFlux metrics.
*/
package org.springframework.boot.actuate.metrics.web.reactive.server;

@ -1,94 +0,0 @@
/*
* 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.
* 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.metrics.web.servlet;
import java.util.Collections;
import java.util.List;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* Default implementation of {@link WebMvcTagsProvider}.
*
* @author Jon Schneider
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {
private final boolean ignoreTrailingSlash;
private final List<WebMvcTagsContributor> contributors;
public DefaultWebMvcTagsProvider() {
this(false);
}
/**
* Creates a new {@link DefaultWebMvcTagsProvider} that will provide tags from the
* given {@code contributors} in addition to its own.
* @param contributors the contributors that will provide additional tags
* @since 2.3.0
*/
public DefaultWebMvcTagsProvider(List<WebMvcTagsContributor> contributors) {
this(false, contributors);
}
public DefaultWebMvcTagsProvider(boolean ignoreTrailingSlash) {
this(ignoreTrailingSlash, Collections.emptyList());
}
/**
* Creates a new {@link DefaultWebMvcTagsProvider} that will provide tags from the
* given {@code contributors} in addition to its own.
* @param ignoreTrailingSlash whether trailing slashes should be ignored when
* determining the {@code uri} tag.
* @param contributors the contributors that will provide additional tags
* @since 2.3.0
*/
public DefaultWebMvcTagsProvider(boolean ignoreTrailingSlash, List<WebMvcTagsContributor> contributors) {
this.ignoreTrailingSlash = ignoreTrailingSlash;
this.contributors = contributors;
}
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response, this.ignoreTrailingSlash),
WebMvcTags.exception(exception), WebMvcTags.status(response), WebMvcTags.outcome(response));
for (WebMvcTagsContributor contributor : this.contributors) {
tags = tags.and(contributor.getTags(request, response, handler, exception));
}
return tags;
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
Tags tags = Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, null, this.ignoreTrailingSlash));
for (WebMvcTagsContributor contributor : this.contributors) {
tags = tags.and(contributor.getLongRequestTags(request, handler));
}
return tags;
}
}

@ -1,193 +0,0 @@
/*
* 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.
* 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.metrics.web.servlet;
import java.util.regex.Pattern;
import io.micrometer.core.instrument.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.metrics.http.Outcome;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.pattern.PathPattern;
/**
* Factory methods for {@link Tag Tags} associated with a request-response exchange that
* is handled by Spring MVC.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @author Brian Clozel
* @author Michael McFadyen
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public final class WebMvcTags {
private static final String DATA_REST_PATH_PATTERN_ATTRIBUTE = "org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.EFFECTIVE_REPOSITORY_RESOURCE_LOOKUP_PATH";
private static final Tag URI_NOT_FOUND = Tag.of("uri", "NOT_FOUND");
private static final Tag URI_REDIRECTION = Tag.of("uri", "REDIRECTION");
private static final Tag URI_ROOT = Tag.of("uri", "root");
private static final Tag URI_UNKNOWN = Tag.of("uri", "UNKNOWN");
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");
private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN");
private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN");
private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$");
private static final Pattern MULTIPLE_SLASH_PATTERN = Pattern.compile("//+");
private WebMvcTags() {
}
/**
* Creates a {@code method} tag based on the {@link HttpServletRequest#getMethod()
* method} of the given {@code request}.
* @param request the request
* @return the method tag whose value is a capitalized method (e.g. GET).
*/
public static Tag method(HttpServletRequest request) {
return (request != null) ? Tag.of("method", request.getMethod()) : METHOD_UNKNOWN;
}
/**
* Creates a {@code status} tag based on the status of the given {@code response}.
* @param response the HTTP response
* @return the status tag derived from the status of the response
*/
public static Tag status(HttpServletResponse response) {
return (response != null) ? Tag.of("status", Integer.toString(response.getStatus())) : STATUS_UNKNOWN;
}
/**
* Creates a {@code uri} tag based on the URI of the given {@code request}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND}
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN}
* for all other requests.
* @param request the request
* @param response the response
* @return the uri tag derived from the request
*/
public static Tag uri(HttpServletRequest request, HttpServletResponse response) {
return uri(request, response, false);
}
/**
* Creates a {@code uri} tag based on the URI of the given {@code request}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND}
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN}
* for all other requests.
* @param request the request
* @param response the response
* @param ignoreTrailingSlash whether to ignore the trailing slash
* @return the uri tag derived from the request
*/
public static Tag uri(HttpServletRequest request, HttpServletResponse response, boolean ignoreTrailingSlash) {
if (request != null) {
String pattern = getMatchingPattern(request);
if (pattern != null) {
if (ignoreTrailingSlash && pattern.length() > 1) {
pattern = TRAILING_SLASH_PATTERN.matcher(pattern).replaceAll("");
}
if (pattern.isEmpty()) {
return URI_ROOT;
}
return Tag.of("uri", pattern);
}
if (response != null) {
HttpStatus status = extractStatus(response);
if (status != null) {
if (status.is3xxRedirection()) {
return URI_REDIRECTION;
}
if (status == HttpStatus.NOT_FOUND) {
return URI_NOT_FOUND;
}
}
}
String pathInfo = getPathInfo(request);
if (pathInfo.isEmpty()) {
return URI_ROOT;
}
}
return URI_UNKNOWN;
}
private static HttpStatus extractStatus(HttpServletResponse response) {
try {
return HttpStatus.valueOf(response.getStatus());
}
catch (IllegalArgumentException ex) {
return null;
}
}
private static String getMatchingPattern(HttpServletRequest request) {
PathPattern dataRestPathPattern = (PathPattern) request.getAttribute(DATA_REST_PATH_PATTERN_ATTRIBUTE);
if (dataRestPathPattern != null) {
return dataRestPathPattern.getPatternString();
}
return (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
}
private static String getPathInfo(HttpServletRequest request) {
String pathInfo = request.getPathInfo();
String uri = StringUtils.hasText(pathInfo) ? pathInfo : "/";
uri = MULTIPLE_SLASH_PATTERN.matcher(uri).replaceAll("/");
return TRAILING_SLASH_PATTERN.matcher(uri).replaceAll("");
}
/**
* Creates an {@code exception} tag based on the {@link Class#getSimpleName() simple
* name} of the class of the given {@code exception}.
* @param exception the exception, may be {@code null}
* @return the exception tag derived from the exception
*/
public static Tag exception(Throwable exception) {
if (exception != null) {
String simpleName = exception.getClass().getSimpleName();
return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName : exception.getClass().getName());
}
return EXCEPTION_NONE;
}
/**
* Creates an {@code outcome} tag based on the status of the given {@code response}.
* @param response the HTTP response
* @return the outcome tag derived from the status of the response
* @since 2.1.0
*/
public static Tag outcome(HttpServletResponse response) {
Outcome outcome = (response != null) ? Outcome.forStatus(response.getStatus()) : Outcome.UNKNOWN;
return outcome.asTag();
}
}

@ -1,58 +0,0 @@
/*
* 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.
* 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.metrics.web.servlet;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* A contributor of {@link Tag Tags} for Spring MVC-based request handling. Typically used
* by a {@link WebMvcTagsProvider} to provide tags in addition to its defaults.
*
* @author Andy Wilkinson
* @since 2.3.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public interface WebMvcTagsContributor {
/**
* Provides tags to be associated with metrics for the given {@code request} and
* {@code response} exchange.
* @param request the request
* @param response the response
* @param handler the handler for the request or {@code null} if the handler is
* unknown
* @param exception the current exception, if any
* @return tags to associate with metrics for the request and response exchange
*/
Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception);
/**
* Provides tags to be used by {@link LongTaskTimer long task timers}.
* @param request the HTTP request
* @param handler the handler for the request or {@code null} if the handler is
* unknown
* @return tags to associate with metrics recorded for the request
*/
Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler);
}

@ -1,58 +0,0 @@
/*
* 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.
* 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.metrics.web.servlet;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* Provides {@link Tag Tags} for Spring MVC-based request handling.
*
* @author Jon Schneider
* @author Andy Wilkinson
* @since 2.0.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.http.server.observation.ServerRequestObservationConvention}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public interface WebMvcTagsProvider {
/**
* Provides tags to be associated with metrics for the given {@code request} and
* {@code response} exchange.
* @param request the request
* @param response the response
* @param handler the handler for the request or {@code null} if the handler is
* unknown
* @param exception the current exception, if any
* @return tags to associate with metrics for the request and response exchange
*/
Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception);
/**
* Provides tags to be used by {@link LongTaskTimer long task timers}.
* @param request the HTTP request
* @param handler the handler for the request or {@code null} if the handler is
* unknown
* @return tags to associate with metrics recorded for the request
*/
Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler);
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2019 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.
*/
/**
* Actuator support for Spring MVC metrics.
*/
package org.springframework.boot.actuate.metrics.web.servlet;

@ -1,120 +0,0 @@
/*
* Copyright 2012-2023 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.web.servlet;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import io.micrometer.core.instrument.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsContributor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DefaultWebMvcTagsProvider}.
*
* @author Andy Wilkinson
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class DefaultWebMvcTagsProviderTests {
@Test
void whenTagsAreProvidedThenDefaultTagsArePresent() {
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getTags(null, null, null, null));
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri");
}
@Test
void givenSomeContributorsWhenTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() {
Map<String, Tag> tags = asMap(
new DefaultWebMvcTagsProvider(Arrays.asList(new TestWebMvcTagsContributor("alpha"),
new TestWebMvcTagsContributor("bravo", "charlie")))
.getTags(null, null, null, null));
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri", "alpha", "bravo",
"charlie");
}
@Test
void whenLongRequestTagsAreProvidedThenDefaultTagsArePresent() {
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getLongRequestTags(null, null));
assertThat(tags).containsOnlyKeys("method", "uri");
}
@Test
void givenSomeContributorsWhenLongRequestTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() {
Map<String, Tag> tags = asMap(
new DefaultWebMvcTagsProvider(Arrays.asList(new TestWebMvcTagsContributor("alpha"),
new TestWebMvcTagsContributor("bravo", "charlie")))
.getLongRequestTags(null, null));
assertThat(tags).containsOnlyKeys("method", "uri", "alpha", "bravo", "charlie");
}
@Test
void trailingSlashIsIncludedByDefault() {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/the/uri/");
request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "{one}/{two}/");
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider().getTags(request, null, null, null));
assertThat(tags.get("uri").getValue()).isEqualTo("{one}/{two}/");
}
@Test
void trailingSlashCanBeIgnored() {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/the/uri/");
request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "{one}/{two}/");
Map<String, Tag> tags = asMap(new DefaultWebMvcTagsProvider(true).getTags(request, null, null, null));
assertThat(tags.get("uri").getValue()).isEqualTo("{one}/{two}");
}
private Map<String, Tag> asMap(Iterable<Tag> tags) {
return StreamSupport.stream(tags.spliterator(), false)
.collect(Collectors.toMap(Tag::getKey, Function.identity()));
}
private static final class TestWebMvcTagsContributor implements WebMvcTagsContributor {
private final List<String> tagNames;
private TestWebMvcTagsContributor(String... tagNames) {
this.tagNames = Arrays.asList(tagNames);
}
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList();
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList();
}
}
}

@ -1,184 +0,0 @@
/*
* 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.
* 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.web.servlet;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTags;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebMvcTags}.
*
* @author Andy Wilkinson
* @author Brian Clozel
* @author Michael McFadyen
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class WebMvcTagsTests {
private final MockHttpServletRequest request = new MockHttpServletRequest();
private final MockHttpServletResponse response = new MockHttpServletResponse();
@Test
void uriTagIsDataRestsEffectiveRepositoryLookupPathWhenAvailable() {
this.request.setAttribute(
"org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.EFFECTIVE_REPOSITORY_RESOURCE_LOOKUP_PATH",
new PathPatternParser().parse("/api/cities"));
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/api/{repository}");
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("/api/cities");
}
@Test
void uriTagValueIsBestMatchingPatternWhenAvailable() {
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/spring/");
this.response.setStatus(301);
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("/spring/");
}
@Test
void uriTagValueIsRootWhenBestMatchingPatternIsEmpty() {
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "");
this.response.setStatus(301);
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashRemoveTrailingSlash() {
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/spring/");
Tag tag = WebMvcTags.uri(this.request, this.response, true);
assertThat(tag.getValue()).isEqualTo("/spring");
}
@Test
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashKeepSingleSlash() {
this.request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/");
Tag tag = WebMvcTags.uri(this.request, this.response, true);
assertThat(tag.getValue()).isEqualTo("/");
}
@Test
void uriTagValueIsRootWhenRequestHasNoPatternOrPathInfo() {
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("root");
}
@Test
void uriTagValueIsRootWhenRequestHasNoPatternAndSlashPathInfo() {
this.request.setPathInfo("/");
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("root");
}
@Test
void uriTagValueIsUnknownWhenRequestHasNoPatternAndNonRootPathInfo() {
this.request.setPathInfo("/example");
assertThat(WebMvcTags.uri(this.request, null).getValue()).isEqualTo("UNKNOWN");
}
@Test
void uriTagValueIsRedirectionWhenResponseStatusIs3xx() {
this.response.setStatus(301);
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void uriTagValueIsNotFoundWhenResponseStatusIs404() {
this.response.setStatus(404);
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("NOT_FOUND");
}
@Test
void uriTagToleratesCustomResponseStatus() {
this.response.setStatus(601);
Tag tag = WebMvcTags.uri(this.request, this.response);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagIsUnknownWhenRequestIsNull() {
Tag tag = WebMvcTags.uri(null, null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsUnknownWhenResponseIsNull() {
Tag tag = WebMvcTags.outcome(null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsInformationalWhenResponseIs1xx() {
this.response.setStatus(100);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}
@Test
void outcomeTagIsSuccessWhenResponseIs2xx() {
this.response.setStatus(200);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsRedirectionWhenResponseIs3xx() {
this.response.setStatus(301);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void outcomeTagIsClientErrorWhenResponseIs4xx() {
this.response.setStatus(400);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() {
this.response.setStatus(490);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsServerErrorWhenResponseIs5xx() {
this.response.setStatus(500);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}
@Test
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() {
this.response.setStatus(701);
Tag tag = WebMvcTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
}

@ -140,18 +140,6 @@ class PrometheusPushGatewayManagerTests {
then(otherScheduler).should(never()).shutdown(); then(otherScheduler).should(never()).shutdown();
} }
@Test
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
void shutdownWhenShutdownOperationIsPushPerformsPushAddOnShutdown() throws Exception {
givenScheduleAtFixedRateWithReturnFuture();
PrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, this.registry,
this.scheduler, this.pushRate, "job", this.groupingKey, ShutdownOperation.PUSH);
manager.shutdown();
then(this.future).should().cancel(false);
then(this.pushGateway).should().pushAdd(this.registry, "job", this.groupingKey);
}
@Test @Test
void shutdownWhenShutdownOperationIsPostPerformsPushAddOnShutdown() throws Exception { void shutdownWhenShutdownOperationIsPostPerformsPushAddOnShutdown() throws Exception {
givenScheduleAtFixedRateWithReturnFuture(); givenScheduleAtFixedRateWithReturnFuture();

@ -1,118 +0,0 @@
/*
* 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.
* 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.metrics.web.client;
import java.io.IOException;
import java.net.URI;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link RestTemplateExchangeTags}.
*
* @author Nishant Raut
* @author Brian Clozel
*/
@SuppressWarnings({ "removal" })
@Deprecated(since = "3.0.0", forRemoval = true)
class RestTemplateExchangeTagsTests {
@Test
void outcomeTagIsUnknownWhenResponseIsNull() {
Tag tag = RestTemplateExchangeTags.outcome(null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsInformationalWhenResponseIs1xx() {
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.CONTINUE);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}
@Test
void outcomeTagIsSuccessWhenResponseIs2xx() {
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.OK);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsRedirectionWhenResponseIs3xx() {
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.MOVED_PERMANENTLY);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void outcomeTagIsClientErrorWhenResponseIs4xx() {
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.BAD_REQUEST);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsServerErrorWhenResponseIs5xx() {
ClientHttpResponse response = new MockClientHttpResponse("foo".getBytes(), HttpStatus.BAD_GATEWAY);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}
@Test
void outcomeTagIsUnknownWhenResponseThrowsIOException() throws Exception {
ClientHttpResponse response = mock(ClientHttpResponse.class);
given(response.getStatusCode()).willThrow(IOException.class);
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() throws IOException {
ClientHttpResponse response = mock(ClientHttpResponse.class);
given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(490));
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() throws IOException {
ClientHttpResponse response = mock(ClientHttpResponse.class);
given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(701));
Tag tag = RestTemplateExchangeTags.outcome(response);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void clientNameTagIsHostOfRequestUri() {
ClientHttpRequest request = mock(ClientHttpRequest.class);
given(request.getURI()).willReturn(URI.create("https://example.org"));
Tag tag = RestTemplateExchangeTags.clientName(request);
assertThat(tag).isEqualTo(Tag.of("client.name", "example.org"));
}
}

@ -1,100 +0,0 @@
/*
* Copyright 2012-2023 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.metrics.web.reactive.client;
import java.io.IOException;
import java.net.URI;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DefaultWebClientExchangeTagsProvider}
*
* @author Brian Clozel
* @author Nishant Raut
*/
@SuppressWarnings({ "deprecation", "removal" })
class DefaultWebClientExchangeTagsProviderTests {
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
private final WebClientExchangeTagsProvider tagsProvider = new DefaultWebClientExchangeTagsProvider();
private ClientRequest request;
private ClientResponse response;
@BeforeEach
void setup() {
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot"))
.attribute(URI_TEMPLATE_ATTRIBUTE, "https://example.org/projects/{project}")
.build();
this.response = mock(ClientResponse.class);
given(this.response.statusCode()).willReturn(HttpStatus.OK);
}
@Test
void tagsShouldBePopulated() {
Iterable<Tag> tags = this.tagsProvider.tags(this.request, this.response, null);
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"),
Tag.of("client.name", "example.org"), Tag.of("status", "200"), Tag.of("outcome", "SUCCESS"));
}
@Test
void tagsWhenNoUriTemplateShouldProvideUriPath() {
ClientRequest request = ClientRequest
.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot"))
.build();
Iterable<Tag> tags = this.tagsProvider.tags(request, this.response, null);
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/spring-boot"),
Tag.of("client.name", "example.org"), Tag.of("status", "200"), Tag.of("outcome", "SUCCESS"));
}
@Test
void tagsWhenIoExceptionShouldReturnIoErrorStatus() {
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, new IOException());
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"),
Tag.of("client.name", "example.org"), Tag.of("status", "IO_ERROR"), Tag.of("outcome", "UNKNOWN"));
}
@Test
void tagsWhenExceptionShouldReturnClientErrorStatus() {
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, new IllegalArgumentException());
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"),
Tag.of("client.name", "example.org"), Tag.of("status", "CLIENT_ERROR"), Tag.of("outcome", "UNKNOWN"));
}
@Test
void tagsWhenCancelledRequestShouldReturnClientErrorStatus() {
Iterable<Tag> tags = this.tagsProvider.tags(this.request, null, null);
assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"),
Tag.of("client.name", "example.org"), Tag.of("status", "CLIENT_ERROR"), Tag.of("outcome", "UNKNOWN"));
}
}

@ -1,182 +0,0 @@
/*
* Copyright 2012-2023 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.metrics.web.reactive.client;
import java.io.IOException;
import java.net.URI;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link WebClientExchangeTags}.
*
* @author Brian Clozel
* @author Nishant Raut
*/
@SuppressWarnings({ "deprecation", "removal" })
class WebClientExchangeTagsTests {
private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
private ClientRequest request;
private ClientResponse response;
@BeforeEach
void setup() {
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot"))
.attribute(URI_TEMPLATE_ATTRIBUTE, "https://example.org/projects/{project}")
.build();
this.response = mock(ClientResponse.class);
}
@Test
void method() {
assertThat(WebClientExchangeTags.method(this.request)).isEqualTo(Tag.of("method", "GET"));
}
@Test
void uriWhenAbsoluteTemplateIsAvailableShouldReturnTemplate() {
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/{project}"));
}
@Test
void uriWhenRelativeTemplateIsAvailableShouldReturnTemplate() {
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot"))
.attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}")
.build();
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/{project}"));
}
@Test
void uriWhenTemplateIsMissingShouldReturnPath() {
this.request = ClientRequest.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot"))
.build();
assertThat(WebClientExchangeTags.uri(this.request)).isEqualTo(Tag.of("uri", "/projects/spring-boot"));
}
@Test
void uriWhenTemplateIsMissingShouldReturnPathWithQueryParams() {
this.request = ClientRequest
.create(HttpMethod.GET, URI.create("https://example.org/projects/spring-boot?section=docs"))
.build();
assertThat(WebClientExchangeTags.uri(this.request))
.isEqualTo(Tag.of("uri", "/projects/spring-boot?section=docs"));
}
@Test
void clientName() {
assertThat(WebClientExchangeTags.clientName(this.request)).isEqualTo(Tag.of("client.name", "example.org"));
}
@Test
void status() {
given(this.response.statusCode()).willReturn(HttpStatus.OK);
assertThat(WebClientExchangeTags.status(this.response, null)).isEqualTo(Tag.of("status", "200"));
}
@Test
void statusWhenIOException() {
assertThat(WebClientExchangeTags.status(null, new IOException())).isEqualTo(Tag.of("status", "IO_ERROR"));
}
@Test
void statusWhenClientException() {
assertThat(WebClientExchangeTags.status(null, new IllegalArgumentException()))
.isEqualTo(Tag.of("status", "CLIENT_ERROR"));
}
@Test
void statusWhenNonStandard() {
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(490));
assertThat(WebClientExchangeTags.status(this.response, null)).isEqualTo(Tag.of("status", "490"));
}
@Test
void statusWhenCancelled() {
assertThat(WebClientExchangeTags.status(null, null)).isEqualTo(Tag.of("status", "CLIENT_ERROR"));
}
@Test
void outcomeTagIsUnknownWhenResponseIsNull() {
Tag tag = WebClientExchangeTags.outcome(null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsInformationalWhenResponseIs1xx() {
given(this.response.statusCode()).willReturn(HttpStatus.CONTINUE);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}
@Test
void outcomeTagIsSuccessWhenResponseIs2xx() {
given(this.response.statusCode()).willReturn(HttpStatus.OK);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsRedirectionWhenResponseIs3xx() {
given(this.response.statusCode()).willReturn(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void outcomeTagIsClientErrorWhenResponseIs4xx() {
given(this.response.statusCode()).willReturn(HttpStatus.BAD_REQUEST);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsServerErrorWhenResponseIs5xx() {
given(this.response.statusCode()).willReturn(HttpStatus.BAD_GATEWAY);
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}
@Test
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() {
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(490));
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() {
given(this.response.statusCode()).willReturn(HttpStatusCode.valueOf(701));
Tag tag = WebClientExchangeTags.outcome(this.response);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
}

@ -1,82 +0,0 @@
/*
* Copyright 2012-2023 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.metrics.web.reactive.server;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DefaultWebFluxTagsProvider}.
*
* @author Andy Wilkinson
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class DefaultWebFluxTagsProviderTests {
@Test
void whenTagsAreProvidedThenDefaultTagsArePresent() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test"));
Map<String, Tag> tags = asMap(new DefaultWebFluxTagsProvider().httpRequestTags(exchange, null));
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri");
}
@Test
void givenSomeContributorsWhenTagsAreProvidedThenDefaultTagsAndContributedTagsArePresent() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test"));
Map<String, Tag> tags = asMap(
new DefaultWebFluxTagsProvider(Arrays.asList(new TestWebFluxTagsContributor("alpha"),
new TestWebFluxTagsContributor("bravo", "charlie")))
.httpRequestTags(exchange, null));
assertThat(tags).containsOnlyKeys("exception", "method", "outcome", "status", "uri", "alpha", "bravo",
"charlie");
}
private Map<String, Tag> asMap(Iterable<Tag> tags) {
return StreamSupport.stream(tags.spliterator(), false)
.collect(Collectors.toMap(Tag::getKey, Function.identity()));
}
private static final class TestWebFluxTagsContributor implements WebFluxTagsContributor {
private final List<String> tagNames;
private TestWebFluxTagsContributor(String... tagNames) {
this.tagNames = Arrays.asList(tagNames);
}
@Override
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
return this.tagNames.stream().map((name) -> Tag.of(name, "value")).toList();
}
}
}

@ -1,220 +0,0 @@
/*
* Copyright 2012-2023 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.metrics.web.reactive.server;
import java.io.EOFException;
import io.micrometer.core.instrument.Tag;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link WebFluxTags}.
*
* @author Brian Clozel
* @author Michael McFadyen
* @author Madhura Bhave
* @author Stephane Nicoll
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
class WebFluxTagsTests {
private MockServerWebExchange exchange;
private final PathPatternParser parser = new PathPatternParser();
@BeforeEach
void setup() {
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get(""));
}
@Test
void uriTagValueIsBestMatchingPatternWhenAvailable() {
this.exchange.getAttributes()
.put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/spring/"));
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("/spring/");
}
@Test
void uriTagValueIsRootWhenBestMatchingPatternIsEmpty() {
this.exchange.getAttributes().put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse(""));
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashRemoveTrailingSlash() {
this.exchange.getAttributes()
.put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/spring/"));
Tag tag = WebFluxTags.uri(this.exchange, true);
assertThat(tag.getValue()).isEqualTo("/spring");
}
@Test
void uriTagValueWithBestMatchingPatternAndIgnoreTrailingSlashKeepSingleSlash() {
this.exchange.getAttributes().put(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/"));
Tag tag = WebFluxTags.uri(this.exchange, true);
assertThat(tag.getValue()).isEqualTo("/");
}
@Test
void uriTagValueIsRedirectionWhenResponseStatusIs3xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void uriTagValueIsNotFoundWhenResponseStatusIs404() {
this.exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("NOT_FOUND");
}
@Test
void uriTagToleratesCustomResponseStatus() {
this.exchange.getResponse().setRawStatusCode(601);
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagValueIsRootWhenRequestHasNoPatternOrPathInfo() {
Tag tag = WebFluxTags.uri(this.exchange);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagValueIsRootWhenRequestHasNoPatternAndSlashPathInfo() {
MockServerHttpRequest request = MockServerHttpRequest.get("/").build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
Tag tag = WebFluxTags.uri(exchange);
assertThat(tag.getValue()).isEqualTo("root");
}
@Test
void uriTagValueIsUnknownWhenRequestHasNoPatternAndNonRootPathInfo() {
MockServerHttpRequest request = MockServerHttpRequest.get("/example").build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
Tag tag = WebFluxTags.uri(exchange);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void methodTagToleratesNonStandardHttpMethods() {
ServerWebExchange exchange = mock(ServerWebExchange.class);
ServerHttpRequest request = mock(ServerHttpRequest.class);
given(exchange.getRequest()).willReturn(request);
given(request.getMethod()).willReturn(HttpMethod.valueOf("CUSTOM"));
Tag tag = WebFluxTags.method(exchange);
assertThat(tag.getValue()).isEqualTo("CUSTOM");
}
@Test
void outcomeTagIsSuccessWhenResponseStatusIsNull() {
this.exchange.getResponse().setStatusCode(null);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsSuccessWhenResponseStatusIsAvailableFromUnderlyingServer() {
ServerWebExchange exchange = mock(ServerWebExchange.class);
ServerHttpRequest request = mock(ServerHttpRequest.class);
ServerHttpResponse response = mock(ServerHttpResponse.class);
given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getStatusCode().value()).willReturn(null);
given(exchange.getRequest()).willReturn(request);
given(exchange.getResponse()).willReturn(response);
Tag tag = WebFluxTags.outcome(exchange, null);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsInformationalWhenResponseIs1xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.CONTINUE);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
}
@Test
void outcomeTagIsSuccessWhenResponseIs2xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.OK);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("SUCCESS");
}
@Test
void outcomeTagIsRedirectionWhenResponseIs3xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
}
@Test
void outcomeTagIsClientErrorWhenResponseIs4xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsServerErrorWhenResponseIs5xx() {
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
}
@Test
void outcomeTagIsClientErrorWhenResponseIsNonStandardInClientSeries() {
this.exchange.getResponse().setRawStatusCode(490);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
}
@Test
void outcomeTagIsUnknownWhenResponseStatusIsInUnknownSeries() {
this.exchange.getResponse().setRawStatusCode(701);
Tag tag = WebFluxTags.outcome(this.exchange, null);
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
@Test
void outcomeTagIsUnknownWhenExceptionIsDisconnectedClient() {
Tag tag = WebFluxTags.outcome(this.exchange, new EOFException("broken pipe"));
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
}
}

@ -127,16 +127,6 @@ public class FlywayAutoConfiguration {
return new PropertiesFlywayConnectionDetails(properties); return new PropertiesFlywayConnectionDetails(properties);
} }
@Deprecated(since = "3.0.0", forRemoval = true)
public Flyway flyway(FlywayProperties properties, ResourceLoader resourceLoader,
ObjectProvider<DataSource> dataSource, ObjectProvider<DataSource> flywayDataSource,
ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks) {
return flyway(properties, new PropertiesFlywayConnectionDetails(properties), resourceLoader, dataSource,
flywayDataSource, fluentConfigurationCustomizers, javaMigrations, callbacks,
new ResourceProviderCustomizer());
}
@Bean @Bean
Flyway flyway(FlywayProperties properties, FlywayConnectionDetails connectionDetails, Flyway flyway(FlywayProperties properties, FlywayConnectionDetails connectionDetails,
ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource, ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource,

@ -22,7 +22,6 @@ import java.util.Map;
import liquibase.integration.spring.SpringLiquibase; import liquibase.integration.spring.SpringLiquibase;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -257,17 +256,6 @@ public class LiquibaseProperties {
this.labelFilter = labelFilter; this.labelFilter = labelFilter;
} }
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(replacement = "spring.liquibase.label-filter")
public String getLabels() {
return getLabelFilter();
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setLabels(String labels) {
setLabelFilter(labels);
}
public Map<String, String> getParameters() { public Map<String, String> getParameters() {
return this.parameters; return this.parameters;
} }

@ -41,8 +41,8 @@ import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.Cookie.SameSite; import org.springframework.boot.web.server.Cookie.SameSite;
import org.springframework.boot.web.servlet.server.Session.Cookie;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

@ -154,17 +154,6 @@ public class ServerProperties {
this.serverHeader = serverHeader; this.serverHeader = serverHeader;
} }
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty
public DataSize getMaxHttpHeaderSize() {
return getMaxHttpRequestHeaderSize();
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setMaxHttpHeaderSize(DataSize maxHttpHeaderSize) {
setMaxHttpRequestHeaderSize(maxHttpHeaderSize);
}
public DataSize getMaxHttpRequestHeaderSize() { public DataSize getMaxHttpRequestHeaderSize() {
return this.maxHttpRequestHeaderSize; return this.maxHttpRequestHeaderSize;
} }
@ -475,7 +464,7 @@ public class ServerProperties {
/** /**
* Whether to reject requests with illegal header names or values. * Whether to reject requests with illegal header names or values.
*/ */
@Deprecated(since = "2.7.12", forRemoval = true) @Deprecated(since = "2.7.12", forRemoval = true) // Remove in 3.3
private boolean rejectIllegalHeader = true; private boolean rejectIllegalHeader = true;
/** /**
@ -1409,11 +1398,6 @@ public class ServerProperties {
*/ */
private DataSize initialBufferSize = DataSize.ofBytes(128); private DataSize initialBufferSize = DataSize.ofBytes(128);
/**
* Maximum chunk size that can be decoded for an HTTP request.
*/
private DataSize maxChunkSize = DataSize.ofKilobytes(8);
/** /**
* Maximum length that can be decoded for an HTTP request's initial line. * Maximum length that can be decoded for an HTTP request's initial line.
*/ */
@ -1460,17 +1444,6 @@ public class ServerProperties {
this.initialBufferSize = initialBufferSize; this.initialBufferSize = initialBufferSize;
} }
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(reason = "Deprecated for removal in Reactor Netty")
public DataSize getMaxChunkSize() {
return this.maxChunkSize;
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setMaxChunkSize(DataSize maxChunkSize) {
this.maxChunkSize = maxChunkSize;
}
public DataSize getMaxInitialLineLength() { public DataSize getMaxInitialLineLength() {
return this.maxInitialLineLength; return this.maxInitialLineLength;
} }

@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.web.embedded;
import java.time.Duration; import java.time.Duration;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import reactor.netty.http.server.HttpRequestDecoderSpec;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.cloud.CloudPlatform; import org.springframework.boot.cloud.CloudPlatform;
@ -87,7 +86,6 @@ public class NettyWebServerFactoryCustomizer
.to((maxHttpRequestHeader) -> httpRequestDecoderSpec .to((maxHttpRequestHeader) -> httpRequestDecoderSpec
.maxHeaderSize((int) maxHttpRequestHeader.toBytes())); .maxHeaderSize((int) maxHttpRequestHeader.toBytes()));
ServerProperties.Netty nettyProperties = this.serverProperties.getNetty(); ServerProperties.Netty nettyProperties = this.serverProperties.getNetty();
maxChunkSize(propertyMapper, httpRequestDecoderSpec, nettyProperties);
propertyMapper.from(nettyProperties.getMaxInitialLineLength()) propertyMapper.from(nettyProperties.getMaxInitialLineLength())
.whenNonNull() .whenNonNull()
.to((maxInitialLineLength) -> httpRequestDecoderSpec .to((maxInitialLineLength) -> httpRequestDecoderSpec
@ -106,14 +104,6 @@ public class NettyWebServerFactoryCustomizer
})); }));
} }
@SuppressWarnings({ "deprecation", "removal" })
private void maxChunkSize(PropertyMapper propertyMapper, HttpRequestDecoderSpec httpRequestDecoderSpec,
ServerProperties.Netty nettyProperties) {
propertyMapper.from(nettyProperties.getMaxChunkSize())
.whenNonNull()
.to((maxChunkSize) -> httpRequestDecoderSpec.maxChunkSize((int) maxChunkSize.toBytes()));
}
private void customizeIdleTimeout(NettyReactiveWebServerFactory factory, Duration idleTimeout) { private void customizeIdleTimeout(NettyReactiveWebServerFactory factory, Duration idleTimeout) {
factory.addServerCustomizers((httpServer) -> httpServer.idleTimeout(idleTimeout)); factory.addServerCustomizers((httpServer) -> httpServer.idleTimeout(idleTimeout));
} }

@ -31,7 +31,6 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -403,24 +402,6 @@ public class WebMvcAutoConfiguration {
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
conversionService, validator);
setIgnoreDefaultModelOnRedirect(adapter);
return adapter;
}
@SuppressWarnings({ "deprecation", "removal" })
private void setIgnoreDefaultModelOnRedirect(RequestMappingHandlerAdapter adapter) {
adapter.setIgnoreDefaultModelOnRedirect(
this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
}
@Override @Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.mvcRegistrations != null) { if (this.mvcRegistrations != null) {

@ -21,7 +21,6 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.DefaultMessageCodesResolver;
@ -57,12 +56,6 @@ public class WebMvcProperties {
*/ */
private boolean dispatchOptionsRequest = true; private boolean dispatchOptionsRequest = true;
/**
* Whether the content of the "default" model should be ignored during redirect
* scenarios.
*/
private boolean ignoreDefaultModelOnRedirect = true;
/** /**
* Whether to publish a ServletRequestHandledEvent at the end of each request. * Whether to publish a ServletRequestHandledEvent at the end of each request.
*/ */
@ -120,17 +113,6 @@ public class WebMvcProperties {
return this.format; return this.format;
} }
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty(reason = "Deprecated for removal in Spring MVC")
public boolean isIgnoreDefaultModelOnRedirect() {
return this.ignoreDefaultModelOnRedirect;
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {
this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
}
public boolean isPublishRequestHandledEvents() { public boolean isPublishRequestHandledEvents() {
return this.publishRequestHandledEvents; return this.publishRequestHandledEvents;
} }

@ -115,6 +115,13 @@
"level": "error" "level": "error"
} }
}, },
{
"name": "server.max-http-header-size",
"deprecation": {
"replacement": "server.max-http-request-header-size",
"level": "error"
}
},
{ {
"name": "server.max-http-post-size", "name": "server.max-http-post-size",
"type": "java.lang.Integer", "type": "java.lang.Integer",
@ -125,6 +132,13 @@
"level": "error" "level": "error"
} }
}, },
{
"name": "server.netty.max-chunk-size",
"deprecation": {
"reason": "Deprecated for removal in Reactor Netty.",
"level": "error"
}
},
{ {
"name": "server.port", "name": "server.port",
"defaultValue": 8080 "defaultValue": 8080
@ -210,7 +224,10 @@
}, },
{ {
"name": "server.servlet.session.cookie.comment", "name": "server.servlet.session.cookie.comment",
"description": "Comment for the cookie." "description": "Comment for the cookie.",
"deprecation": {
"level": "error"
}
}, },
{ {
"name": "server.servlet.session.cookie.domain", "name": "server.servlet.session.cookie.domain",
@ -2043,6 +2060,13 @@
"level": "error" "level": "error"
} }
}, },
{
"name": "spring.liquibase.labels",
"deprecation": {
"replacement": "spring.liquibase.label-filter",
"level": "error"
}
},
{ {
"name": "spring.mail.test-connection", "name": "spring.mail.test-connection",
"description": "Whether to test that the mail server is available on startup.", "description": "Whether to test that the mail server is available on startup.",
@ -2105,6 +2129,13 @@
"description": "Whether to enable Spring's HiddenHttpMethodFilter.", "description": "Whether to enable Spring's HiddenHttpMethodFilter.",
"defaultValue": false "defaultValue": false
}, },
{
"name": "spring.mvc.ignore-default-model-on-redirect",
"deprecation": {
"reason": "Deprecated for removal in Spring MVC.",
"level": "error"
}
},
{ {
"name": "spring.mvc.locale", "name": "spring.mvc.locale",
"type": "java.util.Locale", "type": "java.util.Locale",

@ -379,14 +379,6 @@ class LiquibaseAutoConfigurationTests {
.run(assertLiquibase((liquibase) -> assertThat(liquibase.getLabelFilter()).isEqualTo("test, production"))); .run(assertLiquibase((liquibase) -> assertThat(liquibase.getLabelFilter()).isEqualTo("test, production")));
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
void overrideLabelFilterWithDeprecatedLabelsProperty() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.liquibase.labels:test, production")
.run(assertLiquibase((liquibase) -> assertThat(liquibase.getLabelFilter()).isEqualTo("test, production")));
}
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
void testOverrideParameters() { void testOverrideParameters() {

@ -205,24 +205,6 @@ class ServerPropertiesTests {
assertThat(this.properties.getTomcat().getUriEncoding()).isEqualTo(StandardCharsets.US_ASCII); assertThat(this.properties.getTomcat().getUriEncoding()).isEqualTo(StandardCharsets.US_ASCII);
} }
@Test
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
void testCustomizeHeaderSize() {
bind("server.max-http-header-size", "1MB");
assertThat(this.properties.getMaxHttpHeaderSize()).isEqualTo(DataSize.ofMegabytes(1));
assertThat(this.properties.getMaxHttpRequestHeaderSize()).isEqualTo(DataSize.ofMegabytes(1));
}
@Test
@SuppressWarnings("removal")
@Deprecated(since = "3.0.0", forRemoval = true)
void testCustomizeHeaderSizeUseBytesByDefault() {
bind("server.max-http-header-size", "1024");
assertThat(this.properties.getMaxHttpHeaderSize()).isEqualTo(DataSize.ofKilobytes(1));
assertThat(this.properties.getMaxHttpRequestHeaderSize()).isEqualTo(DataSize.ofKilobytes(1));
}
@Test @Test
void testCustomizeMaxHttpRequestHeaderSize() { void testCustomizeMaxHttpRequestHeaderSize() {
bind("server.max-http-request-header-size", "1MB"); bind("server.max-http-request-header-size", "1MB");
@ -538,14 +520,6 @@ class ServerPropertiesTests {
.isEqualTo(UndertowOptions.DEFAULT_MAX_ENTITY_SIZE); .isEqualTo(UndertowOptions.DEFAULT_MAX_ENTITY_SIZE);
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
void nettyMaxChunkSizeMatchesHttpDecoderSpecDefault() {
assertThat(this.properties.getNetty().getMaxChunkSize().toBytes())
.isEqualTo(HttpDecoderSpec.DEFAULT_MAX_CHUNK_SIZE);
}
@Test @Test
void nettyMaxInitialLineLengthMatchesHttpDecoderSpecDefault() { void nettyMaxInitialLineLengthMatchesHttpDecoderSpecDefault() {
assertThat(this.properties.getNetty().getMaxInitialLineLength().toBytes()) assertThat(this.properties.getNetty().getMaxInitialLineLength().toBytes())

@ -263,30 +263,6 @@ class JettyWebServerFactoryCustomizerTests {
then(factory).should().setUseForwardHeaders(true); then(factory).should().setUseForwardHeaders(true);
} }
@Test
void customizeMaxHttpHeaderSize() {
bind("server.max-http-header-size=2048");
JettyWebServer server = customizeAndGetServer();
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
assertThat(requestHeaderSizes).containsOnly(2048);
}
@Test
void customMaxHttpHeaderSizeIgnoredIfNegative() {
bind("server.max-http-header-size=-1");
JettyWebServer server = customizeAndGetServer();
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
assertThat(requestHeaderSizes).containsOnly(8192);
}
@Test
void customMaxHttpHeaderSizeIgnoredIfZero() {
bind("server.max-http-header-size=0");
JettyWebServer server = customizeAndGetServer();
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
assertThat(requestHeaderSizes).containsOnly(8192);
}
@Test @Test
void customizeMaxRequestHttpHeaderSize() { void customizeMaxRequestHttpHeaderSize() {
bind("server.max-http-request-header-size=2048"); bind("server.max-http-request-header-size=2048");

@ -132,7 +132,6 @@ class NettyWebServerFactoryCustomizerTests {
nettyProperties.setValidateHeaders(false); nettyProperties.setValidateHeaders(false);
nettyProperties.setInitialBufferSize(DataSize.ofBytes(512)); nettyProperties.setInitialBufferSize(DataSize.ofBytes(512));
nettyProperties.setH2cMaxContentLength(DataSize.ofKilobytes(1)); nettyProperties.setH2cMaxContentLength(DataSize.ofKilobytes(1));
setMaxChunkSize(nettyProperties);
nettyProperties.setMaxInitialLineLength(DataSize.ofKilobytes(32)); nettyProperties.setMaxInitialLineLength(DataSize.ofKilobytes(32));
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
this.customizer.customize(factory); this.customizer.customize(factory);
@ -143,20 +142,9 @@ class NettyWebServerFactoryCustomizerTests {
assertThat(decoder.validateHeaders()).isFalse(); assertThat(decoder.validateHeaders()).isFalse();
assertThat(decoder.initialBufferSize()).isEqualTo(nettyProperties.getInitialBufferSize().toBytes()); assertThat(decoder.initialBufferSize()).isEqualTo(nettyProperties.getInitialBufferSize().toBytes());
assertThat(decoder.h2cMaxContentLength()).isEqualTo(nettyProperties.getH2cMaxContentLength().toBytes()); assertThat(decoder.h2cMaxContentLength()).isEqualTo(nettyProperties.getH2cMaxContentLength().toBytes());
assertMaxChunkSize(nettyProperties, decoder);
assertThat(decoder.maxInitialLineLength()).isEqualTo(nettyProperties.getMaxInitialLineLength().toBytes()); assertThat(decoder.maxInitialLineLength()).isEqualTo(nettyProperties.getMaxInitialLineLength().toBytes());
} }
@SuppressWarnings("removal")
private void setMaxChunkSize(ServerProperties.Netty nettyProperties) {
nettyProperties.setMaxChunkSize(DataSize.ofKilobytes(16));
}
@SuppressWarnings({ "deprecation", "removal" })
private void assertMaxChunkSize(ServerProperties.Netty nettyProperties, HttpRequestDecoderSpec decoder) {
assertThat(decoder.maxChunkSize()).isEqualTo(nettyProperties.getMaxChunkSize().toBytes());
}
private void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Integer expected) { private void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Integer expected) {
if (expected == null) { if (expected == null) {
then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class)); then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class));

@ -176,47 +176,6 @@ class TomcatWebServerFactoryCustomizerTests {
(server) -> assertThat(server.getTomcat().getConnector().getMaxPostSize()).isEqualTo(10000)); (server) -> assertThat(server.getTomcat().getConnector().getMaxPostSize()).isEqualTo(10000));
} }
@Test
void customMaxHttpHeaderSize() {
bind("server.max-http-header-size=1KB");
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getMaxHttpRequestHeaderSize())
.isEqualTo(DataSize.ofKilobytes(1).toBytes()));
}
@Test
void customMaxHttpHeaderSizeWithHttp2() {
bind("server.max-http-header-size=1KB", "server.http2.enabled=true");
customizeAndRunServer((server) -> {
AbstractHttp11Protocol<?> protocolHandler = (AbstractHttp11Protocol<?>) server.getTomcat()
.getConnector()
.getProtocolHandler();
long expectedSize = DataSize.ofKilobytes(1).toBytes();
assertThat(protocolHandler.getMaxHttpRequestHeaderSize()).isEqualTo(expectedSize);
assertThat(((Http2Protocol) protocolHandler.getUpgradeProtocol("h2c")).getMaxHeaderSize())
.isEqualTo(expectedSize);
});
}
@Test
void customMaxHttpHeaderSizeIgnoredIfNegative() {
bind("server.max-http-header-size=-1");
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getMaxHttpRequestHeaderSize())
.isEqualTo(DataSize.ofKilobytes(8).toBytes()));
}
@Test
void customMaxHttpHeaderSizeIgnoredIfZero() {
bind("server.max-http-header-size=0");
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getMaxHttpRequestHeaderSize())
.isEqualTo(DataSize.ofKilobytes(8).toBytes()));
}
@Test @Test
void defaultMaxHttpRequestHeaderSize() { void defaultMaxHttpRequestHeaderSize() {
customizeAndRunServer((server) -> assertThat( customizeAndRunServer((server) -> assertThat(
@ -436,16 +395,6 @@ class TomcatWebServerFactoryCustomizerTests {
assertThat(factory.getEngineValves()).isEmpty(); assertThat(factory.getEngineValves()).isEmpty();
} }
@Test
@Deprecated(since = "2.7.12", forRemoval = true)
void testCustomizeRejectIllegalHeader() {
bind("server.tomcat.reject-illegal-header=false");
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getRejectIllegalHeader())
.isFalse());
}
@Test @Test
void errorReportValveIsConfiguredToNotReportStackTraces() { void errorReportValveIsConfiguredToNotReportStackTraces() {
TomcatWebServer server = customizeAndGetServer(); TomcatWebServer server = customizeAndGetServer();

@ -86,20 +86,20 @@ class UndertowWebServerFactoryCustomizerTests {
} }
@Test @Test
void customMaxHttpHeaderSize() { void customMaxHttpRequestHeaderSize() {
bind("server.max-http-header-size=2048"); bind("server.max-http-request-header-size=2048");
assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isEqualTo(2048); assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isEqualTo(2048);
} }
@Test @Test
void customMaxHttpHeaderSizeIgnoredIfNegative() { void customMaxHttpRequestHeaderSizeIgnoredIfNegative() {
bind("server.max-http-header-size=-1"); bind("server.max-http-request-header-size=-1");
assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull(); assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull();
} }
@Test @Test
void customMaxHttpHeaderSizeIgnoredIfZero() { void customMaxHttpRequestHeaderSizeIgnoredIfZero() {
bind("server.max-http-header-size=0"); bind("server.max-http-request-header-size=0");
assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull(); assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull();
} }

@ -28,11 +28,11 @@ import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Jsp; import org.springframework.boot.web.servlet.server.Jsp;
import org.springframework.boot.web.servlet.server.Session.Cookie;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -97,7 +97,6 @@ class ServletWebServerFactoryCustomizerTests {
} }
@Test @Test
@SuppressWarnings("removal")
void customizeSessionProperties() { void customizeSessionProperties() {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("server.servlet.session.timeout", "123"); map.put("server.servlet.session.timeout", "123");
@ -105,7 +104,6 @@ class ServletWebServerFactoryCustomizerTests {
map.put("server.servlet.session.cookie.name", "testname"); map.put("server.servlet.session.cookie.name", "testname");
map.put("server.servlet.session.cookie.domain", "testdomain"); map.put("server.servlet.session.cookie.domain", "testdomain");
map.put("server.servlet.session.cookie.path", "/testpath"); map.put("server.servlet.session.cookie.path", "/testpath");
map.put("server.servlet.session.cookie.comment", "testcomment");
map.put("server.servlet.session.cookie.http-only", "true"); map.put("server.servlet.session.cookie.http-only", "true");
map.put("server.servlet.session.cookie.secure", "true"); map.put("server.servlet.session.cookie.secure", "true");
map.put("server.servlet.session.cookie.max-age", "60"); map.put("server.servlet.session.cookie.max-age", "60");
@ -118,7 +116,6 @@ class ServletWebServerFactoryCustomizerTests {
assertThat(cookie.getName()).isEqualTo("testname"); assertThat(cookie.getName()).isEqualTo("testname");
assertThat(cookie.getDomain()).isEqualTo("testdomain"); assertThat(cookie.getDomain()).isEqualTo("testdomain");
assertThat(cookie.getPath()).isEqualTo("/testpath"); assertThat(cookie.getPath()).isEqualTo("/testpath");
assertThat(cookie.getComment()).isEqualTo("testcomment");
assertThat(cookie.getHttpOnly()).isTrue(); assertThat(cookie.getHttpOnly()).isTrue();
assertThat(cookie.getMaxAge()).hasSeconds(60); assertThat(cookie.getMaxAge()).hasSeconds(60);
})); }));

@ -380,29 +380,6 @@ class WebMvcAutoConfigurationTests {
}); });
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("deprecation")
void customThemeResolverWithMatchingNameReplacesDefaultThemeResolver() {
this.contextRunner.withBean("themeResolver", CustomThemeResolver.class, CustomThemeResolver::new)
.run((context) -> {
assertThat(context).hasSingleBean(org.springframework.web.servlet.ThemeResolver.class);
assertThat(context.getBean("themeResolver")).isInstanceOf(CustomThemeResolver.class);
});
}
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("deprecation")
void customThemeResolverWithDifferentNameDoesNotReplaceDefaultThemeResolver() {
this.contextRunner.withBean("customThemeResolver", CustomThemeResolver.class, CustomThemeResolver::new)
.run((context) -> {
assertThat(context.getBean("customThemeResolver")).isInstanceOf(CustomThemeResolver.class);
assertThat(context.getBean("themeResolver"))
.isInstanceOf(org.springframework.web.servlet.theme.FixedThemeResolver.class);
});
}
@Test @Test
void customFlashMapManagerWithMatchingNameReplacesDefaultFlashMapManager() { void customFlashMapManagerWithMatchingNameReplacesDefaultFlashMapManager() {
this.contextRunner.withBean("flashMapManager", CustomFlashMapManager.class, CustomFlashMapManager::new) this.contextRunner.withBean("flashMapManager", CustomFlashMapManager.class, CustomFlashMapManager::new)
@ -493,21 +470,6 @@ class WebMvcAutoConfigurationTests {
.isNotNull()); .isNotNull());
} }
@Test
void ignoreDefaultModelOnRedirectIsTrue() {
this.contextRunner.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))
.extracting("ignoreDefaultModelOnRedirect")
.isEqualTo(true));
}
@Test
void overrideIgnoreDefaultModelOnRedirect() {
this.contextRunner.withPropertyValues("spring.mvc.ignore-default-model-on-redirect:false")
.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))
.extracting("ignoreDefaultModelOnRedirect")
.isEqualTo(false));
}
@Test @Test
void customViewResolver() { void customViewResolver() {
this.contextRunner.withUserConfiguration(CustomViewResolver.class) this.contextRunner.withUserConfiguration(CustomViewResolver.class)
@ -1464,20 +1426,6 @@ class WebMvcAutoConfigurationTests {
} }
@Deprecated(since = "3.0.0", forRemoval = true)
static class CustomThemeResolver implements org.springframework.web.servlet.ThemeResolver {
@Override
public String resolveThemeName(HttpServletRequest request) {
return "custom";
}
@Override
public void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName) {
}
}
static class CustomFlashMapManager extends AbstractFlashMapManager { static class CustomFlashMapManager extends AbstractFlashMapManager {
@Override @Override

@ -1,63 +0,0 @@
/*
* Copyright 2012-2023 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.test.autoconfigure;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ApplicationContextFailureProcessor;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
/**
* Since 3.0.0 this class has been replaced by
* {@link ConditionReportApplicationContextFailureProcessor} and is not used internally.
*
* @author Phillip Webb
* @since 1.4.1
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link ApplicationContextFailureProcessor}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public class SpringBootDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener {
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
try {
super.prepareTestInstance(testContext);
}
catch (Exception ex) {
outputConditionEvaluationReport(testContext);
throw ex;
}
}
private void outputConditionEvaluationReport(TestContext testContext) {
try {
ApplicationContext context = testContext.getApplicationContext();
if (context instanceof ConfigurableApplicationContext configurableContext) {
ConditionEvaluationReport report = ConditionEvaluationReport.get(configurableContext.getBeanFactory());
System.err.println(new ConditionEvaluationReportMessage(report));
}
}
catch (Exception ex) {
// Allow original failure to be reported
}
}
}

@ -1,45 +0,0 @@
/*
* 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.
* 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.test.autoconfigure.actuate.metrics;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
/**
* Annotation that can be applied to a test class to enable auto-configuration for metrics
* exporters.
*
* @author Chris Bono
* @since 2.4.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link AutoConfigureObservability @AutoConfigureObservability}
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Deprecated(since = "3.0.0", forRemoval = true)
@AutoConfigureObservability(tracing = false)
public @interface AutoConfigureMetrics {
}

@ -1,20 +0,0 @@
/*
* Copyright 2012-2020 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.
*/
/**
* Auto-configuration for handling metrics in tests.
*/
package org.springframework.boot.test.autoconfigure.actuate.metrics;

@ -1,53 +0,0 @@
/*
* 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.
* 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.test.autoconfigure.actuate.metrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to verify behaviour when
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is not present on the test class.
*
* @author Chris Bono
*/
@SpringBootTest
class AutoConfigureMetricsMissingIntegrationTests {
@Test
void customizerRunsAndOnlyEnablesSimpleMeterRegistryWhenNoAnnotationPresent(
@Autowired ApplicationContext applicationContext) {
assertThat(applicationContext.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class);
assertThat(applicationContext.getBeansOfType(PrometheusMeterRegistry.class)).isEmpty();
}
@Test
void customizerRunsAndSetsExclusionPropertiesWhenNoAnnotationPresent(@Autowired Environment environment) {
assertThat(environment.getProperty("management.defaults.metrics.export.enabled")).isEqualTo("false");
assertThat(environment.getProperty("management.simple.metrics.export.enabled")).isEqualTo("true");
}
}

@ -1,53 +0,0 @@
/*
* 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.
* 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.test.autoconfigure.actuate.metrics;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to verify behaviour when
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is present on the test class.
*
* @author Chris Bono
*/
@SuppressWarnings("removal")
@SpringBootTest
@AutoConfigureMetrics
@Deprecated(since = "3.0.0", forRemoval = true)
class AutoConfigureMetricsPresentIntegrationTests {
@Test
void customizerDoesNotDisableAvailableMeterRegistriesWhenAnnotationPresent(
@Autowired ApplicationContext applicationContext) {
assertThat(applicationContext.getBeansOfType(PrometheusMeterRegistry.class)).hasSize(1);
}
@Test
void customizerDoesNotSetExclusionPropertiesWhenAnnotationPresent(@Autowired Environment environment) {
assertThat(environment.containsProperty("management.defaults.metrics.export.enabled")).isFalse();
assertThat(environment.containsProperty("management.simple.metrics.export.enabled")).isFalse();
}
}

@ -1,37 +0,0 @@
/*
* 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.
* 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.test.autoconfigure.actuate.metrics;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
/**
* Example {@link SpringBootApplication @SpringBootApplication} for use with
* {@link AutoConfigureMetrics @AutoConfigureMetrics} tests.
*
* @author Chris Bono
*/
@SpringBootConfiguration
@EnableAutoConfiguration(exclude = { CassandraAutoConfiguration.class, MongoAutoConfiguration.class,
MongoReactiveAutoConfiguration.class })
class AutoConfigureMetricsSpringBootApplication {
}

@ -1,48 +0,0 @@
/*
* 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.
* 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.test.context;
import java.util.List;
import org.springframework.test.context.ApplicationContextFailureProcessor;
import org.springframework.test.context.TestExecutionListener;
/**
* Callback interface trigger from {@link SpringBootTestContextBootstrapper} that can be
* used to post-process the list of default {@link TestExecutionListener
* TestExecutionListeners} to be used by a test. Can be used to add or remove existing
* listeners.
*
* @author Phillip Webb
* @since 1.4.1
* @deprecated since 3.0.0 removal in 3.2.0 in favor of
* {@link ApplicationContextFailureProcessor}
*/
@FunctionalInterface
@Deprecated(since = "3.0.0", forRemoval = true)
public interface DefaultTestExecutionListenersPostProcessor {
/**
* Post process the list of default {@link TestExecutionListener listeners} to be
* used.
* @param listeners the source listeners
* @return the actual listeners that should be used
* @since 3.0.0
*/
List<TestExecutionListener> postProcessDefaultTestExecutionListeners(List<TestExecutionListener> listeners);
}

@ -38,7 +38,6 @@ import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.ContextCustomizer;
@ -48,7 +47,6 @@ import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContext; import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestContextAnnotationUtils; import org.springframework.test.context.TestContextAnnotationUtils;
import org.springframework.test.context.TestContextBootstrapper; import org.springframework.test.context.TestContextBootstrapper;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.aot.AotTestAttributes; import org.springframework.test.context.aot.AotTestAttributes;
import org.springframework.test.context.support.DefaultTestContextBootstrapper; import org.springframework.test.context.support.DefaultTestContextBootstrapper;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
@ -122,18 +120,6 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
return context; return context;
} }
@Override
@SuppressWarnings("removal")
protected List<TestExecutionListener> getDefaultTestExecutionListeners() {
List<TestExecutionListener> listeners = new ArrayList<>(super.getDefaultTestExecutionListeners());
List<DefaultTestExecutionListenersPostProcessor> postProcessors = SpringFactoriesLoader
.loadFactories(DefaultTestExecutionListenersPostProcessor.class, getClass().getClassLoader());
for (DefaultTestExecutionListenersPostProcessor postProcessor : postProcessors) {
listeners = postProcessor.postProcessDefaultTestExecutionListeners(listeners);
}
return listeners;
}
@Override @Override
protected ContextLoader resolveContextLoader(Class<?> testClass, protected ContextLoader resolveContextLoader(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributesList) { List<ContextConfigurationAttributes> configAttributesList) {

@ -45,8 +45,6 @@ class SpringBootTestContextBootstrapperIntegrationTests {
@Autowired @Autowired
private SpringBootTestContextBootstrapperExampleConfig config; private SpringBootTestContextBootstrapperExampleConfig config;
boolean defaultTestExecutionListenersPostProcessorCalled = false;
@Test @Test
void findConfigAutomatically() { void findConfigAutomatically() {
assertThat(this.config).isNotNull(); assertThat(this.config).isNotNull();
@ -62,11 +60,6 @@ class SpringBootTestContextBootstrapperIntegrationTests {
assertThat(this.context.getBean(ExampleBean.class)).isNotNull(); assertThat(this.context.getBean(ExampleBean.class)).isNotNull();
} }
@Test
void defaultTestExecutionListenersPostProcessorShouldBeCalled() {
assertThat(this.defaultTestExecutionListenersPostProcessorCalled).isTrue();
}
@TestConfiguration(proxyBeanMethods = false) @TestConfiguration(proxyBeanMethods = false)
static class TestConfig { static class TestConfig {

@ -1,52 +0,0 @@
/*
* 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.
* 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.test.context.bootstrap;
import java.util.List;
import org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.support.AbstractTestExecutionListener;
/**
* Test {@link DefaultTestExecutionListenersPostProcessor}.
*
* @author Phillip Webb
*/
@SuppressWarnings("removal")
public class TestDefaultTestExecutionListenersPostProcessor implements DefaultTestExecutionListenersPostProcessor {
@Override
public List<TestExecutionListener> postProcessDefaultTestExecutionListeners(List<TestExecutionListener> listeners) {
listeners.add(new ExampleTestExecutionListener());
return listeners;
}
static class ExampleTestExecutionListener extends AbstractTestExecutionListener {
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
Object testInstance = testContext.getTestInstance();
if (testInstance instanceof SpringBootTestContextBootstrapperIntegrationTests test) {
test.defaultTestExecutionListenersPostProcessorCalled = true;
}
}
}
}

@ -146,17 +146,6 @@ class PropertyDescriptorResolverTests {
.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor))); .allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
void propertiesWithMultiConstructorAndDeprecatedAnnotation() {
process(org.springframework.boot.configurationsample.immutable.DeprecatedImmutableMultiConstructorProperties.class,
propertyNames((stream) -> assertThat(stream).containsExactly("name", "description")));
process(org.springframework.boot.configurationsample.immutable.DeprecatedImmutableMultiConstructorProperties.class,
properties((stream) -> assertThat(stream)
.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));
}
@Test @Test
void propertiesWithMultiConstructorNoDirective() { void propertiesWithMultiConstructorNoDirective() {
process(TwoConstructorsExample.class, propertyNames((stream) -> assertThat(stream).containsExactly("name"))); process(TwoConstructorsExample.class, propertyNames((stream) -> assertThat(stream).containsExactly("name")));

@ -1,39 +0,0 @@
/*
* Copyright 2012-2023 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.configurationsample;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Alternative to Spring Boot's deprecated
* {@code @org.springframework.boot.context.properties.ConstructorBinding} for testing
* (removes the need for a dependency on the real annotation).
*
* @author Stephane Nicoll
*/
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConstructorBinding
@Deprecated(since = "3.0.0", forRemoval = true)
public @interface DeprecatedConstructorBinding {
}

@ -1,46 +0,0 @@
/*
* 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.
* 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.configurationsample.immutable;
/**
* Simple immutable properties with several constructors.
*
* @author Stephane Nicoll
*/
@SuppressWarnings("unused")
@Deprecated(since = "3.0.0", forRemoval = true)
public class DeprecatedImmutableMultiConstructorProperties {
private final String name;
/**
* Test description.
*/
private final String description;
public DeprecatedImmutableMultiConstructorProperties(String name) {
this(name, null);
}
@SuppressWarnings("removal")
@org.springframework.boot.configurationsample.DeprecatedConstructorBinding
public DeprecatedImmutableMultiConstructorProperties(String name, String description) {
this.name = name;
this.description = description;
}
}

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 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,6 +22,7 @@ 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.context.properties.bind.ConstructorBinding;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed; import org.springframework.stereotype.Indexed;

@ -1,52 +0,0 @@
/*
* 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.
* 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.context.properties;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation that can be used to indicate which constructor to use when binding
* configuration properties using constructor arguments rather than by calling setters. A
* single parameterized constructor implicitly indicates that constructor binding should
* be used unless the constructor is annotated with `@Autowired`.
* <p>
* Note: To use constructor binding the class must be enabled using
* {@link EnableConfigurationProperties @EnableConfigurationProperties} or configuration
* property scanning. Constructor binding cannot be used with beans that are created by
* the regular Spring mechanisms (e.g.
* {@link org.springframework.stereotype.Component @Component} beans, beans created via
* {@link org.springframework.context.annotation.Bean @Bean} methods or beans loaded using
* {@link org.springframework.context.annotation.Import @Import}).
*
* @author Phillip Webb
* @since 2.2.0
* @see ConfigurationProperties
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link org.springframework.boot.context.properties.bind.ConstructorBinding}
*/
@Target({ ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Deprecated(since = "3.0.0", forRemoval = true)
@org.springframework.boot.context.properties.bind.ConstructorBinding
public @interface ConstructorBinding {
}

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2022 the original author or authors. * Copyright 2019-2023 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,6 +17,7 @@
package org.springframework.boot.context.properties; package org.springframework.boot.context.properties;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
/** /**
* Helper class to programmatically bind configuration properties that use constructor * Helper class to programmatically bind configuration properties that use constructor

@ -16,14 +16,9 @@
package org.springframework.boot.jackson; package org.springframework.boot.jackson;
import java.util.Collection;
import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
/** /**
* Spring Bean and Jackson {@link Module} to find and * Spring Bean and Jackson {@link Module} to find and
* {@link SimpleModule#setMixInAnnotation(Class, Class) register} * {@link SimpleModule#setMixInAnnotation(Class, Class) register}
@ -36,22 +31,6 @@ import org.springframework.util.Assert;
*/ */
public class JsonMixinModule extends SimpleModule { public class JsonMixinModule extends SimpleModule {
public JsonMixinModule() {
}
/**
* Create a new {@link JsonMixinModule} instance.
* @param context the source application context
* @param basePackages the packages to check for annotated classes
* @deprecated since 3.0.0 in favor of
* {@link #registerEntries(JsonMixinModuleEntries, ClassLoader)}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public JsonMixinModule(ApplicationContext context, Collection<String> basePackages) {
Assert.notNull(context, "Context must not be null");
registerEntries(JsonMixinModuleEntries.scan(context, basePackages), context.getClassLoader());
}
/** /**
* Register the specified {@link JsonMixinModuleEntries entries}. * Register the specified {@link JsonMixinModuleEntries entries}.
* @param entries the entries to register to this instance * @param entries the entries to register to this instance

@ -1,41 +0,0 @@
/*
* 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.
* 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.web.client;
import java.util.function.Supplier;
import org.springframework.http.client.ClientHttpRequestFactory;
/**
* A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate
* based on the available implementations on the classpath.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
* @since 2.1.0
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
* {@link ClientHttpRequestFactories}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public class ClientHttpRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {
@Override
public ClientHttpRequestFactory get() {
return ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS);
}
}

@ -325,8 +325,9 @@ public class RestTemplateBuilder {
} }
/** /**
* Set the {@link ClientHttpRequestFactorySupplier} that should be called each time we * Set the request factory function that should be called to provide a
* {@link #build()} a new {@link RestTemplate} instance. * {@link ClientHttpRequestFactory} each time we {@link #build()} a new
* {@link RestTemplate} instance.
* @param requestFactoryFunction the settings to request factory function * @param requestFactoryFunction the settings to request factory function
* @return a new builder instance * @return a new builder instance
* @since 3.0.0 * @since 3.0.0

@ -39,6 +39,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.MimeMappings; import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -335,14 +336,12 @@ public abstract class AbstractServletWebServerFactory extends AbstractConfigurab
configureSessionCookie(servletContext.getSessionCookieConfig()); configureSessionCookie(servletContext.getSessionCookieConfig());
} }
@SuppressWarnings("removal")
private void configureSessionCookie(SessionCookieConfig config) { private void configureSessionCookie(SessionCookieConfig config) {
Session.Cookie cookie = this.session.getCookie(); Cookie cookie = this.session.getCookie();
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(cookie::getName).to(config::setName); map.from(cookie::getName).to(config::setName);
map.from(cookie::getDomain).to(config::setDomain); map.from(cookie::getDomain).to(config::setDomain);
map.from(cookie::getPath).to(config::setPath); map.from(cookie::getPath).to(config::setPath);
map.from(cookie::getComment).to(config::setComment);
map.from(cookie::getHttpOnly).to(config::setHttpOnly); map.from(cookie::getHttpOnly).to(config::setHttpOnly);
map.from(cookie::getSecure).to(config::setSecure); map.from(cookie::getSecure).to(config::setSecure);
map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(config::setMaxAge); map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(config::setMaxAge);

@ -21,8 +21,9 @@ import java.time.Duration;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Set; import java.util.Set;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.convert.DurationUnit; import org.springframework.boot.convert.DurationUnit;
import org.springframework.boot.web.server.Cookie;
/** /**
* Session properties. * Session properties.
@ -44,6 +45,7 @@ public class Session {
*/ */
private File storeDir; private File storeDir;
@NestedConfigurationProperty
private final Cookie cookie = new Cookie(); private final Cookie cookie = new Cookie();
private final SessionStoreDirectory sessionStoreDirectory = new SessionStoreDirectory(); private final SessionStoreDirectory sessionStoreDirectory = new SessionStoreDirectory();
@ -101,34 +103,6 @@ public class Session {
return this.sessionStoreDirectory; return this.sessionStoreDirectory;
} }
/**
* Session cookie properties.
*/
public static class Cookie extends org.springframework.boot.web.server.Cookie {
/**
* Comment for the session cookie.
*/
private String comment;
/**
* Return the comment for the session cookie.
* @return the session cookie comment
* @deprecated since 3.0.0 without replacement
*/
@Deprecated(since = "3.0.0", forRemoval = true)
@DeprecatedConfigurationProperty
public String getComment() {
return this.comment;
}
@Deprecated(since = "3.0.0", forRemoval = true)
public void setComment(String comment) {
this.comment = comment;
}
}
/** /**
* Available session tracking modes (mirrors * Available session tracking modes (mirrors
* {@link jakarta.servlet.SessionTrackingMode}. * {@link jakarta.servlet.SessionTrackingMode}.

@ -233,24 +233,6 @@ class ConfigurationPropertiesBeanTests {
.isNotNull(); .isNotNull();
} }
@Test
void forValueObjectWithDeprecatedConstructorBindingAnnotatedClassReturnsBean() {
ConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean
.forValueObject(DeprecatedConstructorBindingOnConstructor.class, "valueObjectBean");
assertThat(propertiesBean.getName()).isEqualTo("valueObjectBean");
assertThat(propertiesBean.getInstance()).isNull();
assertThat(propertiesBean.getType()).isEqualTo(DeprecatedConstructorBindingOnConstructor.class);
assertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.VALUE_OBJECT);
assertThat(propertiesBean.getAnnotation()).isNotNull();
Bindable<?> target = propertiesBean.asBindTarget();
assertThat(target.getType())
.isEqualTo(ResolvableType.forClass(DeprecatedConstructorBindingOnConstructor.class));
assertThat(target.getValue()).isNull();
assertThat(BindConstructorProvider.DEFAULT.getBindConstructor(DeprecatedConstructorBindingOnConstructor.class,
false))
.isNotNull();
}
@Test @Test
void forValueObjectWithRecordReturnsBean() { void forValueObjectWithRecordReturnsBean() {
Class<?> implicitConstructorBinding = new ByteBuddy(ClassFileVersion.JAVA_V16).makeRecord() Class<?> implicitConstructorBinding = new ByteBuddy(ClassFileVersion.JAVA_V16).makeRecord()
@ -558,20 +540,6 @@ class ConfigurationPropertiesBeanTests {
} }
@ConfigurationProperties
@SuppressWarnings("removal")
static class DeprecatedConstructorBindingOnConstructor {
DeprecatedConstructorBindingOnConstructor(String name) {
this(name, -1);
}
@org.springframework.boot.context.properties.ConstructorBinding
DeprecatedConstructorBindingOnConstructor(String name, int age) {
}
}
@ConfigurationProperties @ConfigurationProperties
static class ConstructorBindingOnMultipleConstructors { static class ConstructorBindingOnMultipleConstructors {

@ -17,7 +17,6 @@
package org.springframework.boot.jackson; package org.springframework.boot.jackson;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.Module;
@ -35,7 +34,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/** /**
* Tests for {@link JsonMixinModule}. * Tests for {@link JsonMixinModule}.
@ -53,14 +51,6 @@ class JsonMixinModuleTests {
} }
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
@SuppressWarnings("removal")
void createWhenContextIsNullShouldThrowException() {
assertThatIllegalArgumentException().isThrownBy(() -> new JsonMixinModule(null, Collections.emptyList()))
.withMessageContaining("Context must not be null");
}
@Test @Test
void jsonWithModuleWithRenameMixInClassShouldBeMixedIn() throws Exception { void jsonWithModuleWithRenameMixInClassShouldBeMixedIn() throws Exception {
load(RenameMixInClass.class); load(RenameMixInClass.class);

@ -120,11 +120,6 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
} }
@Override
protected boolean isCookieCommentSupported() {
return false;
}
// JMX MBean names clash if you get more than one Engine with the same name... // JMX MBean names clash if you get more than one Engine with the same name...
@Test @Test
void tomcatEngineNames() { void tomcatEngineNames() {

@ -204,10 +204,6 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
} }
protected boolean isCookieCommentSupported() {
return true;
}
@Test @Test
void startServlet() throws Exception { void startServlet() throws Exception {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
@ -870,13 +866,11 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Test @Test
@SuppressWarnings("removal")
void sessionCookieConfiguration() { void sessionCookieConfiguration() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
factory.getSession().getCookie().setName("testname"); factory.getSession().getCookie().setName("testname");
factory.getSession().getCookie().setDomain("testdomain"); factory.getSession().getCookie().setDomain("testdomain");
factory.getSession().getCookie().setPath("/testpath"); factory.getSession().getCookie().setPath("/testpath");
factory.getSession().getCookie().setComment("testcomment");
factory.getSession().getCookie().setHttpOnly(true); factory.getSession().getCookie().setHttpOnly(true);
factory.getSession().getCookie().setSecure(true); factory.getSession().getCookie().setSecure(true);
factory.getSession().getCookie().setMaxAge(Duration.ofSeconds(60)); factory.getSession().getCookie().setMaxAge(Duration.ofSeconds(60));
@ -886,9 +880,6 @@ public abstract class AbstractServletWebServerFactoryTests {
assertThat(sessionCookieConfig.getName()).isEqualTo("testname"); assertThat(sessionCookieConfig.getName()).isEqualTo("testname");
assertThat(sessionCookieConfig.getDomain()).isEqualTo("testdomain"); assertThat(sessionCookieConfig.getDomain()).isEqualTo("testdomain");
assertThat(sessionCookieConfig.getPath()).isEqualTo("/testpath"); assertThat(sessionCookieConfig.getPath()).isEqualTo("/testpath");
if (isCookieCommentSupported()) {
assertThat(sessionCookieConfig.getComment()).isEqualTo("testcomment");
}
assertThat(sessionCookieConfig.isHttpOnly()).isTrue(); assertThat(sessionCookieConfig.isHttpOnly()).isTrue();
assertThat(sessionCookieConfig.isSecure()).isTrue(); assertThat(sessionCookieConfig.isSecure()).isTrue();
assertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60); assertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60);
@ -1143,7 +1134,6 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Test @Test
@SuppressWarnings("removal")
void sessionConfiguration() { void sessionConfiguration() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
factory.getSession().setTimeout(Duration.ofSeconds(123)); factory.getSession().setTimeout(Duration.ofSeconds(123));
@ -1151,7 +1141,6 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.getSession().getCookie().setName("testname"); factory.getSession().getCookie().setName("testname");
factory.getSession().getCookie().setDomain("testdomain"); factory.getSession().getCookie().setDomain("testdomain");
factory.getSession().getCookie().setPath("/testpath"); factory.getSession().getCookie().setPath("/testpath");
factory.getSession().getCookie().setComment("testcomment");
factory.getSession().getCookie().setHttpOnly(true); factory.getSession().getCookie().setHttpOnly(true);
factory.getSession().getCookie().setSecure(true); factory.getSession().getCookie().setSecure(true);
factory.getSession().getCookie().setMaxAge(Duration.ofMinutes(1)); factory.getSession().getCookie().setMaxAge(Duration.ofMinutes(1));
@ -1163,9 +1152,6 @@ public abstract class AbstractServletWebServerFactoryTests {
assertThat(servletContext.getSessionCookieConfig().getName()).isEqualTo("testname"); assertThat(servletContext.getSessionCookieConfig().getName()).isEqualTo("testname");
assertThat(servletContext.getSessionCookieConfig().getDomain()).isEqualTo("testdomain"); assertThat(servletContext.getSessionCookieConfig().getDomain()).isEqualTo("testdomain");
assertThat(servletContext.getSessionCookieConfig().getPath()).isEqualTo("/testpath"); assertThat(servletContext.getSessionCookieConfig().getPath()).isEqualTo("/testpath");
if (isCookieCommentSupported()) {
assertThat(servletContext.getSessionCookieConfig().getComment()).isEqualTo("testcomment");
}
assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue(); assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue();
assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue(); assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue();
assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60); assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60);

Loading…
Cancel
Save