diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java index 38f7cc5c6f..e1f43db98c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java @@ -40,19 +40,19 @@ public enum AccessLevel { public static final String REQUEST_ATTRIBUTE = "cloudFoundryAccessLevel"; - private final List endpointIds; + private final List ids; - AccessLevel(String... endpointIds) { - this.endpointIds = Arrays.asList(endpointIds); + AccessLevel(String... ids) { + this.ids = Arrays.asList(ids); } /** - * Returns if the access level should allow access to the specified endpoint path. - * @param endpointId the endpoint ID to check + * Returns if the access level should allow access to the specified ID. + * @param id the ID to check * @return {@code true} if access is allowed */ - public boolean isAccessAllowed(String endpointId) { - return this.endpointIds.isEmpty() || this.endpointIds.contains(endpointId); + public boolean isAccessAllowed(String id) { + return this.ids.isEmpty() || this.ids.contains(id); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundrySecurityInterceptor.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundrySecurityInterceptor.java index 760b669090..355900d466 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundrySecurityInterceptor.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundrySecurityInterceptor.java @@ -59,7 +59,7 @@ class CloudFoundrySecurityInterceptor { this.applicationId = applicationId; } - Mono preHandle(ServerWebExchange exchange, String endpointId) { + Mono preHandle(ServerWebExchange exchange, String id) { ServerHttpRequest request = exchange.getRequest(); if (CorsUtils.isPreFlightRequest(request)) { return SUCCESS; @@ -72,7 +72,7 @@ class CloudFoundrySecurityInterceptor { return Mono.error(new CloudFoundryAuthorizationException( Reason.SERVICE_UNAVAILABLE, "Cloud controller URL is not available")); } - return check(exchange, endpointId).then(SUCCESS).doOnError(this::logError) + return check(exchange, id).then(SUCCESS).doOnError(this::logError) .onErrorResume(this::getErrorResponse); } @@ -80,13 +80,13 @@ class CloudFoundrySecurityInterceptor { logger.error(ex.getMessage(), ex); } - private Mono check(ServerWebExchange exchange, String path) { + private Mono check(ServerWebExchange exchange, String id) { try { Token token = getToken(exchange.getRequest()); return this.tokenValidator.validate(token) .then(this.cloudFoundrySecurityService .getAccessLevel(token.toString(), this.applicationId)) - .filter((accessLevel) -> accessLevel.isAccessAllowed(path)) + .filter((accessLevel) -> accessLevel.isAccessAllowed(id)) .switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException( Reason.ACCESS_DENIED, "Access denied"))) .doOnSuccess((accessLevel) -> exchange.getAttributes() diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java index 1cee0e313f..f8e1811adc 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java @@ -27,6 +27,7 @@ import reactor.core.publisher.Mono; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; @@ -70,7 +71,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping protected ReactiveWebOperation wrapReactiveWebOperation(ExposableWebEndpoint endpoint, WebOperation operation, ReactiveWebOperation reactiveWebOperation) { return new SecureReactiveWebOperation(reactiveWebOperation, - this.securityInterceptor, endpoint.getId()); + this.securityInterceptor, endpoint.getEndpointId()); } @Override @@ -113,10 +114,11 @@ class CloudFoundryWebFluxEndpointHandlerMapping private final CloudFoundrySecurityInterceptor securityInterceptor; - private final String endpointId; + private final EndpointId endpointId; SecureReactiveWebOperation(ReactiveWebOperation delegate, - CloudFoundrySecurityInterceptor securityInterceptor, String endpointId) { + CloudFoundrySecurityInterceptor securityInterceptor, + EndpointId endpointId) { this.delegate = delegate; this.securityInterceptor = securityInterceptor; this.endpointId = endpointId; @@ -125,7 +127,8 @@ class CloudFoundryWebFluxEndpointHandlerMapping @Override public Mono> handle(ServerWebExchange exchange, Map body) { - return this.securityInterceptor.preHandle(exchange, this.endpointId) + return this.securityInterceptor + .preHandle(exchange, this.endpointId.toLowerCaseString()) .flatMap((securityResponse) -> flatMapResponse(exchange, body, securityResponse)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java index cdca8b6aba..809e8a6930 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java @@ -28,6 +28,7 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryA import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.Token; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.util.StringUtils; @@ -59,7 +60,7 @@ class CloudFoundrySecurityInterceptor { this.applicationId = applicationId; } - SecurityResponse preHandle(HttpServletRequest request, String endpointId) { + SecurityResponse preHandle(HttpServletRequest request, EndpointId endpointId) { if (CorsUtils.isPreFlightRequest(request)) { return SecurityResponse.success(); } @@ -90,12 +91,14 @@ class CloudFoundrySecurityInterceptor { return SecurityResponse.success(); } - private void check(HttpServletRequest request, String endpointId) throws Exception { + private void check(HttpServletRequest request, EndpointId endpointId) + throws Exception { Token token = getToken(request); this.tokenValidator.validate(token); AccessLevel accessLevel = this.cloudFoundrySecurityService .getAccessLevel(token.toString(), this.applicationId); - if (!accessLevel.isAccessAllowed(endpointId)) { + if (!accessLevel.isAccessAllowed( + (endpointId != null) ? endpointId.toLowerCaseString() : "")) { throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied"); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java index 646c5d70dc..5b20e0fcbf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; @@ -68,7 +69,7 @@ class CloudFoundryWebEndpointServletHandlerMapping protected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint, WebOperation operation, ServletWebOperation servletWebOperation) { return new SecureServletWebOperation(servletWebOperation, - this.securityInterceptor, endpoint.getId()); + this.securityInterceptor, endpoint.getEndpointId()); } @Override @@ -76,7 +77,7 @@ class CloudFoundryWebEndpointServletHandlerMapping protected Map> links(HttpServletRequest request, HttpServletResponse response) { SecurityResponse securityResponse = this.securityInterceptor.preHandle(request, - ""); + null); if (!securityResponse.getStatus().equals(HttpStatus.OK)) { sendFailureResponse(response, securityResponse); } @@ -115,10 +116,11 @@ class CloudFoundryWebEndpointServletHandlerMapping private final CloudFoundrySecurityInterceptor securityInterceptor; - private final String endpointId; + private final EndpointId endpointId; SecureServletWebOperation(ServletWebOperation delegate, - CloudFoundrySecurityInterceptor securityInterceptor, String endpointId) { + CloudFoundrySecurityInterceptor securityInterceptor, + EndpointId endpointId) { this.delegate = delegate; this.securityInterceptor = securityInterceptor; this.endpointId = endpointId; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java index d61b0370c9..c435e84d94 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java @@ -110,7 +110,7 @@ public class ExposeExcludePropertyEndpointFilter> } private boolean contains(Set items, ExposableEndpoint endpoint) { - return items.contains(endpoint.getId().toLowerCase(Locale.ENGLISH)); + return items.contains(endpoint.getEndpointId().toLowerCaseString()); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java index c513b4933e..4a37c099a0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java @@ -52,7 +52,8 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { throws MalformedObjectNameException { StringBuilder builder = new StringBuilder(this.properties.getDomain()); builder.append(":type=Endpoint"); - builder.append(",name=" + StringUtils.capitalize(endpoint.getId())); + builder.append( + ",name=" + StringUtils.capitalize(endpoint.getEndpointId().toString())); String baseName = builder.toString(); if (this.mBeanServer != null && hasMBean(baseName)) { builder.append(",context=" + this.contextId); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapper.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapper.java index 6f4c1d078a..64bdbf39fd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapper.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapper.java @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.web; import java.util.Map; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.PathMapper; /** @@ -35,8 +36,14 @@ class MappingWebEndpointPathMapper implements PathMapper { } @Override + @Deprecated public String getRootPath(String endpointId) { - return this.pathMapping.getOrDefault(endpointId, endpointId); + return getRootPath(EndpointId.of(endpointId)); + } + + @Override + public String getRootPath(EndpointId endpointId) { + return this.pathMapping.getOrDefault(endpointId, endpointId.toLowerCaseString()); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java index 942e979d72..15ed8c5e2d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java @@ -31,6 +31,7 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints; import org.springframework.boot.security.reactive.ApplicationContextServerWebExchangeMatcher; @@ -208,9 +209,12 @@ public final class EndpointRequest { .map(pathMappedEndpoints::getPath); } - private String getEndpointId(Object source) { + private EndpointId getEndpointId(Object source) { + if (source instanceof EndpointId) { + return (EndpointId) source; + } if (source instanceof String) { - return (String) source; + return (EndpointId.of((String) source)); } if (source instanceof Class) { return getEndpointId((Class) source); @@ -218,12 +222,12 @@ public final class EndpointRequest { throw new IllegalStateException("Unsupported source " + source); } - private String getEndpointId(Class source) { + private EndpointId getEndpointId(Class source) { Endpoint annotation = AnnotatedElementUtils.getMergedAnnotation(source, Endpoint.class); Assert.state(annotation != null, () -> "Class " + source + " is not annotated with @Endpoint"); - return annotation.id(); + return EndpointId.of(annotation.id()); } private List getDelegateMatchers(Set paths) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index f3633bd7b1..625ec9f7c4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints; import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider; @@ -256,9 +257,12 @@ public final class EndpointRequest { .map(pathMappedEndpoints::getPath); } - private String getEndpointId(Object source) { + private EndpointId getEndpointId(Object source) { + if (source instanceof EndpointId) { + return (EndpointId) source; + } if (source instanceof String) { - return (String) source; + return (EndpointId.of((String) source)); } if (source instanceof Class) { return getEndpointId((Class) source); @@ -266,12 +270,12 @@ public final class EndpointRequest { throw new IllegalStateException("Unsupported source " + source); } - private String getEndpointId(Class source) { + private EndpointId getEndpointId(Class source) { Endpoint annotation = AnnotatedElementUtils.getMergedAnnotation(source, Endpoint.class); Assert.state(annotation != null, () -> "Class " + source + " is not annotated with @Endpoint"); - return annotation.id(); + return EndpointId.of(annotation.id()); } private List getDelegateMatchers( diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 31acdc8034..b40ea50a86 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -23,6 +23,7 @@ import java.util.function.Function; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -57,7 +58,7 @@ public class CloudFoundryWebEndpointDiscovererTests { Collection endpoints = discoverer.getEndpoints(); assertThat(endpoints.size()).isEqualTo(2); for (ExposableWebEndpoint endpoint : endpoints) { - if (endpoint.getId().equals("health")) { + if (endpoint.getEndpointId().equals(EndpointId.of("health"))) { WebOperation operation = endpoint.getOperations().iterator().next(); assertThat(operation.invoke(new InvocationContext( mock(SecurityContext.class), Collections.emptyMap()))) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index 111366da84..3a7e47bc5d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -33,6 +33,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfi import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @@ -243,9 +244,10 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests { context); Collection endpoints = handlerMapping .getEndpoints(); - List endpointIds = endpoints.stream() - .map(ExposableEndpoint::getId).collect(Collectors.toList()); - assertThat(endpointIds).contains("test"); + List endpointIds = endpoints.stream() + .map(ExposableEndpoint::getEndpointId) + .collect(Collectors.toList()); + assertThat(endpointIds).contains(EndpointId.of("test")); }); } @@ -261,7 +263,8 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests { Collection endpoints = handlerMapping .getEndpoints(); ExposableWebEndpoint endpoint = endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())) + .filter((candidate) -> EndpointId.of("test") + .equals(candidate.getEndpointId())) .findFirst().get(); assertThat(endpoint.getOperations()).hasSize(1); WebOperation operation = endpoint.getOperations().iterator().next(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index 94e6afde96..7dd77459ba 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -26,6 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; @@ -235,7 +236,8 @@ public class CloudFoundryActuatorAutoConfigurationTests { Collection endpoints = handlerMapping .getEndpoints(); assertThat(endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())) + .filter((candidate) -> EndpointId.of("test") + .equals(candidate.getEndpointId())) .findFirst()).isNotEmpty(); }); } @@ -253,7 +255,8 @@ public class CloudFoundryActuatorAutoConfigurationTests { Collection endpoints = handlerMapping .getEndpoints(); ExposableWebEndpoint endpoint = endpoints.stream() - .filter((candidate) -> "test".equals(candidate.getId())) + .filter((candidate) -> EndpointId.of("test") + .equals(candidate.getEndpointId())) .findFirst().get(); Collection operations = endpoint.getOperations(); assertThat(operations).hasSize(1); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptorTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptorTests.java index d1b4da936d..d43668c5e8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptorTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,6 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.Token; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletRequest; @@ -65,13 +66,15 @@ public class CloudFoundrySecurityInterceptorTests { this.request.setMethod("OPTIONS"); this.request.addHeader(HttpHeaders.ORIGIN, "http://example.com"); this.request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); } @Test public void preHandleWhenTokenIsMissingShouldReturnFalse() { - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()) .isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus()); } @@ -79,7 +82,8 @@ public class CloudFoundrySecurityInterceptorTests { @Test public void preHandleWhenTokenIsNotBearerShouldReturnFalse() { this.request.addHeader("Authorization", mockAccessToken()); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()) .isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus()); } @@ -89,7 +93,8 @@ public class CloudFoundrySecurityInterceptorTests { this.interceptor = new CloudFoundrySecurityInterceptor(this.tokenValidator, this.securityService, null); this.request.addHeader("Authorization", "bearer " + mockAccessToken()); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()) .isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus()); } @@ -99,7 +104,8 @@ public class CloudFoundrySecurityInterceptorTests { this.interceptor = new CloudFoundrySecurityInterceptor(this.tokenValidator, null, "my-app-id"); this.request.addHeader("Authorization", "bearer " + mockAccessToken()); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()) .isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus()); } @@ -110,7 +116,8 @@ public class CloudFoundrySecurityInterceptorTests { this.request.addHeader("Authorization", "bearer " + accessToken); given(this.securityService.getAccessLevel(accessToken, "my-app-id")) .willReturn(AccessLevel.RESTRICTED); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); assertThat(response.getStatus()).isEqualTo(Reason.ACCESS_DENIED.getStatus()); } @@ -120,7 +127,8 @@ public class CloudFoundrySecurityInterceptorTests { this.request.addHeader("Authorization", "Bearer " + accessToken); given(this.securityService.getAccessLevel(accessToken, "my-app-id")) .willReturn(AccessLevel.FULL); - SecurityResponse response = this.interceptor.preHandle(this.request, "/a"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("test")); ArgumentCaptor tokenArgumentCaptor = ArgumentCaptor.forClass(Token.class); verify(this.tokenValidator).validate(tokenArgumentCaptor.capture()); Token token = tokenArgumentCaptor.getValue(); @@ -136,7 +144,8 @@ public class CloudFoundrySecurityInterceptorTests { this.request.addHeader("Authorization", "Bearer " + accessToken); given(this.securityService.getAccessLevel(accessToken, "my-app-id")) .willReturn(AccessLevel.RESTRICTED); - SecurityResponse response = this.interceptor.preHandle(this.request, "info"); + SecurityResponse response = this.interceptor.preHandle(this.request, + EndpointId.of("info")); ArgumentCaptor tokenArgumentCaptor = ArgumentCaptor.forClass(Token.class); verify(this.tokenValidator).validate(tokenArgumentCaptor.capture()); Token token = tokenArgumentCaptor.getValue(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilterTests.java index 0b6b62555b..e386c989a2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilterTests.java @@ -23,6 +23,7 @@ import org.junit.rules.ExpectedException; import org.mockito.MockitoAnnotations; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.mock.env.MockEnvironment; @@ -81,43 +82,43 @@ public class ExposeExcludePropertyEndpointFilterTests { @Test public void matchWhenExposeIsEmptyAndExcludeIsEmptyAndInDefaultShouldMatch() { setupFilter("", ""); - assertThat(match("def")).isTrue(); + assertThat(match(EndpointId.of("def"))).isTrue(); } @Test public void matchWhenExposeIsEmptyAndExcludeIsEmptyAndNotInDefaultShouldNotMatch() { setupFilter("", ""); - assertThat(match("bar")).isFalse(); + assertThat(match(EndpointId.of("bar"))).isFalse(); } @Test public void matchWhenExposeMatchesAndExcludeIsEmptyShouldMatch() { setupFilter("bar", ""); - assertThat(match("bar")).isTrue(); + assertThat(match(EndpointId.of("bar"))).isTrue(); } @Test public void matchWhenExposeDoesNotMatchAndExcludeIsEmptyShouldNotMatch() { setupFilter("bar", ""); - assertThat(match("baz")).isFalse(); + assertThat(match(EndpointId.of("baz"))).isFalse(); } @Test public void matchWhenExposeMatchesAndExcludeMatchesShouldNotMatch() { setupFilter("bar,baz", "baz"); - assertThat(match("baz")).isFalse(); + assertThat(match(EndpointId.of("baz"))).isFalse(); } @Test public void matchWhenExposeMatchesAndExcludeDoesNotMatchShouldMatch() { setupFilter("bar,baz", "buz"); - assertThat(match("baz")).isTrue(); + assertThat(match(EndpointId.of("baz"))).isTrue(); } @Test public void matchWhenExposeMatchesWithDifferentCaseShouldMatch() { setupFilter("bar", ""); - assertThat(match("bAr")).isTrue(); + assertThat(match(EndpointId.of("bAr"))).isTrue(); } @Test @@ -127,23 +128,23 @@ public class ExposeExcludePropertyEndpointFilterTests { environment.setProperty("foo.exclude", ""); this.filter = new ExposeExcludePropertyEndpointFilter<>( DifferentTestExposableWebEndpoint.class, environment, "foo"); - assertThat(match("baz")).isTrue(); + assertThat(match(EndpointId.of("baz"))).isTrue(); } @Test public void matchWhenIncludeIsAsteriskShouldMatchAll() { setupFilter("*", "buz"); - assertThat(match("bar")).isTrue(); - assertThat(match("baz")).isTrue(); - assertThat(match("buz")).isFalse(); + assertThat(match(EndpointId.of("bar"))).isTrue(); + assertThat(match(EndpointId.of("baz"))).isTrue(); + assertThat(match(EndpointId.of("buz"))).isFalse(); } @Test public void matchWhenExcludeIsAsteriskShouldMatchNone() { setupFilter("bar,baz,buz", "*"); - assertThat(match("bar")).isFalse(); - assertThat(match("baz")).isFalse(); - assertThat(match("buz")).isFalse(); + assertThat(match(EndpointId.of("bar"))).isFalse(); + assertThat(match(EndpointId.of("baz"))).isFalse(); + assertThat(match(EndpointId.of("buz"))).isFalse(); } private void setupFilter(String include, String exclude) { @@ -155,9 +156,9 @@ public class ExposeExcludePropertyEndpointFilterTests { } @SuppressWarnings({ "rawtypes", "unchecked" }) - private boolean match(String id) { + private boolean match(EndpointId id) { ExposableEndpoint endpoint = mock(TestExposableWebEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); return ((EndpointFilter) this.filter).match(endpoint); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java index 08ebe3e580..0b34899bc9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java @@ -24,6 +24,7 @@ import javax.management.ObjectName; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; import org.springframework.mock.env.MockEnvironment; import org.springframework.util.ObjectUtils; @@ -50,22 +51,23 @@ public class DefaultEndpointObjectNameFactoryTests { @Test public void generateObjectName() { - ObjectName objectName = generateObjectName(endpoint("Test")); + ObjectName objectName = generateObjectName(endpoint(EndpointId.of("test"))); assertThat(objectName.toString()) .isEqualTo("org.springframework.boot:type=Endpoint,name=Test"); } @Test public void generateObjectNameWithCapitalizedId() { - ObjectName objectName = generateObjectName(endpoint("test")); + ObjectName objectName = generateObjectName( + endpoint(EndpointId.of("testEndpoint"))); assertThat(objectName.toString()) - .isEqualTo("org.springframework.boot:type=Endpoint,name=Test"); + .isEqualTo("org.springframework.boot:type=Endpoint,name=TestEndpoint"); } @Test public void generateObjectNameWithCustomDomain() { this.properties.setDomain("com.example.acme"); - ObjectName objectName = generateObjectName(endpoint("test")); + ObjectName objectName = generateObjectName(endpoint(EndpointId.of("test"))); assertThat(objectName.toString()) .isEqualTo("com.example.acme:type=Endpoint,name=Test"); } @@ -73,7 +75,7 @@ public class DefaultEndpointObjectNameFactoryTests { @Test public void generateObjectNameWithUniqueNames() { this.properties.setUniqueNames(true); - ExposableJmxEndpoint endpoint = endpoint("test"); + ExposableJmxEndpoint endpoint = endpoint(EndpointId.of("test")); String id = ObjectUtils.getIdentityHexString(endpoint); ObjectName objectName = generateObjectName(endpoint); assertThat(objectName.toString()).isEqualTo( @@ -84,7 +86,7 @@ public class DefaultEndpointObjectNameFactoryTests { public void generateObjectNameWithStaticNames() { this.properties.getStaticNames().setProperty("counter", "42"); this.properties.getStaticNames().setProperty("foo", "bar"); - ObjectName objectName = generateObjectName(endpoint("test")); + ObjectName objectName = generateObjectName(endpoint(EndpointId.of("test"))); assertThat(objectName.getKeyProperty("counter")).isEqualTo("42"); assertThat(objectName.getKeyProperty("foo")).isEqualTo("bar"); assertThat(objectName.toString()) @@ -99,7 +101,7 @@ public class DefaultEndpointObjectNameFactoryTests { null)).willReturn( Collections.singleton(new ObjectName( "org.springframework.boot:type=Endpoint,name=Test"))); - ObjectName objectName = generateObjectName(endpoint("test")); + ObjectName objectName = generateObjectName(endpoint(EndpointId.of("test"))); assertThat(objectName.toString()).isEqualTo( "org.springframework.boot:type=Endpoint,name=Test,context=testContext"); @@ -115,9 +117,9 @@ public class DefaultEndpointObjectNameFactoryTests { } } - private ExposableJmxEndpoint endpoint(String id) { + private ExposableJmxEndpoint endpoint(EndpointId id) { ExposableJmxEndpoint endpoint = mock(ExposableJmxEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); return endpoint; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapperTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapperTests.java index 0a1fffdfd7..a16acdddbd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapperTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapperTests.java @@ -20,6 +20,8 @@ import java.util.Collections; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -33,14 +35,14 @@ public class MappingWebEndpointPathMapperTests { public void defaultConfiguration() { MappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper( Collections.emptyMap()); - assertThat(mapper.getRootPath("test")).isEqualTo("test"); + assertThat(mapper.getRootPath(EndpointId.of("test"))).isEqualTo("test"); } @Test public void userConfiguration() { MappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper( Collections.singletonMap("test", "custom")); - assertThat(mapper.getRootPath("test")).isEqualTo("custom"); + assertThat(mapper.getRootPath(EndpointId.of("test"))).isEqualTo("custom"); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfigurationTests.java index 54cb1a1309..b662a99009 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfigurationTests.java @@ -20,6 +20,7 @@ import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.PathMapper; @@ -65,7 +66,7 @@ public class WebEndpointAutoConfigurationTests { .run((context) -> { assertThat(context).hasSingleBean(PathMapper.class); String pathMapping = context.getBean(PathMapper.class) - .getRootPath("health"); + .getRootPath(EndpointId.of("health")); assertThat(pathMapping).isEqualTo("healthcheck"); }); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java index e8178c3f14..52cd393267 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java @@ -23,6 +23,7 @@ import org.assertj.core.api.AssertDelegateTarget; import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -129,9 +130,9 @@ public class EndpointRequestTests { ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint() .excluding(FooEndpoint.class, BazServletEndpoint.class); List> endpoints = new ArrayList<>(); - endpoints.add(mockEndpoint("foo", "foo")); - endpoints.add(mockEndpoint("bar", "bar")); - endpoints.add(mockEndpoint("baz", "baz")); + endpoints.add(mockEndpoint(EndpointId.of("foo"), "foo")); + endpoints.add(mockEndpoint(EndpointId.of("bar"), "bar")); + endpoints.add(mockEndpoint(EndpointId.of("baz"), "baz")); PathMappedEndpoints pathMappedEndpoints = new PathMappedEndpoints("/actuator", () -> endpoints); assertMatcher(matcher, pathMappedEndpoints).doesNotMatch("/actuator/foo"); @@ -202,14 +203,14 @@ public class EndpointRequestTests { private PathMappedEndpoints mockPathMappedEndpoints(String basePath) { List> endpoints = new ArrayList<>(); - endpoints.add(mockEndpoint("foo", "foo")); - endpoints.add(mockEndpoint("bar", "bar")); + endpoints.add(mockEndpoint(EndpointId.of("foo"), "foo")); + endpoints.add(mockEndpoint(EndpointId.of("bar"), "bar")); return new PathMappedEndpoints(basePath, () -> endpoints); } - private TestEndpoint mockEndpoint(String id, String rootPath) { + private TestEndpoint mockEndpoint(EndpointId id, String rootPath) { TestEndpoint endpoint = mock(TestEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); given(endpoint.getRootPath()).willReturn(rootPath); return endpoint; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java index 4d194c7393..3ea45365ad 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java @@ -25,6 +25,7 @@ import org.assertj.core.api.AssertDelegateTarget; import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -163,9 +164,9 @@ public class EndpointRequestTests { RequestMatcher matcher = EndpointRequest.toAnyEndpoint() .excluding(FooEndpoint.class, BazServletEndpoint.class); List> endpoints = new ArrayList<>(); - endpoints.add(mockEndpoint("foo", "foo")); - endpoints.add(mockEndpoint("bar", "bar")); - endpoints.add(mockEndpoint("baz", "baz")); + endpoints.add(mockEndpoint(EndpointId.of("foo"), "foo")); + endpoints.add(mockEndpoint(EndpointId.of("bar"), "bar")); + endpoints.add(mockEndpoint(EndpointId.of("baz"), "baz")); PathMappedEndpoints pathMappedEndpoints = new PathMappedEndpoints("/actuator", () -> endpoints); assertMatcher(matcher, pathMappedEndpoints).doesNotMatch("/actuator/foo"); @@ -258,14 +259,14 @@ public class EndpointRequestTests { private PathMappedEndpoints mockPathMappedEndpoints(String basePath) { List> endpoints = new ArrayList<>(); - endpoints.add(mockEndpoint("foo", "foo")); - endpoints.add(mockEndpoint("bar", "bar")); + endpoints.add(mockEndpoint(EndpointId.of("foo"), "foo")); + endpoints.add(mockEndpoint(EndpointId.of("bar"), "bar")); return new PathMappedEndpoints(basePath, () -> endpoints); } - private TestEndpoint mockEndpoint(String id, String rootPath) { + private TestEndpoint mockEndpoint(EndpointId id, String rootPath) { TestEndpoint endpoint = mock(TestEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); given(endpoint.getRootPath()).willReturn(rootPath); return endpoint; } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractExposableEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractExposableEndpoint.java index c7a87cdf2b..e2e762ab75 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractExposableEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractExposableEndpoint.java @@ -33,7 +33,7 @@ import org.springframework.util.Assert; public abstract class AbstractExposableEndpoint implements ExposableEndpoint { - private final String id; + private final EndpointId id; private boolean enabledByDefault; @@ -44,9 +44,24 @@ public abstract class AbstractExposableEndpoint * @param id the endpoint id * @param enabledByDefault if the endpoint is enabled by default * @param operations the endpoint operations + * @deprecated since 2.0.6 in favor of + * {@link #AbstractExposableEndpoint(EndpointId, boolean, Collection)} */ + @Deprecated public AbstractExposableEndpoint(String id, boolean enabledByDefault, Collection operations) { + this(EndpointId.of(id), enabledByDefault, operations); + } + + /** + * Create a new {@link AbstractExposableEndpoint} instance. + * @param id the endpoint id + * @param enabledByDefault if the endpoint is enabled by default + * @param operations the endpoint operations + * @since 2.0.6 + */ + public AbstractExposableEndpoint(EndpointId id, boolean enabledByDefault, + Collection operations) { Assert.notNull(id, "ID must not be null"); Assert.notNull(operations, "Operations must not be null"); this.id = id; @@ -56,7 +71,7 @@ public abstract class AbstractExposableEndpoint @Override public String getId() { - return this.id; + return this.id.toString(); } @Override diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java new file mode 100644 index 0000000000..246ff3c29d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2018 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; + +import java.util.Locale; +import java.util.regex.Pattern; + +import org.springframework.util.Assert; + +/** + * An identifier for an actuator endpoint. Endpoint IDs may contain only letters and + * numbers and must begin with a lower-case letter. Case is ignored when comparing + * endpoint IDs. + * + * @author Phillip Webb + * @since 2.0.6 + */ +public final class EndpointId { + + private static final Pattern ALPHA_NUMERIC = Pattern.compile("[a-zA-Z0-9]+"); + + private final String value; + + private final String lowerCaseValue; + + private EndpointId(String value) { + Assert.hasText(value, "Value must not be empty"); + Assert.isTrue(ALPHA_NUMERIC.matcher(value).matches(), + "Value must be alpha-numeric"); + Assert.isTrue(!Character.isDigit(value.charAt(0)), + "Value must not start with a number"); + Assert.isTrue(!Character.isUpperCase(value.charAt(0)), + "Value must not start with an uppercase letter"); + this.value = value; + this.lowerCaseValue = value.toLowerCase(Locale.ENGLISH); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return toLowerCaseString().equals(((EndpointId) obj).toLowerCaseString()); + } + + @Override + public int hashCode() { + return toLowerCaseString().hashCode(); + } + + /** + * Return a lower-case version of the endpoint ID. + * @return the lower-case endpoint ID + */ + public String toLowerCaseString() { + return this.lowerCaseValue; + } + + @Override + public String toString() { + return this.value; + } + + /** + * Factory method to create a new {@link EndpointId} of the specified value. + * @param value the endpoint ID value + * @return an {@link EndpointId} instance + */ + public static EndpointId of(String value) { + return new EndpointId(value); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ExposableEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ExposableEndpoint.java index 64dce2f9d1..f9984ff20e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ExposableEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ExposableEndpoint.java @@ -31,9 +31,20 @@ public interface ExposableEndpoint { /** * Returns the id of the endpoint. * @return the id + * @deprecated since 2.0.6 in favor of {@link #getEndpointId()} */ + @Deprecated String getId(); + /** + * Return the endpoint ID. + * @return the endpoint ID + * @since 2.0.6 + */ + default EndpointId getEndpointId() { + return EndpointId.of(getId()); + } + /** * Returns if the endpoint is enabled by default. * @return if the endpoint is enabled by default diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredEndpoint.java index 6cd73db8e8..6c582f9fe0 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredEndpoint.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.annotation; import java.util.Collection; import org.springframework.boot.actuate.endpoint.AbstractExposableEndpoint; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.core.style.ToStringCreator; @@ -46,10 +47,28 @@ public abstract class AbstractDiscoveredEndpoint * @param id the ID of the endpoint * @param enabledByDefault if the endpoint is enabled by default * @param operations the endpoint operations + * @deprecated since 2.0.6 in favor of + * {@link #AbstractDiscoveredEndpoint(EndpointDiscoverer, Object, EndpointId, boolean, Collection)} */ + @Deprecated public AbstractDiscoveredEndpoint(EndpointDiscoverer discoverer, Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + this(discoverer, endpointBean, EndpointId.of(id), enabledByDefault, operations); + } + + /** + * Create a new {@link AbstractDiscoveredEndpoint} instance. + * @param discoverer the discoverer that discovered the endpoint + * @param endpointBean the primary source bean + * @param id the ID of the endpoint + * @param enabledByDefault if the endpoint is enabled by default + * @param operations the endpoint operations + * @since 2.0.6 + */ + public AbstractDiscoveredEndpoint(EndpointDiscoverer discoverer, + Object endpointBean, EndpointId id, boolean enabledByDefault, + Collection operations) { super(id, enabledByDefault, operations); Assert.notNull(discoverer, "Discoverer must not be null"); Assert.notNull(endpointBean, "EndpointBean must not be null"); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactory.java index 6a900109a0..3397f5f7e3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactory.java @@ -24,6 +24,7 @@ import java.util.EnumMap; import java.util.Map; import java.util.Objects; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -68,20 +69,20 @@ abstract class DiscoveredOperationsFactory { this.invokerAdvisors = invokerAdvisors; } - public Collection createOperations(String id, Object target) { + public Collection createOperations(EndpointId id, Object target) { return MethodIntrospector.selectMethods(target.getClass(), (MetadataLookup) (method) -> createOperation(id, target, method)) .values(); } - private O createOperation(String endpointId, Object target, Method method) { + private O createOperation(EndpointId endpointId, Object target, Method method) { return OPERATION_TYPES.entrySet().stream() .map((entry) -> createOperation(endpointId, target, method, entry.getKey(), entry.getValue())) .filter(Objects::nonNull).findFirst().orElse(null); } - private O createOperation(String endpointId, Object target, Method method, + private O createOperation(EndpointId endpointId, Object target, Method method, OperationType operationType, Class annotationType) { AnnotationAttributes annotationAttributes = AnnotatedElementUtils .getMergedAnnotationAttributes(method, annotationType); @@ -96,7 +97,7 @@ abstract class DiscoveredOperationsFactory { return createOperation(endpointId, operationMethod, invoker); } - private OperationInvoker applyAdvisors(String endpointId, + private OperationInvoker applyAdvisors(EndpointId endpointId, OperationMethod operationMethod, OperationInvoker invoker) { if (this.invokerAdvisors != null) { for (OperationInvokerAdvisor advisor : this.invokerAdvisors) { @@ -107,7 +108,7 @@ abstract class DiscoveredOperationsFactory { return invoker; } - protected abstract O createOperation(String endpointId, + protected abstract O createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java index 94fff19801..ea5a396b6b 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java @@ -22,6 +22,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.boot.actuate.endpoint.EndpointId; + /** * Identifies a type as being an actuator endpoint that provides information about the * running application. Endpoints can be exposed over a variety of technologies including @@ -52,8 +54,9 @@ import java.lang.annotation.Target; public @interface Endpoint { /** - * The id of the endpoint. + * The id of the endpoint (must follow {@link EndpointId} rules). * @return the id + * @see EndpointId */ String id() default ""; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java index 57aac62bc9..92d59d3d03 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointsSupplier; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; @@ -101,7 +102,7 @@ public abstract class EndpointDiscoverer, O exten return new DiscoveredOperationsFactory(parameterValueMapper, invokerAdvisors) { @Override - protected O createOperation(String endpointId, + protected O createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { return EndpointDiscoverer.this.createOperation(endpointId, operationMethod, invoker); @@ -125,7 +126,7 @@ public abstract class EndpointDiscoverer, O exten } private Collection createEndpointBeans() { - Map byId = new LinkedHashMap<>(); + Map byId = new LinkedHashMap<>(); String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors( this.applicationContext, Endpoint.class); for (String beanName : beanNames) { @@ -145,7 +146,7 @@ public abstract class EndpointDiscoverer, O exten } private void addExtensionBeans(Collection endpointBeans) { - Map byId = endpointBeans.stream() + Map byId = endpointBeans.stream() .collect(Collectors.toMap(EndpointBean::getId, (bean) -> bean)); String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors( this.applicationContext, EndpointExtension.class); @@ -189,7 +190,7 @@ public abstract class EndpointDiscoverer, O exten private E convertToEndpoint(EndpointBean endpointBean) { MultiValueMap indexed = new LinkedMultiValueMap<>(); - String id = endpointBean.getId(); + EndpointId id = endpointBean.getId(); addOperations(indexed, id, endpointBean.getBean(), false); if (endpointBean.getExtensions().size() > 1) { String extensionBeans = endpointBean.getExtensions().stream() @@ -209,7 +210,7 @@ public abstract class EndpointDiscoverer, O exten endpointBean.isEnabledByDefault(), operations); } - private void addOperations(MultiValueMap indexed, String id, + private void addOperations(MultiValueMap indexed, EndpointId id, Object target, boolean replaceLast) { Set replacedLast = new HashSet<>(); Collection operations = this.operationsFactory.createOperations(id, target); @@ -339,7 +340,25 @@ public abstract class EndpointDiscoverer, O exten * @param enabledByDefault if the endpoint is enabled by default * @param operations the endpoint operations * @return a created endpoint (a {@link DiscoveredEndpoint} is recommended) + * @since 2.0.6 */ + protected E createEndpoint(Object endpointBean, EndpointId id, + boolean enabledByDefault, Collection operations) { + return createEndpoint(endpointBean, (id != null) ? id.toString() : null, + enabledByDefault, operations); + } + + /** + * Factory method called to create the {@link ExposableEndpoint endpoint}. + * @param endpointBean the source endpoint bean + * @param id the ID of the endpoint + * @param enabledByDefault if the endpoint is enabled by default + * @param operations the endpoint operations + * @return a created endpoint (a {@link DiscoveredEndpoint} is recommended) + * @deprecated Since 2.0.6 in favor of + * {@link #createEndpoint(Object, EndpointId, boolean, Collection)} + */ + @Deprecated protected abstract E createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations); @@ -349,7 +368,24 @@ public abstract class EndpointDiscoverer, O exten * @param operationMethod the operation method * @param invoker the invoker to use * @return a created operation + * @since 2.0.6 */ + protected O createOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { + return createOperation((endpointId != null) ? endpointId.toString() : null, + operationMethod, invoker); + } + + /** + * Factory method to create an {@link Operation endpoint operation}. + * @param endpointId the endpoint id + * @param operationMethod the operation method + * @param invoker the invoker to use + * @return a created operation + * @deprecated since 2.0.6 in favor of + * {@link #createOperation(EndpointId, DiscoveredOperationMethod, OperationInvoker)} + */ + @Deprecated protected abstract O createOperation(String endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker); @@ -414,7 +450,7 @@ public abstract class EndpointDiscoverer, O exten private final Object bean; - private final String id; + private final EndpointId id; private boolean enabledByDefault; @@ -426,14 +462,15 @@ public abstract class EndpointDiscoverer, O exten AnnotationAttributes attributes = AnnotatedElementUtils .findMergedAnnotationAttributes(bean.getClass(), Endpoint.class, true, true); + String id = attributes.getString("id"); + Assert.state(StringUtils.hasText(id), + () -> "No @Endpoint id attribute specified for " + + bean.getClass().getName()); this.beanName = beanName; this.bean = bean; - this.id = attributes.getString("id"); + this.id = EndpointId.of(id); this.enabledByDefault = (Boolean) attributes.get("enableByDefault"); this.filter = getFilter(this.bean.getClass()); - Assert.state(StringUtils.hasText(this.id), - () -> "No @Endpoint id attribute specified for " - + bean.getClass().getName()); } public void addExtension(ExtensionBean extensionBean) { @@ -461,7 +498,7 @@ public abstract class EndpointDiscoverer, O exten return this.bean; } - public String getId() { + public EndpointId getId() { return this.id; } @@ -484,7 +521,7 @@ public abstract class EndpointDiscoverer, O exten private final Object bean; - private final String endpointId; + private final EndpointId endpointId; private final Class filter; @@ -500,7 +537,7 @@ public abstract class EndpointDiscoverer, O exten true); Assert.state(endpointAttributes != null, () -> "Extension " + endpointType.getName() + " does not specify an endpoint"); - this.endpointId = endpointAttributes.getString("id"); + this.endpointId = EndpointId.of(endpointAttributes.getString("id")); this.filter = attributes.getClass("filter"); } @@ -512,7 +549,7 @@ public abstract class EndpointDiscoverer, O exten return this.bean; } - public String getEndpointId() { + public EndpointId getEndpointId() { return this.endpointId; } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvokerAdvisor.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvokerAdvisor.java index 841cf4d0b7..ab0d0edd72 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvokerAdvisor.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvokerAdvisor.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.endpoint.invoke; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.OperationType; /** @@ -34,7 +35,25 @@ public interface OperationInvokerAdvisor { * @param parameters the operation parameters * @param invoker the invoker to advise * @return an potentially new operation invoker with support for additional features + * @since 2.0.6 */ + default OperationInvoker apply(EndpointId endpointId, OperationType operationType, + OperationParameters parameters, OperationInvoker invoker) { + return apply((endpointId != null) ? endpointId.toString() : null, operationType, + parameters, invoker); + } + + /** + * Apply additional functionality to the given invoker. + * @param endpointId the endpoint ID + * @param operationType the operation type + * @param parameters the operation parameters + * @param invoker the invoker to advise + * @return an potentially new operation invoker with support for additional features + * @deprecated since 2.0.6 in favor of + * {@link #apply(EndpointId, OperationType, OperationParameters, OperationInvoker)} + */ + @Deprecated OperationInvoker apply(String endpointId, OperationType operationType, OperationParameters parameters, OperationInvoker invoker); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java index a1503249b3..4e37f4e30a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java @@ -40,6 +40,7 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { } @Override + @Deprecated public OperationInvoker apply(String endpointId, OperationType operationType, OperationParameters parameters, OperationInvoker invoker) { if (operationType == OperationType.READ && !hasMandatoryParameter(parameters)) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java index 7d1c38bf64..a3a87929fe 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java @@ -89,7 +89,7 @@ public class EndpointMBean implements DynamicMBean { throws MBeanException, ReflectionException { JmxOperation operation = this.operations.get(actionName); if (operation == null) { - String message = "Endpoint with id '" + this.endpoint.getId() + String message = "Endpoint with id '" + this.endpoint.getEndpointId() + "' has no operation named " + actionName; throw new ReflectionException(new IllegalArgumentException(message), message); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporter.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporter.java index 33aa7e64c4..9750c59e45 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporter.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporter.java @@ -136,7 +136,7 @@ public class JmxEndpointExporter } private String getEndpointDescription(ExposableJmxEndpoint endpoint) { - return "endpoint '" + endpoint.getId() + "'"; + return "endpoint '" + endpoint.getEndpointId() + "'"; } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactory.java index 953625a873..63f86e44d6 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactory.java @@ -58,7 +58,7 @@ class MBeanInfoFactory { } private String getDescription(ExposableJmxEndpoint endpoint) { - return "MBean operations for endpoint " + endpoint.getId(); + return "MBean operations for endpoint " + endpoint.getEndpointId(); } private ModelMBeanOperationInfo[] getMBeanOperations(ExposableJmxEndpoint endpoint) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxEndpoint.java index 7b7b9fce09..9d336dcbb3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxEndpoint.java @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.jmx.annotation; import java.util.Collection; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; @@ -32,7 +33,8 @@ class DiscoveredJmxEndpoint extends AbstractDiscoveredEndpoint implements ExposableJmxEndpoint { DiscoveredJmxEndpoint(EndpointDiscoverer discoverer, Object endpointBean, - String id, boolean enabledByDefault, Collection operations) { + EndpointId id, boolean enabledByDefault, + Collection operations) { super(discoverer, endpointBean, id, enabledByDefault, operations); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperation.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperation.java index 1f1d3d80c9..22ff75c3fd 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperation.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperation.java @@ -26,6 +26,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -59,8 +60,8 @@ class DiscoveredJmxOperation extends AbstractDiscoveredOperation implements JmxO private final List parameters; - DiscoveredJmxOperation(String endpointId, DiscoveredOperationMethod operationMethod, - OperationInvoker invoker) { + DiscoveredJmxOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { super(operationMethod, invoker); Method method = operationMethod.getMethod(); this.name = method.getName(); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java index 264afdfcf5..7037475ce7 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.jmx.annotation; import java.util.Collection; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -54,15 +55,30 @@ public class JmxEndpointDiscoverer } @Override + @Deprecated protected ExposableJmxEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + return createEndpoint(endpointBean, EndpointId.of(id), enabledByDefault, + operations); + } + + @Override + protected ExposableJmxEndpoint createEndpoint(Object endpointBean, EndpointId id, + boolean enabledByDefault, Collection operations) { return new DiscoveredJmxEndpoint(this, endpointBean, id, enabledByDefault, operations); } @Override + @Deprecated protected JmxOperation createOperation(String endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { + return createOperation(EndpointId.of(endpointId), operationMethod, invoker); + } + + @Override + protected JmxOperation createOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { return new DiscoveredJmxOperation(endpointId, operationMethod, invoker); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolver.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolver.java index de2348b524..88385c7cdf 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolver.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolver.java @@ -76,8 +76,9 @@ public class EndpointLinksResolver { collectLinks(links, (ExposableWebEndpoint) endpoint, normalizedUrl); } else if (endpoint instanceof PathMappedEndpoint) { - links.put(endpoint.getId(), createLink(normalizedUrl, - ((PathMappedEndpoint) endpoint).getRootPath())); + String rootPath = ((PathMappedEndpoint) endpoint).getRootPath(); + Link link = createLink(normalizedUrl, rootPath); + links.put(endpoint.getEndpointId().toLowerCaseString(), link); } } return links; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoints.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoints.java index b2d270fb20..a3392e87be 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoints.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoints.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointsSupplier; import org.springframework.util.Assert; @@ -37,7 +38,7 @@ public class PathMappedEndpoints implements Iterable { private final String basePath; - private final Map endpoints; + private final Map endpoints; /** * Create a new {@link PathMappedEndpoints} instance for the given supplier. @@ -62,13 +63,14 @@ public class PathMappedEndpoints implements Iterable { this.endpoints = getEndpoints(suppliers); } - private Map getEndpoints( + private Map getEndpoints( Collection> suppliers) { - Map endpoints = new LinkedHashMap<>(); + Map endpoints = new LinkedHashMap<>(); suppliers.forEach((supplier) -> { supplier.getEndpoints().forEach((endpoint) -> { if (endpoint instanceof PathMappedEndpoint) { - endpoints.put(endpoint.getId(), (PathMappedEndpoint) endpoint); + endpoints.put(endpoint.getEndpointId(), + (PathMappedEndpoint) endpoint); } }); }); @@ -88,8 +90,21 @@ public class PathMappedEndpoints implements Iterable { * endpoint cannot be found. * @param endpointId the endpoint ID * @return the root path or {@code null} + * @deprecated since 2.0.6 in favor of {@link #getRootPath(EndpointId)} */ + @Deprecated public String getRootPath(String endpointId) { + return getRootPath(EndpointId.of(endpointId)); + } + + /** + * Return the root path for the endpoint with the given ID or {@code null} if the + * endpoint cannot be found. + * @param endpointId the endpoint ID + * @return the root path or {@code null} + * @since 2.0.6 + */ + public String getRootPath(EndpointId endpointId) { PathMappedEndpoint endpoint = getEndpoint(endpointId); return (endpoint != null) ? endpoint.getRootPath() : null; } @@ -99,8 +114,21 @@ public class PathMappedEndpoints implements Iterable { * endpoint cannot be found. * @param endpointId the endpoint ID * @return the full path or {@code null} + * @deprecated since 2.0.6 in favor of {@link #getPath(EndpointId)} */ + @Deprecated public String getPath(String endpointId) { + return getPath(EndpointId.of(endpointId)); + } + + /** + * Return the full path for the endpoint with the given ID or {@code null} if the + * endpoint cannot be found. + * @param endpointId the endpoint ID + * @return the full path or {@code null} + * @since 2.0.6 + */ + public String getPath(EndpointId endpointId) { return getPath(getEndpoint(endpointId)); } @@ -125,8 +153,21 @@ public class PathMappedEndpoints implements Iterable { * endpoint cannot be found. * @param endpointId the endpoint ID * @return the path mapped endpoint or {@code null} + * @deprecated since 2.0.6 in favor of {@link #getEndpoint(EndpointId)} */ + @Deprecated public PathMappedEndpoint getEndpoint(String endpointId) { + return getEndpoint(EndpointId.of(endpointId)); + } + + /** + * Return the {@link PathMappedEndpoint} with the given ID or {@code null} if the + * endpoint cannot be found. + * @param endpointId the endpoint ID + * @return the path mapped endpoint or {@code null} + * @since 2.0.6 + */ + public PathMappedEndpoint getEndpoint(EndpointId endpointId) { return this.endpoints.get(endpointId); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMapper.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMapper.java index b9116b278d..12af95b1fd 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMapper.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMapper.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.endpoint.web; +import org.springframework.boot.actuate.endpoint.EndpointId; + /** * Strategy interface used to provide a mapping between an endpoint ID and the root path * where it will be exposed. @@ -31,15 +33,41 @@ public interface PathMapper { * Resolve the root path for the endpoint with the specified {@code endpointId}. * @param endpointId the id of an endpoint * @return the path of the endpoint + * @since 2.0.6 + */ + default String getRootPath(EndpointId endpointId) { + return getRootPath((endpointId != null) ? endpointId.toString() : null); + } + + /** + * Resolve the root path for the endpoint with the specified {@code endpointId}. + * @param endpointId the id of an endpoint + * @return the path of the endpoint + * @deprecated since 2.0.6 in favor of {@link #getRootPath(EndpointId)} */ + @Deprecated String getRootPath(String endpointId); /** * Returns an {@link PathMapper} that uses the endpoint ID as the path. - * @return an {@link PathMapper} that uses the endpoint ID as the path + * @return an {@link PathMapper} that uses the lowercase endpoint ID as the path */ static PathMapper useEndpointId() { - return (endpointId) -> endpointId; + return new PathMapper() { + + @Override + @Deprecated + public String getRootPath(String endpointId) { + return getRootPath(EndpointId.of(endpointId)); + } + + @Override + public String getRootPath(EndpointId endpointId) { + return endpointId.toLowerCaseString(); + } + + }; + } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrar.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrar.java index 3d4ba2aa45..dec24a8794 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrar.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrar.java @@ -67,7 +67,7 @@ public class ServletEndpointRegistrar implements ServletContextInitializer { private void register(ServletContext servletContext, ExposableServletEndpoint endpoint) { - String name = endpoint.getId() + "-actuator-endpoint"; + String name = endpoint.getEndpointId().toLowerCaseString() + "-actuator-endpoint"; String path = this.basePath + "/" + endpoint.getRootPath(); String urlMapping = path.endsWith("/") ? path + "*" : path + "/*"; EndpointServlet endpointServlet = endpoint.getEndpointServlet(); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java index 7df0d22e42..8842b20ce4 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; @@ -67,16 +68,31 @@ public class ControllerEndpointDiscoverer } @Override + @Deprecated protected ExposableControllerEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + return createEndpoint(endpointBean, (id != null) ? EndpointId.of(id) : null, + enabledByDefault, operations); + } + + @Override + protected ExposableControllerEndpoint createEndpoint(Object endpointBean, + EndpointId id, boolean enabledByDefault, Collection operations) { String rootPath = this.endpointPathMapper.getRootPath(id); return new DiscoveredControllerEndpoint(this, endpointBean, id, rootPath, enabledByDefault); } @Override + @Deprecated protected Operation createOperation(String endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { + return createOperation(EndpointId.of(endpointId), operationMethod, invoker); + } + + @Override + protected Operation createOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { throw new IllegalStateException( "ControllerEndpoints must not declare operations"); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredControllerEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredControllerEndpoint.java index 550386af4e..43a3376c29 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredControllerEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredControllerEndpoint.java @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.web.annotation; import java.util.Collections; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; @@ -33,7 +34,7 @@ class DiscoveredControllerEndpoint extends AbstractDiscoveredEndpoint private final String rootPath; DiscoveredControllerEndpoint(EndpointDiscoverer discoverer, Object endpointBean, - String id, String rootPath, boolean enabledByDefault) { + EndpointId id, String rootPath, boolean enabledByDefault) { super(discoverer, endpointBean, id, enabledByDefault, Collections.emptyList()); this.rootPath = rootPath; } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredServletEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredServletEndpoint.java index 94932f97fa..c857fc351b 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredServletEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredServletEndpoint.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.web.annotation; import java.util.Collections; import java.util.function.Supplier; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; @@ -39,7 +40,7 @@ class DiscoveredServletEndpoint extends AbstractDiscoveredEndpoint private final EndpointServlet endpointServlet; DiscoveredServletEndpoint(EndpointDiscoverer discoverer, Object endpointBean, - String id, String rootPath, boolean enabledByDefault) { + EndpointId id, String rootPath, boolean enabledByDefault) { super(discoverer, endpointBean, id, enabledByDefault, Collections.emptyList()); String beanType = endpointBean.getClass().getName(); Assert.state(endpointBean instanceof Supplier, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebEndpoint.java index 17acb60389..36d34883a0 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebEndpoint.java @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.web.annotation; import java.util.Collection; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; @@ -34,7 +35,7 @@ class DiscoveredWebEndpoint extends AbstractDiscoveredEndpoint private final String rootPath; DiscoveredWebEndpoint(EndpointDiscoverer discoverer, Object endpointBean, - String id, String rootPath, boolean enabledByDefault, + EndpointId id, String rootPath, boolean enabledByDefault, Collection operations) { super(discoverer, endpointBean, id, enabledByDefault, operations); this.rootPath = rootPath; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebOperation.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebOperation.java index a2bc7071c7..6502d62602 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebOperation.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebOperation.java @@ -23,6 +23,7 @@ import java.util.stream.Stream; import org.reactivestreams.Publisher; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.Selector; @@ -51,8 +52,9 @@ class DiscoveredWebOperation extends AbstractDiscoveredOperation implements WebO private final WebOperationRequestPredicate requestPredicate; - DiscoveredWebOperation(String endpointId, DiscoveredOperationMethod operationMethod, - OperationInvoker invoker, WebOperationRequestPredicate requestPredicate) { + DiscoveredWebOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker, + WebOperationRequestPredicate requestPredicate) { super(operationMethod, invoker); Method method = operationMethod.getMethod(); this.id = getId(endpointId, method); @@ -60,7 +62,7 @@ class DiscoveredWebOperation extends AbstractDiscoveredOperation implements WebO this.requestPredicate = requestPredicate; } - private String getId(String endpointId, Method method) { + private String getId(EndpointId endpointId, Method method) { return endpointId + Stream.of(method.getParameters()).filter(this::hasSelector) .map(this::dashName).collect(Collectors.joining()); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactory.java index 8ce5291b81..44c9476c92 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactory.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.Selector; @@ -50,7 +51,7 @@ class RequestPredicateFactory { this.endpointMediaTypes = endpointMediaTypes; } - public WebOperationRequestPredicate getRequestPredicate(String endpointId, + public WebOperationRequestPredicate getRequestPredicate(EndpointId endpointId, String rootPath, DiscoveredOperationMethod operationMethod) { Method method = operationMethod.getMethod(); String path = getPath(rootPath, method); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java index f00857c2db..fa127b40c0 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; @@ -66,16 +67,31 @@ public class ServletEndpointDiscoverer } @Override + @Deprecated protected ExposableServletEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + return createEndpoint(endpointBean, EndpointId.of(id), enabledByDefault, + operations); + } + + @Override + protected ExposableServletEndpoint createEndpoint(Object endpointBean, EndpointId id, + boolean enabledByDefault, Collection operations) { String rootPath = this.endpointPathMapper.getRootPath(id); return new DiscoveredServletEndpoint(this, endpointBean, id, rootPath, enabledByDefault); } @Override + @Deprecated protected Operation createOperation(String endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { + return createOperation(EndpointId.of(endpointId), operationMethod, invoker); + } + + @Override + protected Operation createOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { throw new IllegalStateException("ServletEndpoints must not declare operations"); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java index 05226a11ce..e6feb3f98a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.web.annotation; import java.util.Collection; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -68,16 +69,31 @@ public class WebEndpointDiscoverer } @Override + @Deprecated protected ExposableWebEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + return createEndpoint(endpointBean, EndpointId.of(id), enabledByDefault, + operations); + } + + @Override + protected ExposableWebEndpoint createEndpoint(Object endpointBean, EndpointId id, + boolean enabledByDefault, Collection operations) { String rootPath = this.endpointPathMapper.getRootPath(id); return new DiscoveredWebEndpoint(this, endpointBean, id, rootPath, enabledByDefault, operations); } @Override + @Deprecated protected WebOperation createOperation(String endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { + return createOperation(EndpointId.of(endpointId), operationMethod, invoker); + } + + @Override + protected WebOperation createOperation(EndpointId endpointId, + DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { String rootPath = this.endpointPathMapper.getRootPath(endpointId); WebOperationRequestPredicate requestPredicate = this.requestPredicateFactory .getRequestPredicate(endpointId, rootPath, operationMethod); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EndpointIdTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EndpointIdTests.java new file mode 100644 index 0000000000..9c11e8f2ef --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EndpointIdTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2018 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; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EndpointId}. + * + * @author Phillip Webb + */ +public class EndpointIdTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void ofWhenNullThorowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must not be empty"); + EndpointId.of(null); + } + + @Test + public void ofWhenEmptyThrowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must not be empty"); + EndpointId.of(""); + } + + @Test + public void ofWhenContainsDashThrowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must be alpha-numeric"); + EndpointId.of("foo-bar"); + } + + @Test + public void ofWhenHasBadCharThrowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must be alpha-numeric"); + EndpointId.of("foo!bar"); + } + + @Test + public void ofWhenStartsWithNumberThrowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must not start with a number"); + EndpointId.of("1foo"); + } + + @Test + public void ofWhenStartsWithUppercaseLetterThrowsException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Value must not start with an uppercase letter"); + EndpointId.of("Foo"); + } + + @Test + public void equalsAndHashCode() { + EndpointId one = EndpointId.of("foobar"); + EndpointId two = EndpointId.of("fooBar"); + EndpointId three = EndpointId.of("barfoo"); + assertThat(one.hashCode()).isEqualTo(two.hashCode()); + assertThat(one).isEqualTo(one).isEqualTo(two).isNotEqualTo(three); + } + + @Test + public void toLowerCaseStringReturnsLowercase() { + assertThat(EndpointId.of("fooBar").toLowerCaseString()).isEqualTo("foobar"); + } + + @Test + public void toStringReturnsString() { + assertThat(EndpointId.of("fooBar").toString()).isEqualTo("fooBar"); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java index 34e546dd67..f8fc5d3e3e 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java @@ -25,6 +25,7 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.InvocationContext; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.SecurityContext; @@ -60,8 +61,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsWhenHasReadMethodShouldCreateOperation() { - Collection operations = this.factory.createOperations("test", - new ExampleRead()); + Collection operations = this.factory + .createOperations(EndpointId.of("test"), new ExampleRead()); assertThat(operations).hasSize(1); TestOperation operation = getFirst(operations); assertThat(operation.getType()).isEqualTo(OperationType.READ); @@ -69,8 +70,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsWhenHasWriteMethodShouldCreateOperation() { - Collection operations = this.factory.createOperations("test", - new ExampleWrite()); + Collection operations = this.factory + .createOperations(EndpointId.of("test"), new ExampleWrite()); assertThat(operations).hasSize(1); TestOperation operation = getFirst(operations); assertThat(operation.getType()).isEqualTo(OperationType.WRITE); @@ -78,8 +79,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsWhenHasDeleteMethodShouldCreateOperation() { - Collection operations = this.factory.createOperations("test", - new ExampleDelete()); + Collection operations = this.factory + .createOperations(EndpointId.of("test"), new ExampleDelete()); assertThat(operations).hasSize(1); TestOperation operation = getFirst(operations); assertThat(operation.getType()).isEqualTo(OperationType.DELETE); @@ -87,8 +88,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsWhenMultipleShouldReturnMultiple() { - Collection operations = this.factory.createOperations("test", - new ExampleMultiple()); + Collection operations = this.factory + .createOperations(EndpointId.of("test"), new ExampleMultiple()); assertThat(operations).hasSize(2); assertThat(operations.stream().map(TestOperation::getType)) .containsOnly(OperationType.READ, OperationType.WRITE); @@ -96,8 +97,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsShouldProvideOperationMethod() { - TestOperation operation = getFirst( - this.factory.createOperations("test", new ExampleWithParams())); + TestOperation operation = getFirst(this.factory + .createOperations(EndpointId.of("test"), new ExampleWithParams())); OperationMethod operationMethod = operation.getOperationMethod(); assertThat(operationMethod.getMethod().getName()).isEqualTo("read"); assertThat(operationMethod.getParameters().hasParameters()).isTrue(); @@ -105,8 +106,8 @@ public class DiscoveredOperationsFactoryTests { @Test public void createOperationsShouldProviderInvoker() { - TestOperation operation = getFirst( - this.factory.createOperations("test", new ExampleWithParams())); + TestOperation operation = getFirst(this.factory + .createOperations(EndpointId.of("test"), new ExampleWithParams())); Map params = Collections.singletonMap("name", 123); Object result = operation .invoke(new InvocationContext(mock(SecurityContext.class), params)); @@ -118,10 +119,10 @@ public class DiscoveredOperationsFactoryTests { TestOperationInvokerAdvisor advisor = new TestOperationInvokerAdvisor(); this.invokerAdvisors.add(advisor); TestOperation operation = getFirst( - this.factory.createOperations("test", new ExampleRead())); + this.factory.createOperations(EndpointId.of("test"), new ExampleRead())); operation.invoke(new InvocationContext(mock(SecurityContext.class), Collections.emptyMap())); - assertThat(advisor.getEndpointId()).isEqualTo("test"); + assertThat(advisor.getEndpointId()).isEqualTo(EndpointId.of("test")); assertThat(advisor.getOperationType()).isEqualTo(OperationType.READ); assertThat(advisor.getParameters()).isEmpty(); } @@ -189,7 +190,7 @@ public class DiscoveredOperationsFactoryTests { } @Override - protected TestOperation createOperation(String endpointId, + protected TestOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { return new TestOperation(endpointId, operationMethod, invoker); } @@ -198,7 +199,7 @@ public class DiscoveredOperationsFactoryTests { static class TestOperation extends AbstractDiscoveredOperation { - TestOperation(String endpointId, DiscoveredOperationMethod operationMethod, + TestOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) { super(operationMethod, invoker); } @@ -207,14 +208,14 @@ public class DiscoveredOperationsFactoryTests { static class TestOperationInvokerAdvisor implements OperationInvokerAdvisor { - private String endpointId; + private EndpointId endpointId; private OperationType operationType; private OperationParameters parameters; @Override - public OperationInvoker apply(String endpointId, OperationType operationType, + public OperationInvoker apply(EndpointId endpointId, OperationType operationType, OperationParameters parameters, OperationInvoker invoker) { this.endpointId = endpointId; this.operationType = operationType; @@ -222,7 +223,14 @@ public class DiscoveredOperationsFactoryTests { return invoker; } - public String getEndpointId() { + @Override + @Deprecated + public OperationInvoker apply(String endpointId, OperationType operationType, + OperationParameters parameters, OperationInvoker invoker) { + throw new IllegalStateException(); + } + + public EndpointId getEndpointId() { return this.endpointId; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java index b38c076ef6..23dda7dabc 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java @@ -37,6 +37,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.boot.actuate.endpoint.EndpointFilter; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -125,10 +126,11 @@ public class EndpointDiscovererTests { public void getEndpointsWhenHasSubclassedEndpointShouldReturnEndpoint() { load(TestEndpointSubclassConfiguration.class, (context) -> { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - Map operations = mapOperations(endpoints.get("test")); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + Map operations = mapOperations( + endpoints.get(EndpointId.of("test"))); assertThat(operations).hasSize(5); assertThat(operations).containsKeys(testEndpointMethods()); assertThat(operations).containsKeys(ReflectionUtils.findMethod( @@ -151,10 +153,11 @@ public class EndpointDiscovererTests { load(TestEndpointConfiguration.class, (context) -> { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context, (endpointId) -> 0L); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - Map operations = mapOperations(endpoints.get("test")); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + Map operations = mapOperations( + endpoints.get(EndpointId.of("test"))); operations.values().forEach((operation) -> assertThat(operation.getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class)); }); @@ -165,10 +168,11 @@ public class EndpointDiscovererTests { load(TestEndpointConfiguration.class, (context) -> { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context, (endpointId) -> (endpointId.equals("foo") ? 500L : 0L)); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - Map operations = mapOperations(endpoints.get("test")); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + Map operations = mapOperations( + endpoints.get(EndpointId.of("test"))); operations.values().forEach((operation) -> assertThat(operation.getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class)); }); @@ -178,11 +182,13 @@ public class EndpointDiscovererTests { public void getEndpointsWhenTtlSetByIdAndIdMatchesShouldCacheInvokeCalls() { load(TestEndpointConfiguration.class, (context) -> { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context, - (endpointId) -> (endpointId.equals("test") ? 500L : 0L)); - Map endpoints = mapEndpoints( + (endpointId) -> (endpointId.equals(EndpointId.of("test")) ? 500L + : 0L)); + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - Map operations = mapOperations(endpoints.get("test")); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + Map operations = mapOperations( + endpoints.get(EndpointId.of("test"))); TestOperation getAll = operations.get(findTestEndpointMethod("getAll")); TestOperation getOne = operations .get(findTestEndpointMethod("getOne", String.class)); @@ -201,9 +207,9 @@ public class EndpointDiscovererTests { public void getEndpointsWhenHasSpecializedFiltersInNonSpecializedDiscovererShouldFilterEndpoints() { load(SpecializedEndpointsConfiguration.class, (context) -> { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); }); } @@ -212,9 +218,10 @@ public class EndpointDiscovererTests { load(SpecializedEndpointsConfiguration.class, (context) -> { SpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer( context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test", "specialized"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test"), + EndpointId.of("specialized")); }); } @@ -223,10 +230,10 @@ public class EndpointDiscovererTests { load(SpecializedEndpointsConfiguration.class, (context) -> { SpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer( context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); Map operations = mapOperations( - endpoints.get("specialized")); + endpoints.get(EndpointId.of("specialized"))); assertThat(operations).containsKeys( ReflectionUtils.findMethod(SpecializedExtension.class, "getSpecial")); @@ -238,10 +245,10 @@ public class EndpointDiscovererTests { load(SubSpecializedEndpointsConfiguration.class, (context) -> { SpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer( context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); Map operations = mapOperations( - endpoints.get("specialized")); + endpoints.get(EndpointId.of("specialized"))); assertThat(operations).containsKeys( ReflectionUtils.findMethod(SpecializedTestEndpoint.class, "getAll")); assertThat(operations).containsKeys(ReflectionUtils.findMethod( @@ -261,18 +268,19 @@ public class EndpointDiscovererTests { }; SpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer( context, Collections.singleton(filter)); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); }); } private void hasTestEndpoint(AnnotationConfigApplicationContext context) { TestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context); - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - Map operations = mapOperations(endpoints.get("test")); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + Map operations = mapOperations( + endpoints.get(EndpointId.of("test"))); assertThat(operations).hasSize(4); assertThat(operations).containsKeys(); } @@ -290,14 +298,15 @@ public class EndpointDiscovererTests { return ReflectionUtils.findMethod(TestEndpoint.class, name, paramTypes); } - private > Map mapEndpoints( + private > Map mapEndpoints( Collection endpoints) { - Map byId = new LinkedHashMap<>(); + Map byId = new LinkedHashMap<>(); endpoints.forEach((endpoint) -> { - E existing = byId.put(endpoint.getId(), endpoint); + E existing = byId.put(endpoint.getEndpointId(), endpoint); if (existing != null) { - throw new AssertionError(String.format( - "Found endpoints with duplicate id '%s'", endpoint.getId())); + throw new AssertionError( + String.format("Found endpoints with duplicate id '%s'", + endpoint.getEndpointId())); } }); return byId; @@ -513,6 +522,12 @@ public class EndpointDiscovererTests { @Override protected TestExposableEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + throw new IllegalStateException(); + } + + @Override + protected TestExposableEndpoint createEndpoint(Object endpointBean, EndpointId id, + boolean enabledByDefault, Collection operations) { return new TestExposableEndpoint(this, endpointBean, id, enabledByDefault, operations); } @@ -548,6 +563,13 @@ public class EndpointDiscovererTests { protected SpecializedExposableEndpoint createEndpoint(Object endpointBean, String id, boolean enabledByDefault, Collection operations) { + throw new IllegalStateException(); + } + + @Override + protected SpecializedExposableEndpoint createEndpoint(Object endpointBean, + EndpointId id, boolean enabledByDefault, + Collection operations) { return new SpecializedExposableEndpoint(this, endpointBean, id, enabledByDefault, operations); } @@ -569,7 +591,7 @@ public class EndpointDiscovererTests { static class TestExposableEndpoint extends AbstractDiscoveredEndpoint { TestExposableEndpoint(EndpointDiscoverer discoverer, Object endpointBean, - String id, boolean enabledByDefault, + EndpointId id, boolean enabledByDefault, Collection operations) { super(discoverer, endpointBean, id, enabledByDefault, operations); } @@ -580,7 +602,7 @@ public class EndpointDiscovererTests { extends AbstractDiscoveredEndpoint { SpecializedExposableEndpoint(EndpointDiscoverer discoverer, - Object endpointBean, String id, boolean enabledByDefault, + Object endpointBean, EndpointId id, boolean enabledByDefault, Collection operations) { super(discoverer, endpointBean, id, enabledByDefault, operations); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java index 921de6b724..95b3311640 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -63,8 +64,8 @@ public class CachingOperationInvokerAdvisorTests { @Test public void applyWhenOperationIsNotReadShouldNotAddAdvise() { OperationParameters parameters = getParameters("get"); - OperationInvoker advised = this.advisor.apply("foo", OperationType.WRITE, - parameters, this.invoker); + OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), + OperationType.WRITE, parameters, this.invoker); assertThat(advised).isSameAs(this.invoker); } @@ -72,8 +73,8 @@ public class CachingOperationInvokerAdvisorTests { public void applyWhenHasAtLeaseOneMandatoryParameterShouldNotAddAdvise() { OperationParameters parameters = getParameters("getWithParameters", String.class, String.class); - OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, - parameters, this.invoker); + OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), + OperationType.READ, parameters, this.invoker); assertThat(advised).isSameAs(this.invoker); } @@ -81,8 +82,8 @@ public class CachingOperationInvokerAdvisorTests { public void applyWhenTimeToLiveReturnsNullShouldNotAddAdvise() { OperationParameters parameters = getParameters("get"); given(this.timeToLive.apply(any())).willReturn(null); - OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, - parameters, this.invoker); + OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), + OperationType.READ, parameters, this.invoker); assertThat(advised).isSameAs(this.invoker); verify(this.timeToLive).apply("foo"); } @@ -91,8 +92,8 @@ public class CachingOperationInvokerAdvisorTests { public void applyWhenTimeToLiveIsZeroShouldNotAddAdvise() { OperationParameters parameters = getParameters("get"); given(this.timeToLive.apply(any())).willReturn(0L); - OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, - parameters, this.invoker); + OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), + OperationType.READ, parameters, this.invoker); assertThat(advised).isSameAs(this.invoker); verify(this.timeToLive).apply("foo"); } @@ -121,8 +122,8 @@ public class CachingOperationInvokerAdvisorTests { } private void assertAdviseIsApplied(OperationParameters parameters) { - OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, - parameters, this.invoker); + OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), + OperationType.READ, parameters, this.invoker); assertThat(advised).isInstanceOf(CachingOperationInvoker.class); assertThat(ReflectionTestUtils.getField(advised, "invoker")) .isEqualTo(this.invoker); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporterTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporterTests.java index b196e96363..de5fd1b1ca 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporterTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporterTests.java @@ -190,9 +190,8 @@ public class JmxEndpointExporterTests { @Override public ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException { - return (endpoint != null) - ? new ObjectName("boot:type=Endpoint,name=" + endpoint.getId()) - : null; + return (endpoint != null) ? new ObjectName( + "boot:type=Endpoint,name=" + endpoint.getEndpointId()) : null; } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperationTests.java index 107432b399..9a1e50af7a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperationTests.java @@ -25,6 +25,7 @@ import java.util.Map; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; @@ -126,8 +127,8 @@ public class DiscoveredJmxOperationTests { annotationAttributes.put("produces", "application/xml"); DiscoveredOperationMethod operationMethod = new DiscoveredOperationMethod(method, OperationType.READ, annotationAttributes); - DiscoveredJmxOperation operation = new DiscoveredJmxOperation("test", - operationMethod, mock(OperationInvoker.class)); + DiscoveredJmxOperation operation = new DiscoveredJmxOperation( + EndpointId.of("test"), operationMethod, mock(OperationInvoker.class)); return operation; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererTests.java index 2dec175552..f4085b7fbc 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererTests.java @@ -28,6 +28,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @@ -70,10 +71,10 @@ public class JmxEndpointDiscovererTests { @Test public void getEndpointsShouldDiscoverStandardEndpoints() { load(TestEndpoint.class, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test"); + Map endpoints = discover(discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); Map operationByName = mapOperations( - endpoints.get("test").getOperations()); + endpoints.get(EndpointId.of("test")).getOperations()); assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update", "deleteSomething"); JmxOperation getAll = operationByName.get("getAll"); @@ -106,8 +107,9 @@ public class JmxEndpointDiscovererTests { @Test public void getEndpointsWhenHasFilteredEndpointShouldOnlyDiscoverJmxEndpoints() { load(MultipleEndpointsConfiguration.class, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test", "jmx"); + Map endpoints = discover(discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test"), + EndpointId.of("jmx")); }); } @@ -125,19 +127,19 @@ public class JmxEndpointDiscovererTests { @Test public void getEndpointsWhenHasJmxExtensionShouldOverrideStandardEndpoint() { load(OverriddenOperationJmxEndpointConfiguration.class, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test"); - assertJmxTestEndpoint(endpoints.get("test")); + Map endpoints = discover(discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + assertJmxTestEndpoint(endpoints.get(EndpointId.of("test"))); }); } @Test public void getEndpointsWhenHasJmxExtensionWithNewOperationAddsExtraOperation() { load(AdditionalOperationJmxEndpointConfiguration.class, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test"); + Map endpoints = discover(discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); Map operationByName = mapOperations( - endpoints.get("test").getOperations()); + endpoints.get(EndpointId.of("test")).getOperations()); assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update", "deleteSomething", "getAnother"); JmxOperation getAnother = operationByName.get("getAnother"); @@ -150,10 +152,10 @@ public class JmxEndpointDiscovererTests { @Test public void getEndpointsWhenHasCacheWithTtlShouldCacheReadOperationWithTtlValue() { load(TestEndpoint.class, (id) -> 500L, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test"); + Map endpoints = discover(discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); Map operationByName = mapOperations( - endpoints.get("test").getOperations()); + endpoints.get(EndpointId.of("test")).getOperations()); assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update", "deleteSomething"); JmxOperation getAll = operationByName.get("getAll"); @@ -167,10 +169,11 @@ public class JmxEndpointDiscovererTests { public void getEndpointsShouldCacheReadOperations() { load(AdditionalOperationJmxEndpointConfiguration.class, (id) -> 500L, (discoverer) -> { - Map endpoints = discover(discoverer); - assertThat(endpoints).containsOnlyKeys("test"); + Map endpoints = discover( + discoverer); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); Map operationByName = mapOperations( - endpoints.get("test").getOperations()); + endpoints.get(EndpointId.of("test")).getOperations()); assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update", "deleteSomething", "getAnother"); JmxOperation getAll = operationByName.get("getAll"); @@ -285,10 +288,11 @@ public class JmxEndpointDiscovererTests { assertThat(parameter.getType()).isEqualTo(type); } - private Map discover(JmxEndpointDiscoverer discoverer) { - Map byId = new HashMap<>(); + private Map discover( + JmxEndpointDiscoverer discoverer) { + Map byId = new HashMap<>(); discoverer.getEndpoints() - .forEach((endpoint) -> byId.put(endpoint.getId(), endpoint)); + .forEach((endpoint) -> byId.put(endpoint.getEndpointId(), endpoint)); return byId; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolverTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolverTests.java index 32ae0fe60e..b97e33550f 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolverTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolverTests.java @@ -24,6 +24,7 @@ import java.util.Map; import org.assertj.core.api.Condition; import org.junit.Test; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint; @@ -62,7 +63,7 @@ public class EndpointLinksResolverTests { operations.add(operationWithPath("/alpha", "alpha")); operations.add(operationWithPath("/alpha/{name}", "alpha-name")); ExposableWebEndpoint endpoint = mock(ExposableWebEndpoint.class); - given(endpoint.getId()).willReturn("alpha"); + given(endpoint.getEndpointId()).willReturn(EndpointId.of("alpha")); given(endpoint.isEnableByDefault()).willReturn(true); given(endpoint.getOperations()).willReturn(operations); String requestUrl = "https://api.example.com/actuator"; @@ -80,7 +81,7 @@ public class EndpointLinksResolverTests { @Test public void resolvedLinksContainsALinkForServletEndpoint() { ExposableServletEndpoint servletEndpoint = mock(ExposableServletEndpoint.class); - given(servletEndpoint.getId()).willReturn("alpha"); + given(servletEndpoint.getEndpointId()).willReturn(EndpointId.of("alpha")); given(servletEndpoint.isEnableByDefault()).willReturn(true); given(servletEndpoint.getRootPath()).willReturn("alpha"); String requestUrl = "https://api.example.com/actuator"; @@ -97,7 +98,7 @@ public class EndpointLinksResolverTests { public void resolvedLinksContainsALinkForControllerEndpoint() { ExposableControllerEndpoint controllerEndpoint = mock( ExposableControllerEndpoint.class); - given(controllerEndpoint.getId()).willReturn("alpha"); + given(controllerEndpoint.getEndpointId()).willReturn(EndpointId.of("alpha")); given(controllerEndpoint.isEnableByDefault()).willReturn(true); given(controllerEndpoint.getRootPath()).willReturn("alpha"); String requestUrl = "https://api.example.com/actuator"; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpointsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpointsTests.java index 1a7f0c2f85..6674efc808 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpointsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpointsTests.java @@ -24,6 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.EndpointsSupplier; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.Operation; @@ -60,38 +61,41 @@ public class PathMappedEndpointsTests { public void iteratorShouldReturnPathMappedEndpoints() { PathMappedEndpoints mapped = createTestMapped(null); assertThat(mapped).hasSize(2); - assertThat(mapped).extracting("id").containsExactly("e2", "e3"); + assertThat(mapped).extracting("endpointId").containsExactly(EndpointId.of("e2"), + EndpointId.of("e3")); } @Test public void streamShouldReturnPathMappedEndpoints() { PathMappedEndpoints mapped = createTestMapped(null); assertThat(mapped.stream()).hasSize(2); - assertThat(mapped.stream()).extracting("id").containsExactly("e2", "e3"); + assertThat(mapped.stream()).extracting("endpointId") + .containsExactly(EndpointId.of("e2"), EndpointId.of("e3")); } @Test public void getRootPathWhenContainsIdShouldReturnRootPath() { PathMappedEndpoints mapped = createTestMapped(null); - assertThat(mapped.getRootPath("e2")).isEqualTo("p2"); + assertThat(mapped.getRootPath(EndpointId.of("e2"))).isEqualTo("p2"); } @Test public void getRootPathWhenMissingIdShouldReturnNull() { PathMappedEndpoints mapped = createTestMapped(null); - assertThat(mapped.getRootPath("xx")).isNull(); + assertThat(mapped.getRootPath(EndpointId.of("xx"))).isNull(); } @Test public void getPathWhenContainsIdShouldReturnRootPath() { - assertThat(createTestMapped(null).getPath("e2")).isEqualTo("/p2"); - assertThat(createTestMapped("/x").getPath("e2")).isEqualTo("/x/p2"); + assertThat(createTestMapped(null).getPath(EndpointId.of("e2"))).isEqualTo("/p2"); + assertThat(createTestMapped("/x").getPath(EndpointId.of("e2"))) + .isEqualTo("/x/p2"); } @Test public void getPathWhenMissingIdShouldReturnNull() { PathMappedEndpoints mapped = createTestMapped(null); - assertThat(mapped.getPath("xx")).isNull(); + assertThat(mapped.getPath(EndpointId.of("xx"))).isNull(); } @Test @@ -110,34 +114,34 @@ public class PathMappedEndpointsTests { @Test public void getEndpointWhenContainsIdShouldReturnPathMappedEndpoint() { PathMappedEndpoints mapped = createTestMapped(null); - assertThat(mapped.getEndpoint("e2").getRootPath()).isEqualTo("p2"); + assertThat(mapped.getEndpoint(EndpointId.of("e2")).getRootPath()).isEqualTo("p2"); } @Test public void getEndpointWhenMissingIdShouldReturnNull() { PathMappedEndpoints mapped = createTestMapped(null); - assertThat(mapped.getEndpoint("xx")).isNull(); + assertThat(mapped.getEndpoint(EndpointId.of("xx"))).isNull(); } private PathMappedEndpoints createTestMapped(String basePath) { List> endpoints = new ArrayList<>(); - endpoints.add(mockEndpoint("e1")); - endpoints.add(mockEndpoint("e2", "p2")); - endpoints.add(mockEndpoint("e3", "p3")); - endpoints.add(mockEndpoint("e4")); + endpoints.add(mockEndpoint(EndpointId.of("e1"))); + endpoints.add(mockEndpoint(EndpointId.of("e2"), "p2")); + endpoints.add(mockEndpoint(EndpointId.of("e3"), "p3")); + endpoints.add(mockEndpoint(EndpointId.of("e4"))); return new PathMappedEndpoints(basePath, () -> endpoints); } - private TestPathMappedEndpoint mockEndpoint(String id, String rootPath) { + private TestPathMappedEndpoint mockEndpoint(EndpointId id, String rootPath) { TestPathMappedEndpoint endpoint = mock(TestPathMappedEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); given(endpoint.getRootPath()).willReturn(rootPath); return endpoint; } - private TestEndpoint mockEndpoint(String id) { + private TestEndpoint mockEndpoint(EndpointId id) { TestEndpoint endpoint = mock(TestEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); return endpoint; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrarTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrarTests.java index 96cfc705ab..51b3d4f220 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrarTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrarTests.java @@ -35,6 +35,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.boot.actuate.endpoint.EndpointId; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -124,7 +126,7 @@ public class ServletEndpointRegistrarTests { private ExposableServletEndpoint mockEndpoint(EndpointServlet endpointServlet) { ExposableServletEndpoint endpoint = mock(ExposableServletEndpoint.class); - given(endpoint.getId()).willReturn("test"); + given(endpoint.getEndpointId()).willReturn(EndpointId.of("test")); given(endpoint.getEndpointServlet()).willReturn(endpointServlet); given(endpoint.getRootPath()).willReturn("test"); return endpoint; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java index e3cd4c7562..0a4d42b6f2 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java @@ -26,6 +26,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -70,7 +71,8 @@ public class ControllerEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableControllerEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testcontroller"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testcontroller")); assertThat(endpoint.getController()) .isInstanceOf(TestControllerEndpoint.class); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); @@ -87,7 +89,8 @@ public class ControllerEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableControllerEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testcontroller"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testcontroller")); assertThat(endpoint.getController()) .isInstanceOf(TestProxyControllerEndpoint.class); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); @@ -102,7 +105,8 @@ public class ControllerEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableControllerEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testrestcontroller"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testrestcontroller")); assertThat(endpoint.getController()) .isInstanceOf(TestRestControllerEndpoint.class); })); @@ -118,7 +122,8 @@ public class ControllerEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableControllerEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testrestcontroller"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testrestcontroller")); assertThat(endpoint.getController()) .isInstanceOf(TestProxyRestControllerEndpoint.class); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); @@ -131,9 +136,11 @@ public class ControllerEndpointDiscovererTests { .run(assertDiscoverer((discoverer) -> { Collection endpoints = discoverer .getEndpoints(); - List ids = endpoints.stream().map(ExposableEndpoint::getId) + List ids = endpoints.stream() + .map(ExposableEndpoint::getEndpointId) .collect(Collectors.toList()); - assertThat(ids).containsOnly("testcontroller", "testrestcontroller"); + assertThat(ids).containsOnly(EndpointId.of("testcontroller"), + EndpointId.of("testrestcontroller")); })); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java index 7ae9093cb2..3f9a2868ba 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java @@ -33,6 +33,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -79,7 +80,8 @@ public class ServletEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableServletEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testservlet"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testservlet")); assertThat(endpoint.getEndpointServlet()).isNotNull(); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); })); @@ -95,7 +97,8 @@ public class ServletEndpointDiscovererTests { .getEndpoints(); assertThat(endpoints).hasSize(1); ExposableServletEndpoint endpoint = endpoints.iterator().next(); - assertThat(endpoint.getId()).isEqualTo("testservlet"); + assertThat(endpoint.getEndpointId()) + .isEqualTo(EndpointId.of("testservlet")); assertThat(endpoint.getEndpointServlet()).isNotNull(); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); })); @@ -107,9 +110,10 @@ public class ServletEndpointDiscovererTests { .run(assertDiscoverer((discoverer) -> { Collection endpoints = discoverer .getEndpoints(); - List ids = endpoints.stream().map(ExposableEndpoint::getId) + List ids = endpoints.stream() + .map(ExposableEndpoint::getEndpointId) .collect(Collectors.toList()); - assertThat(ids).containsOnly("testservlet"); + assertThat(ids).containsOnly(EndpointId.of("testservlet")); })); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererTests.java index cf31c236d8..2eb59000f7 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererTests.java @@ -33,6 +33,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @@ -91,19 +92,19 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenHasFilteredEndpointShouldOnlyDiscoverWebEndpoints() { load(MultipleEndpointsConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); }); } @Test public void getEndpointsWhenHasWebExtensionShouldOverrideStandardEndpoint() { load(OverriddenOperationWebEndpointExtensionConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - ExposableWebEndpoint endpoint = endpoints.get("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("test")); assertThat(requestPredicates(endpoint)).has( requestPredicates(path("test").httpMethod(WebEndpointHttpMethod.GET) .consumes().produces("application/json"))); @@ -113,10 +114,10 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenExtensionAddsOperationShouldHaveBothOperations() { load(AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - ExposableWebEndpoint endpoint = endpoints.get("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("test")); assertThat(requestPredicates(endpoint)).has(requestPredicates( path("test").httpMethod(WebEndpointHttpMethod.GET).consumes() .produces("application/json"), @@ -128,10 +129,10 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenPredicateForWriteOperationThatReturnsVoidShouldHaveNoProducedMediaTypes() { load(VoidWriteOperationEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("voidwrite"); - ExposableWebEndpoint endpoint = endpoints.get("voidwrite"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("voidwrite")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("voidwrite")); assertThat(requestPredicates(endpoint)).has(requestPredicates( path("voidwrite").httpMethod(WebEndpointHttpMethod.POST).produces() .consumes("application/json"))); @@ -191,10 +192,10 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenHasCacheWithTtlShouldCacheReadOperationWithTtlValue() { load((id) -> 500L, (id) -> id, TestEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - ExposableWebEndpoint endpoint = endpoints.get("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("test")); assertThat(endpoint.getOperations()).hasSize(1); WebOperation operation = endpoint.getOperations().iterator().next(); Object invoker = ReflectionTestUtils.getField(operation, "invoker"); @@ -207,10 +208,10 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenOperationReturnsResourceShouldProduceApplicationOctetStream() { load(ResourceEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("resource"); - ExposableWebEndpoint endpoint = endpoints.get("resource"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("resource")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("resource")); assertThat(requestPredicates(endpoint)).has(requestPredicates( path("resource").httpMethod(WebEndpointHttpMethod.GET).consumes() .produces("application/octet-stream"))); @@ -220,10 +221,11 @@ public class WebEndpointDiscovererTests { @Test public void getEndpointsWhenHasCustomMediaTypeShouldProduceCustomMediaType() { load(CustomMediaTypesEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("custommediatypes"); - ExposableWebEndpoint endpoint = endpoints.get("custommediatypes"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("custommediatypes")); + ExposableWebEndpoint endpoint = endpoints + .get(EndpointId.of("custommediatypes")); assertThat(requestPredicates(endpoint)).has(requestPredicates( path("custommediatypes").httpMethod(WebEndpointHttpMethod.GET) .consumes().produces("text/plain"), @@ -238,10 +240,10 @@ public class WebEndpointDiscovererTests { public void getEndpointsWhenHasCustomPathShouldReturnCustomPath() { load((id) -> null, (id) -> "custom/" + id, AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> { - Map endpoints = mapEndpoints( + Map endpoints = mapEndpoints( discoverer.getEndpoints()); - assertThat(endpoints).containsOnlyKeys("test"); - ExposableWebEndpoint endpoint = endpoints.get("test"); + assertThat(endpoints).containsOnlyKeys(EndpointId.of("test")); + ExposableWebEndpoint endpoint = endpoints.get(EndpointId.of("test")); Condition> expected = requestPredicates( path("custom/test").httpMethod(WebEndpointHttpMethod.GET) .consumes().produces("application/json"), @@ -276,10 +278,11 @@ public class WebEndpointDiscovererTests { } } - private Map mapEndpoints( + private Map mapEndpoints( Collection endpoints) { - Map endpointById = new HashMap<>(); - endpoints.forEach((endpoint) -> endpointById.put(endpoint.getId(), endpoint)); + Map endpointById = new HashMap<>(); + endpoints.forEach( + (endpoint) -> endpointById.put(endpoint.getEndpointId(), endpoint)); return endpointById; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/ControllerEndpointHandlerMappingTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/ControllerEndpointHandlerMappingTests.java index c789cb0b63..daf13f0681 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/ControllerEndpointHandlerMappingTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/ControllerEndpointHandlerMappingTests.java @@ -22,6 +22,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint; import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint; @@ -121,22 +122,22 @@ public class ControllerEndpointHandlerMappingTests { } private ExposableControllerEndpoint firstEndpoint() { - return mockEndpoint("first", new FirstTestMvcEndpoint()); + return mockEndpoint(EndpointId.of("first"), new FirstTestMvcEndpoint()); } private ExposableControllerEndpoint secondEndpoint() { - return mockEndpoint("second", new SecondTestMvcEndpoint()); + return mockEndpoint(EndpointId.of("second"), new SecondTestMvcEndpoint()); } private ExposableControllerEndpoint pathlessEndpoint() { - return mockEndpoint("pathless", new PathlessControllerEndpoint()); + return mockEndpoint(EndpointId.of("pathless"), new PathlessControllerEndpoint()); } - private ExposableControllerEndpoint mockEndpoint(String id, Object controller) { + private ExposableControllerEndpoint mockEndpoint(EndpointId id, Object controller) { ExposableControllerEndpoint endpoint = mock(ExposableControllerEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); given(endpoint.getController()).willReturn(controller); - given(endpoint.getRootPath()).willReturn(id); + given(endpoint.getRootPath()).willReturn(id.toString()); return endpoint; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMappingTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMappingTests.java index acdc57b70b..d159bacce3 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMappingTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMappingTests.java @@ -22,6 +22,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.web.EndpointMapping; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint; import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint; @@ -113,22 +114,22 @@ public class ControllerEndpointHandlerMappingTests { } private ExposableControllerEndpoint firstEndpoint() { - return mockEndpoint("first", new FirstTestMvcEndpoint()); + return mockEndpoint(EndpointId.of("first"), new FirstTestMvcEndpoint()); } private ExposableControllerEndpoint secondEndpoint() { - return mockEndpoint("second", new SecondTestMvcEndpoint()); + return mockEndpoint(EndpointId.of("second"), new SecondTestMvcEndpoint()); } private ExposableControllerEndpoint pathlessEndpoint() { - return mockEndpoint("pathless", new PathlessControllerEndpoint()); + return mockEndpoint(EndpointId.of("pathless"), new PathlessControllerEndpoint()); } - private ExposableControllerEndpoint mockEndpoint(String id, Object controller) { + private ExposableControllerEndpoint mockEndpoint(EndpointId id, Object controller) { ExposableControllerEndpoint endpoint = mock(ExposableControllerEndpoint.class); - given(endpoint.getId()).willReturn(id); + given(endpoint.getEndpointId()).willReturn(id); given(endpoint.getController()).willReturn(controller); - given(endpoint.getRootPath()).willReturn(id); + given(endpoint.getRootPath()).willReturn(id.toString()); return endpoint; }