Properly discover endpoints that are proxied

Previously to this commit, if a `@ControllerEndpoint`,
`@RestControllerEndpoint` or `@ServletEndpoint` annotated bean was
proxied, the endpoint wasn't properly detected.

This commit makes sure that annotation retrieval works on the user class
while preserving the get (vs. find) retrieval semantic

Closes gh-12441
pull/12890/head
Stephane Nicoll 7 years ago
parent 86b96254a1
commit e8fac7d9c4

@ -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
@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;
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
@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,11 +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.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer; 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;
@ -73,6 +76,22 @@ public class ControllerEndpointDiscovererTests {
})); }));
} }
@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() {
this.contextRunner.withUserConfiguration(TestRestControllerEndpoint.class) this.contextRunner.withUserConfiguration(TestRestControllerEndpoint.class)
@ -86,6 +105,22 @@ public class ControllerEndpointDiscovererTests {
})); }));
} }
@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() {
this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class) this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)
@ -133,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,11 +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.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer; 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;
@ -81,6 +84,20 @@ public class ServletEndpointDiscovererTests {
})); }));
} }
@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() {
this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class) this.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)
@ -163,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 {

Loading…
Cancel
Save