0

I have a spring-data-rest & spring-hateoas app powering a UI that depends heavily on the presence of the _links field in all responses. This has been working well. However I have a need to serialize response models out-of-band of any request (during a scheduled task), which then need to be fed to an event stream API. In this case there is no available current servlet request at serialization time, and the default RepositoryEntityLinks implementation breaks.

In python/Django I would be able to provide a "mock request" object prefilled with data from configuration settings which the framework would use to serialize links for this purpose, but that doesn't appear to be an option here.

As far as I can tell, I would be able to fix this issue were I able to override the following method in the default RepositoryEntityLinks implementation and add a fallback for how to serialize links when a request is not present:

// RepositoryEntityLinks.java
@Override
public LinkBuilder linkFor(Class<?> type) {
    ResourceMetadata metadata = mappings.getMetadataFor(type);
    return new RepositoryLinkBuilder(metadata, new BaseUri(config.getBasePath()));
}

// BaseURI.java
public UriComponentsBuilder getUriComponentsBuilder() {
    return baseUri.isAbsolute() //
        ? UriComponentsBuilder.fromUri(baseUri) //
        : ServletUriComponentsBuilder.fromCurrentServletMapping().path(baseUri.toString());
    }
}

However I've found no way to do this easily. I've tried several hacks to provide an absolute baseUri but all have caused more issues that they've solved.

Any suggestions on how to do this? I'm open to completely new approaches as well.

Here is my code that triggers this issue:

@Scheduled(fixedRate = threeSecondRate)
public void doScheduledTask() {
    for (var resource : getResources(()) {
        doOutOfBandOperation(resource);
        
        eventPublisher.publishEvent(new BeforeSaveEvent(resource));
        resourceRepository.save(resource);
        eventPublisher.publishEvent(new AfterSaveEvent(resource));
    }
}

@HandleAfterSave
public void onSave(MyResource myResource) {
    // This is the line that breaks trying to assemble the links for the resource.
    var resource = invoker.getObject().invokeProcessorsFor(resourceAssembler().toFullResource(myResource));
    eventService.broadcastUpdated(resource);
}

0 Answers0