Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ControllerLinkBuilder.linkTo is not working for actuator @Endpoint #674

Closed
Aloren opened this issue Nov 17, 2017 · 6 comments
Closed

ControllerLinkBuilder.linkTo is not working for actuator @Endpoint #674

Aloren opened this issue Nov 17, 2017 · 6 comments

Comments

@Aloren
Copy link

Aloren commented Nov 17, 2017

We are currently in the process of migrating from Spring Boot 1.5 to 2.0. We were previously using actuator's class MvcEndpoint with @RequestMapping. Now new annotation for actuator endpoints was introduced: @Endpoint. The following code was producing valid hateoas links in Spring Boot 1.5:

@RequestMapping("/dashboards")
public class MetricsDashboardsEndpoint implements MvcEndpoint {
    @RequestMapping(method = GET)
    @ResponseBody
    public List<Link> dashboards() throws IOException {
        return resources.keySet().stream()
                .map(name -> linkTo(DashboardsEndpoint.class).slash(name).withRel("dashboard"))
                .collect(Collectors.toList());
    }

The same code migrated to Spring Boot 2.0:

@Endpoint(id = "dashboards")
public class MetricsDashboardsEndpoint {
    @ReadOperation
    public List<Link> dashboards() throws IOException {
        return resources.keySet().stream()
                .map(name -> linkTo(MetricsDashboardsEndpoint.class).slash(name).withRel("dashboard"))
                .collect(Collectors.toList());
    }

Actual result in Spring Boot 1.5: "href":"http://localhost:9999/dashboards/dashboard2.json"
Actual result in in Spring Boot 2.0: "href":"http://localhost:9999/dashboard2.json"
Expected result in Spring Boot 2.0: "href":"http://localhost:9999/application/dashboards/dashboard2.json"

As I understand the issue is within ControllerLinkBuilder:

	private static final CachingAnnotationMappingDiscoverer DISCOVERER = new CachingAnnotationMappingDiscoverer(
			new AnnotationMappingDiscoverer(RequestMapping.class));

It only knows about @RequestMapping and knows nothing about new @Endpoint.

Could you please advise what is the correct way in Spring Boot Actuator 2.0 to produce links with valid base path?

@odrotbohm
Copy link
Member

I guess we need @wilkinsona's advice here. I'm afraid we can't do much about that as Spring HATEOAS doesn't and must not know anything about Spring Boot specifics. The only thing I can imagine is an @RequestMapping meta-annotation on @Endpoint and then somehow pointing to the configured basepath, so that we can obtain that via Spring-standard mechanisms (environment based property lookups?)

@Aloren
Copy link
Author

Aloren commented Nov 17, 2017

I've found temporary workaround using EndpointPathProvider:

    @Autowired
    private EndpointPathProvider endpointPathProvider;
    @ReadOperation
    public List<Link> dashboards() {
        String dashboards = endpointPathProvider.getPath(DASHBOARDS_ID);
        return resources.keySet().stream()
                .map(name -> BasicLinkBuilder.linkToCurrentMapping().slash(dashboards).slash(name).withRel(DASHBOARD))
                .collect(Collectors.toList());
    }

I also found the following ticket:
spring-projects/spring-boot#9901
As I understand there is a way to produce links in Actuator without Hateoas, but I haven't found API to do that for my custom endpoint :(

@wilkinsona
Copy link
Member

wilkinsona commented Nov 17, 2017

An endpoint, even a web-specific one, that's trying to do something that's Spring MVC-specific doesn't feel right to me. The endpoint contract in Spring Boot 2.0 has been deliberately tightened up to allow us to expose endpoints using Jersey, Spring MVC, or WebFlux in addition to JMX.

We can, perhaps, look at providing an API for web-specific Actuator endpoints that lets you build links, or at least gives you access to the current path. Spring HATEOAS isn't the right tool for the job, though, as it's coupled to Spring's @RequestMapping as @olivergierke explained above. If you'd like to pursue this option, please open a Spring Boot issue.

If your endpoint doesn't need the flexibility of being exposable using Jersey, WebFlux, or Spring MVC, you could turn it into a regular Spring MVC controller and continue to use your current approach.

@Aloren
Copy link
Author

Aloren commented Nov 17, 2017

I would like to have simple controller registered on management port. Previously I was using MvcEndpoint to register my controller on management port and now I don't see any other option except for @WebEndpointExtension which is also not supported by hateoas. So I don't have any clean options to use hateoas for actuator web endpoint.
@wilkinsona do you mind if I open ticket regarding my current concern in Spring Actuator project?

@snicoll
Copy link
Member

snicoll commented Nov 18, 2017

@Aloren you can register your controller in the management context, please see the documentation. Note that the doc isn't as obvious as the 1.5.x version but we intend to work on that.

We've discussed this use case on the team call yesterday and reinstating MvcEndpoint in a different fashion is under consideration. Regardless, please add your controller in the management context (as explained above).

I guess there's not much we can do here so if that doesn't work, please raise an issue in the Spring Boot tracker. Thanks!

@Aloren
Copy link
Author

Aloren commented Nov 24, 2017

Thank you for the answers.
I will wait for the decision on: spring-projects/spring-boot#10257
I suppose it will resolve my issue with management controller.

@Aloren Aloren closed this as completed Nov 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants