Allow to customize the path of a web endpoint
This commit introduces a endpoints.<id>.web.path generic property that allows to customize the path of an endpoint. By default the path is the same as the id of the endpoint. Such customization does not apply for the CloudFoundry specific endpoints. Closes gh-10181
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* Resolve the path of an endpoint.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface EndpointPathResolver {
|
||||
|
||||
/**
|
||||
* Resolve the path for the endpoint with the specified {@code endpointId}.
|
||||
* @param endpointId the id of an endpoint
|
||||
* @return the path of the endpoint
|
||||
*/
|
||||
String resolvePath(String endpointId);
|
||||
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
|
||||
import org.springframework.boot.actuate.endpoint.cache.CachingOperationInvoker;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.OperationRequestPredicate;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
|
||||
@@ -71,14 +72,17 @@ public class WebAnnotationEndpointDiscoverer extends
|
||||
* @param cachingConfigurationFactory the {@link CachingConfiguration} factory to use
|
||||
* @param endpointMediaTypes the media types produced and consumed by web endpoint
|
||||
* operations
|
||||
* @param endpointPathResolver the {@link EndpointPathResolver} used to resolve
|
||||
* endpoint paths
|
||||
*/
|
||||
public WebAnnotationEndpointDiscoverer(ApplicationContext applicationContext,
|
||||
OperationParameterMapper operationParameterMapper,
|
||||
CachingConfigurationFactory cachingConfigurationFactory,
|
||||
EndpointMediaTypes endpointMediaTypes) {
|
||||
EndpointMediaTypes endpointMediaTypes,
|
||||
EndpointPathResolver endpointPathResolver) {
|
||||
super(applicationContext,
|
||||
new WebEndpointOperationFactory(operationParameterMapper,
|
||||
endpointMediaTypes),
|
||||
endpointMediaTypes, endpointPathResolver),
|
||||
WebEndpointOperation::getRequestPredicate, cachingConfigurationFactory);
|
||||
}
|
||||
|
||||
@@ -121,10 +125,14 @@ public class WebAnnotationEndpointDiscoverer extends
|
||||
|
||||
private final EndpointMediaTypes endpointMediaTypes;
|
||||
|
||||
private final EndpointPathResolver endpointPathResolver;
|
||||
|
||||
private WebEndpointOperationFactory(OperationParameterMapper parameterMapper,
|
||||
EndpointMediaTypes endpointMediaTypes) {
|
||||
EndpointMediaTypes endpointMediaTypes,
|
||||
EndpointPathResolver endpointPathResolver) {
|
||||
this.parameterMapper = parameterMapper;
|
||||
this.endpointMediaTypes = endpointMediaTypes;
|
||||
this.endpointPathResolver = endpointPathResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,7 +155,8 @@ public class WebAnnotationEndpointDiscoverer extends
|
||||
}
|
||||
|
||||
private String determinePath(String endpointId, Method operationMethod) {
|
||||
StringBuilder path = new StringBuilder(endpointId);
|
||||
StringBuilder path = new StringBuilder(
|
||||
this.endpointPathResolver.resolvePath(endpointId));
|
||||
Stream.of(operationMethod.getParameters())
|
||||
.filter((
|
||||
parameter) -> parameter.getAnnotation(Selector.class) != null)
|
||||
|
||||
@@ -385,7 +385,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
DefaultConversionService.getSharedInstance());
|
||||
return new WebAnnotationEndpointDiscoverer(applicationContext,
|
||||
parameterMapper, (id) -> new CachingConfiguration(0),
|
||||
endpointMediaTypes());
|
||||
endpointMediaTypes(), (id) -> id);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -189,8 +189,8 @@ public class WebAnnotationEndpointDiscovererTests {
|
||||
|
||||
@Test
|
||||
public void endpointMainReadOperationIsCachedWithMatchingId() {
|
||||
load((id) -> new CachingConfiguration(500), TestEndpointConfiguration.class,
|
||||
(discoverer) -> {
|
||||
load((id) -> new CachingConfiguration(500), (id) -> id,
|
||||
TestEndpointConfiguration.class, (discoverer) -> {
|
||||
Map<String, EndpointInfo<WebEndpointOperation>> endpoints = mapEndpoints(
|
||||
discoverer.discoverEndpoints());
|
||||
assertThat(endpoints).containsOnlyKeys("test");
|
||||
@@ -237,12 +237,29 @@ public class WebAnnotationEndpointDiscovererTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointPathCanBeCustomized() {
|
||||
load((id) -> null, (id) -> "custom/" + id,
|
||||
AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> {
|
||||
Map<String, EndpointInfo<WebEndpointOperation>> endpoints = mapEndpoints(
|
||||
discoverer.discoverEndpoints());
|
||||
assertThat(endpoints).containsOnlyKeys("test");
|
||||
EndpointInfo<WebEndpointOperation> endpoint = endpoints.get("test");
|
||||
assertThat(requestPredicates(endpoint)).has(requestPredicates(
|
||||
path("custom/test").httpMethod(WebEndpointHttpMethod.GET).consumes()
|
||||
.produces("application/json"),
|
||||
path("custom/test/{id}").httpMethod(WebEndpointHttpMethod.GET).consumes()
|
||||
.produces("application/json")));
|
||||
});
|
||||
}
|
||||
|
||||
private void load(Class<?> configuration,
|
||||
Consumer<WebAnnotationEndpointDiscoverer> consumer) {
|
||||
this.load((id) -> null, configuration, consumer);
|
||||
this.load((id) -> null, (id) -> id, configuration, consumer);
|
||||
}
|
||||
|
||||
private void load(CachingConfigurationFactory cachingConfigurationFactory,
|
||||
EndpointPathResolver endpointPathResolver,
|
||||
Class<?> configuration, Consumer<WebAnnotationEndpointDiscoverer> consumer) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
configuration);
|
||||
@@ -254,7 +271,8 @@ public class WebAnnotationEndpointDiscovererTests {
|
||||
cachingConfigurationFactory,
|
||||
new EndpointMediaTypes(
|
||||
Collections.singletonList("application/json"),
|
||||
Collections.singletonList("application/json"))));
|
||||
Collections.singletonList("application/json")),
|
||||
endpointPathResolver));
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
|
||||
@@ -99,7 +99,7 @@ class JerseyEndpointsRunner extends AbstractWebEndpointRunner {
|
||||
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
|
||||
this.applicationContext,
|
||||
new ConversionServiceOperationParameterMapper(), (id) -> null,
|
||||
endpointMediaTypes);
|
||||
endpointMediaTypes, (id) -> id);
|
||||
Collection<Resource> resources = new JerseyEndpointResourceFactory()
|
||||
.createEndpointResources(new EndpointMapping("/application"),
|
||||
discoverer.discoverEndpoints(), endpointMediaTypes);
|
||||
|
||||
@@ -105,7 +105,7 @@ class WebFluxEndpointsRunner extends AbstractWebEndpointRunner {
|
||||
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
|
||||
this.applicationContext,
|
||||
new ConversionServiceOperationParameterMapper(), (id) -> null,
|
||||
endpointMediaTypes);
|
||||
endpointMediaTypes, (id) -> id);
|
||||
return new WebFluxEndpointHandlerMapping(new EndpointMapping("/application"),
|
||||
discoverer.discoverEndpoints(), endpointMediaTypes,
|
||||
new CorsConfiguration());
|
||||
|
||||
@@ -88,7 +88,7 @@ class WebMvcEndpointRunner extends AbstractWebEndpointRunner {
|
||||
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
|
||||
this.applicationContext,
|
||||
new ConversionServiceOperationParameterMapper(), (id) -> null,
|
||||
endpointMediaTypes);
|
||||
endpointMediaTypes, (id) -> id);
|
||||
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/application"),
|
||||
discoverer.discoverEndpoints(), endpointMediaTypes,
|
||||
new CorsConfiguration());
|
||||
|
||||
Reference in New Issue
Block a user