Commit 55ea9f79 authored by Stephane Nicoll's avatar Stephane Nicoll

Merge branch '2.0.x'

parents 02c0425a e8fac7d9
...@@ -29,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper; ...@@ -29,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/** /**
* {@link EndpointDiscoverer} for {@link ExposableControllerEndpoint controller * {@link EndpointDiscoverer} for {@link ExposableControllerEndpoint controller
...@@ -60,7 +61,7 @@ public class ControllerEndpointDiscoverer ...@@ -60,7 +61,7 @@ public class ControllerEndpointDiscoverer
@Override @Override
protected boolean isEndpointExposed(Object endpointBean) { protected boolean isEndpointExposed(Object endpointBean) {
Class<?> type = endpointBean.getClass(); Class<?> type = ClassUtils.getUserClass(endpointBean.getClass());
return AnnotatedElementUtils.isAnnotated(type, ControllerEndpoint.class) return AnnotatedElementUtils.isAnnotated(type, ControllerEndpoint.class)
|| AnnotatedElementUtils.isAnnotated(type, RestControllerEndpoint.class); || AnnotatedElementUtils.isAnnotated(type, RestControllerEndpoint.class);
} }
......
...@@ -30,6 +30,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper; ...@@ -30,6 +30,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/** /**
* {@link EndpointDiscoverer} for {@link ExposableServletEndpoint servlet endpoints}. * {@link EndpointDiscoverer} for {@link ExposableServletEndpoint servlet endpoints}.
...@@ -60,7 +61,7 @@ public class ServletEndpointDiscoverer ...@@ -60,7 +61,7 @@ public class ServletEndpointDiscoverer
@Override @Override
protected boolean isEndpointExposed(Object endpointBean) { protected boolean isEndpointExposed(Object endpointBean) {
Class<?> type = endpointBean.getClass(); Class<?> type = ClassUtils.getUserClass(endpointBean.getClass());
return AnnotatedElementUtils.isAnnotated(type, ServletEndpoint.class); return AnnotatedElementUtils.isAnnotated(type, ServletEndpoint.class);
} }
......
...@@ -31,9 +31,14 @@ import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint; ...@@ -31,9 +31,14 @@ import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.validation.annotation.Validated;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -41,74 +46,109 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -41,74 +46,109 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link ControllerEndpointDiscoverer}. * Tests for {@link ControllerEndpointDiscoverer}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
public class ControllerEndpointDiscovererTests { public class ControllerEndpointDiscovererTests {
@Rule @Rule
public final ExpectedException thrown = ExpectedException.none(); public final ExpectedException thrown = ExpectedException.none();
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test @Test
public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() { public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {
load(EmptyConfiguration.class, this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run(
(discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty()); assertDiscoverer((discoverer) ->
assertThat(discoverer.getEndpoints()).isEmpty()));
} }
@Test @Test
public void getEndpointsShouldIncludeControllerEndpoints() { public void getEndpointsShouldIncludeControllerEndpoints() {
load(TestControllerEndpoint.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestControllerEndpoint.class)
Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints(); .run(assertDiscoverer((discoverer) -> {
assertThat(endpoints).hasSize(1); Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();
ExposableControllerEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoints).hasSize(1);
assertThat(endpoint.getId()).isEqualTo("testcontroller"); ExposableControllerEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getController()) assertThat(endpoint.getId()).isEqualTo("testcontroller");
.isInstanceOf(TestControllerEndpoint.class); assertThat(endpoint.getController())
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); .isInstanceOf(TestControllerEndpoint.class);
}); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}));
}
@Test
public void getEndpointsShouldDiscoverProxyControllerEndpoints() {
this.contextRunner.withUserConfiguration(TestProxyControllerEndpoint.class)
.withConfiguration(AutoConfigurations.of(
ValidationAutoConfiguration.class))
.run(assertDiscoverer((discoverer) -> {
Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();
assertThat(endpoints).hasSize(1);
ExposableControllerEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getId()).isEqualTo("testcontroller");
assertThat(endpoint.getController())
.isInstanceOf(TestProxyControllerEndpoint.class);
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}));
} }
@Test @Test
public void getEndpointsShouldIncludeRestControllerEndpoints() { public void getEndpointsShouldIncludeRestControllerEndpoints() {
load(TestRestControllerEndpoint.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestRestControllerEndpoint.class)
Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints(); .run(assertDiscoverer((discoverer) -> {
assertThat(endpoints).hasSize(1); Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();
ExposableControllerEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoints).hasSize(1);
assertThat(endpoint.getId()).isEqualTo("testrestcontroller"); ExposableControllerEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getController()) assertThat(endpoint.getId()).isEqualTo("testrestcontroller");
.isInstanceOf(TestRestControllerEndpoint.class); assertThat(endpoint.getController())
}); .isInstanceOf(TestRestControllerEndpoint.class);
}));
}
@Test
public void getEndpointsShouldDiscoverProxyRestControllerEndpoints() {
this.contextRunner.withUserConfiguration(TestProxyRestControllerEndpoint.class)
.withConfiguration(AutoConfigurations.of(
ValidationAutoConfiguration.class))
.run(assertDiscoverer((discoverer) -> {
Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();
assertThat(endpoints).hasSize(1);
ExposableControllerEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getId()).isEqualTo("testrestcontroller");
assertThat(endpoint.getController())
.isInstanceOf(TestProxyRestControllerEndpoint.class);
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}));
} }
@Test @Test
public void getEndpointsShouldNotDiscoverRegularEndpoints() { public void getEndpointsShouldNotDiscoverRegularEndpoints() {
load(WithRegularEndpointConfiguration.class, (discoverer) -> { this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)
Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints(); .run(assertDiscoverer((discoverer) -> {
List<String> ids = endpoints.stream().map(ExposableEndpoint::getId) Collection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();
.collect(Collectors.toList()); List<String> ids = endpoints.stream().map(ExposableEndpoint::getId)
assertThat(ids).containsOnly("testcontroller", "testrestcontroller"); .collect(Collectors.toList());
}); assertThat(ids).containsOnly("testcontroller", "testrestcontroller");
}));
} }
@Test @Test
public void getEndpointWhenEndpointHasOperationsShouldThrowException() { public void getEndpointWhenEndpointHasOperationsShouldThrowException() {
load(TestControllerWithOperation.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestControllerWithOperation.class)
this.thrown.expect(IllegalStateException.class); .run(assertDiscoverer((discoverer) -> {
this.thrown.expectMessage("ControllerEndpoints must not declare operations"); this.thrown.expect(IllegalStateException.class);
discoverer.getEndpoints(); this.thrown.expectMessage("ControllerEndpoints must not declare operations");
}); discoverer.getEndpoints();
}));
} }
private void load(Class<?> configuration, private ContextConsumer<AssertableApplicationContext> assertDiscoverer(
Consumer<ControllerEndpointDiscoverer> consumer) { Consumer<ControllerEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( return (context) -> {
configuration);
try {
ControllerEndpointDiscoverer discoverer = new ControllerEndpointDiscoverer( ControllerEndpointDiscoverer discoverer = new ControllerEndpointDiscoverer(
context, PathMapper.useEndpointId(), Collections.emptyList()); context, PathMapper.useEndpointId(), Collections.emptyList());
consumer.accept(discoverer); consumer.accept(discoverer);
} };
finally {
context.close();
}
} }
@Configuration @Configuration
...@@ -128,11 +168,23 @@ public class ControllerEndpointDiscovererTests { ...@@ -128,11 +168,23 @@ public class ControllerEndpointDiscovererTests {
} }
@ControllerEndpoint(id = "testcontroller")
@Validated
static class TestProxyControllerEndpoint {
}
@RestControllerEndpoint(id = "testrestcontroller") @RestControllerEndpoint(id = "testrestcontroller")
static class TestRestControllerEndpoint { static class TestRestControllerEndpoint {
} }
@RestControllerEndpoint(id = "testrestcontroller")
@Validated
static class TestProxyRestControllerEndpoint {
}
@Endpoint(id = "test") @Endpoint(id = "test")
static class TestEndpoint { static class TestEndpoint {
......
...@@ -40,9 +40,14 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; ...@@ -40,9 +40,14 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.EndpointServlet; import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.PathMapper;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.validation.annotation.Validated;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -50,88 +55,108 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -50,88 +55,108 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link ServletEndpointDiscoverer}. * Tests for {@link ServletEndpointDiscoverer}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
public class ServletEndpointDiscovererTests { public class ServletEndpointDiscovererTests {
@Rule @Rule
public final ExpectedException thrown = ExpectedException.none(); public final ExpectedException thrown = ExpectedException.none();
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test @Test
public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() { public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {
load(EmptyConfiguration.class, this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
(discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty()); .run(assertDiscoverer((discoverer)
-> assertThat(discoverer.getEndpoints()).isEmpty()));
} }
@Test @Test
public void getEndpointsShouldIncludeServletEndpoints() { public void getEndpointsShouldIncludeServletEndpoints() {
load(TestServletEndpoint.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestServletEndpoint.class)
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints(); .run(assertDiscoverer((discoverer) -> {
assertThat(endpoints).hasSize(1); Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
ExposableServletEndpoint endpoint = endpoints.iterator().next(); assertThat(endpoints).hasSize(1);
assertThat(endpoint.getId()).isEqualTo("testservlet"); ExposableServletEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getEndpointServlet()).isNotNull(); assertThat(endpoint.getId()).isEqualTo("testservlet");
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class); assertThat(endpoint.getEndpointServlet()).isNotNull();
}); assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}));
}
@Test
public void getEndpointsShouldDiscoverProxyServletEndpoints() {
this.contextRunner.withUserConfiguration(TestProxyServletEndpoint.class)
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))
.run(assertDiscoverer((discoverer) -> {
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
assertThat(endpoints).hasSize(1);
ExposableServletEndpoint endpoint = endpoints.iterator().next();
assertThat(endpoint.getId()).isEqualTo("testservlet");
assertThat(endpoint.getEndpointServlet()).isNotNull();
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
}));
} }
@Test @Test
public void getEndpointsShouldNotDiscoverRegularEndpoints() { public void getEndpointsShouldNotDiscoverRegularEndpoints() {
load(WithRegularEndpointConfiguration.class, (discoverer) -> { this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints(); .run(assertDiscoverer((discoverer) -> {
List<String> ids = endpoints.stream().map(ExposableEndpoint::getId) Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
.collect(Collectors.toList()); List<String> ids = endpoints.stream().map(ExposableEndpoint::getId)
assertThat(ids).containsOnly("testservlet"); .collect(Collectors.toList());
}); assertThat(ids).containsOnly("testservlet");
}));
} }
@Test @Test
public void getEndpointWhenEndpointHasOperationsShouldThrowException() { public void getEndpointWhenEndpointHasOperationsShouldThrowException() {
load(TestServletEndpointWithOperation.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestServletEndpointWithOperation.class)
this.thrown.expect(IllegalStateException.class); .run(assertDiscoverer((discoverer) -> {
this.thrown.expectMessage("ServletEndpoints must not declare operations"); this.thrown.expect(IllegalStateException.class);
discoverer.getEndpoints(); this.thrown.expectMessage("ServletEndpoints must not declare operations");
}); discoverer.getEndpoints();
}));
} }
@Test @Test
public void getEndpointWhenEndpointNotASupplierShouldThrowException() { public void getEndpointWhenEndpointNotASupplierShouldThrowException() {
load(TestServletEndpointNotASupplier.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestServletEndpointNotASupplier.class)
this.thrown.expect(IllegalStateException.class); .run(assertDiscoverer((discoverer) -> {
this.thrown.expectMessage("must be a supplier"); this.thrown.expect(IllegalStateException.class);
discoverer.getEndpoints(); this.thrown.expectMessage("must be a supplier");
}); discoverer.getEndpoints();
}));
} }
@Test @Test
public void getEndpointWhenEndpointSuppliesWrongTypeShouldThrowException() { public void getEndpointWhenEndpointSuppliesWrongTypeShouldThrowException() {
load(TestServletEndpointSupplierOfWrongType.class, (discoverer) -> { this.contextRunner
this.thrown.expect(IllegalStateException.class); .withUserConfiguration(TestServletEndpointSupplierOfWrongType.class)
this.thrown.expectMessage("must supply an EndpointServlet"); .run(assertDiscoverer((discoverer) -> {
discoverer.getEndpoints(); this.thrown.expect(IllegalStateException.class);
}); this.thrown.expectMessage("must supply an EndpointServlet");
discoverer.getEndpoints();
}));
} }
@Test @Test
public void getEndpointWhenEndpointSuppliesNullShouldThrowException() { public void getEndpointWhenEndpointSuppliesNullShouldThrowException() {
load(TestServletEndpointSupplierOfNull.class, (discoverer) -> { this.contextRunner.withUserConfiguration(TestServletEndpointSupplierOfNull.class)
this.thrown.expect(IllegalStateException.class); .run(assertDiscoverer((discoverer) -> {
this.thrown.expectMessage("must not supply null"); this.thrown.expect(IllegalStateException.class);
discoverer.getEndpoints(); this.thrown.expectMessage("must not supply null");
}); discoverer.getEndpoints();
}));
} }
private void load(Class<?> configuration, private ContextConsumer<AssertableApplicationContext> assertDiscoverer(
Consumer<ServletEndpointDiscoverer> consumer) { Consumer<ServletEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( return (context) -> {
configuration);
try {
ServletEndpointDiscoverer discoverer = new ServletEndpointDiscoverer(context, ServletEndpointDiscoverer discoverer = new ServletEndpointDiscoverer(context,
PathMapper.useEndpointId(), Collections.emptyList()); PathMapper.useEndpointId(), Collections.emptyList());
consumer.accept(discoverer); consumer.accept(discoverer);
} };
finally {
context.close();
}
} }
@Configuration @Configuration
...@@ -155,6 +180,17 @@ public class ServletEndpointDiscovererTests { ...@@ -155,6 +180,17 @@ public class ServletEndpointDiscovererTests {
} }
@ServletEndpoint(id = "testservlet")
@Validated
static class TestProxyServletEndpoint implements Supplier<EndpointServlet> {
@Override
public EndpointServlet get() {
return new EndpointServlet(TestServlet.class);
}
}
@Endpoint(id = "test") @Endpoint(id = "test")
static class TestEndpoint { static class TestEndpoint {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment