4

I am developing a Service based on Spring Data REST. Cause of the fact that we are creating the frontend code using swagger (generated via SpringFox) I had to deactivate the return of the HAL-format which works fine with one exception.

If the result of a request is an empty list the response looks like this

{
"links": [
    {
        "rel": "self",
        "href": "http://localhost:9999/users"
    },
    {
        "rel": "profile",
        "href": "http://localhost:9999/profile/users"
    }
],
"content": [
    {
        "rel": null,
        "collectionValue": true,
        "relTargetType": "com.example.User",
        "value": []
    }
]
}

How can I get an empty List as content?

stoetti
  • 93
  • 1
  • 5
  • Hey @stoetti, have you found a solution for this? I'm facing the same issue. – Davi Cavalcanti Mar 05 '18 at 07:35
  • 1
    Hello back! Sorry, I did not get any answer or found a server side solution, so we handled on the client side with special handling of the empty response. – stoetti Mar 07 '18 at 05:03
  • Ha, that's what I'm doing as well. I don't really get the behaviour, as when there are no results back from a get / and there is nothing to return it just returns an empty content array [ ]. For my that's really a bug, as it causes an unneeded lack of consistency. Thanks for getting back to me on this @stoetti ;-) – Davi Cavalcanti Mar 08 '18 at 06:00
  • hey, found anything? – Daniel Jeney Dec 18 '19 at 09:59
  • No but we did not investigate further as with the default HATEOAS serialization the response is en empty "embedded" collection – stoetti Dec 19 '19 at 10:12

2 Answers2

2

I have had to adapt the solution provided in the previous solution to use the types introduced by the Spring HATEOAS 1.x

This is the code I'm using:

@Component
public class ResourceProcessorEmpty implements RepresentationModelProcessor<CollectionModel<Object>> {
    @Override
    public CollectionModel<Object> process(CollectionModel<Object> resourceToThrowAway) {
        if (resourceToThrowAway.getContent().size() != 1) {
            return resourceToThrowAway;
        }
        if (!resourceToThrowAway.getContent().iterator().next().getClass().getCanonicalName().contains("EmptyCollectionEmbeddedWrapper")) {
            return resourceToThrowAway;
        }

        CollectionModel<Object> newResource = new CollectionModel<>(Collections.emptyList());
        newResource.add(resourceToThrowAway.getLinks());
        return newResource;
    }
}
antdavidl
  • 21
  • 1
  • 4
1

The best and easiest solution i found finally for this so far is the following. Implement a custom ResourceProcessor, which is automatically picked up and used by spring(because of the @Component). Override the process method and in the method return a new Resource() which is initialized with an empty list, instead of the old Resource you got as an argument, add the links and all what you want and that's it. Like this:

import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceProcessor;
import org.springframework.hateoas.Resources;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Component
public class ResourceProcessorEmpty implements ResourceProcessor<Resources<Object>>
{
    @Override
    public Resources<Object> process(final Resources<Object> resourceToThrowAway)
    {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

// In my case i needed the request link with parameters, and the empty content[] array

        Link link = new Link(request.getRequestURL().toString() + "?" + request.getQueryString());
        Resources<Object> newResource = new Resources<>(Collections.emptyList());
        newResource.add(link);
        return newResource;
    }
}

For clarification: if you use Resources<Object>, that will handle empty collections(when that "EmptyCollectionEmbeddedWrapper" dummy object would be returned), whereas Resources<Resource<Object>> will handle non-empty collections. In this case the first needs to be used.

Daniel Jeney
  • 486
  • 1
  • 5
  • 19