spring-projects / spring-data-rest

Simplifies building hypermedia-driven REST web services on top of Spring Data repositories
https://spring.io/projects/spring-data-rest
Apache License 2.0
920 stars 563 forks source link

Empty collections are not serialized properly with default media type json [DATAREST-1346] #1709

Open spring-projects-issues opened 5 years ago

spring-projects-issues commented 5 years ago

MitchelLabonte opened DATAREST-1346 and commented

 

When setting the default media type to application/json, an empty collection will be serialized like this:

"content": [ {

"value": [ ],

"relTargetType": "redacted",

"collectionValue": true,

"rel": null

}]

 

This happens because class AbstractRepositoryRestController, method entitiesToResources maps empty collections to an EmptyCollectionEmbeddedWrapper no matter what media type is used. But, the custom deserializer for EmptyCollectionEmbeddedWrapper is only used when using hal as the mediatype


Affects: 3.1.5 (Lovelace SR5)

spring-projects-issues commented 5 years ago

Ben Madore commented

People have been running into this on Stack Overflow for a few years, and there has been no response from anyone:

 

https://stackoverflow.com/questions/45590207/spring-data-rest-returns-emptycollectionembeddedwrapper-instead-of-empty-collect

https://stackoverflow.com/questions/40654754/empty-collection-returns-single-object-in-spring-data-rest-instead-of-empty-arra

 

spring-projects-issues commented 4 years ago

David Lopez commented

I'm puzzled to see that this issue is reported and has not been fixed so far.

IMHO, it is quite blocking as returning an empty list of resources is a quite usual case.

 

I'm not aware of any good workaround; all that I have found either does not work or is extremely tricky (and unportable).

 

Sadly, I'll have to remove Spring Data REST from the project; it was promising, but I don't know how I could handle correctly this situation.

 

I read that Resources class handles this situation, but it seems that the latest versions of Spring HATEOAS remove these classes and remove them by EntityModel/CollectionModel which fails in the de-serialization

spring-projects-issues commented 4 years ago

David Lopez commented

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

@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;
    }
}
johnny-minty commented 3 years ago

The above workaround works and ensures Spring Data Rest returns an empty list in the 'content' element instead of a 1 element array.

Returning an array with a single element is very strange when there are no rows in the datasource..