1

I have a spring data repository like that:

@RepositoryRestResource(collectionResourceRel = "items", path = "items")
public interface ItemRepository extends CrudRepository<Item, Long> {
}

and my custom repository:

@RepositoryRestController
@ExposesResourceFor(Item.class)
@RequestMapping("items")
public class CustomItemController implements ResourceProcessor<RepositoryLinksResource> {

    @Autowired
    ItemRepository itemRepository;


    @GetMapping(value = "/customMethod")
    @ResponseBody
    public List<String> customMethod() {

        //some logic
    }

    @Override
    public RepositoryLinksResource process(RepositoryLinksResource resource) {
        resource.add(linkTo(methodOn(CustomItemController.class).customMethod()).withRel("customMethod"));
        return resource;
    }
}

I would like to have a link to the custom method on the level of collection entities,

{
    _embedded: {
        items: [...]
    },
    _links: {
        self: {
            href: "https://localhost:8080/api/items"
        },
        profile: {
            href: "https://localhost:8080/api/profile/items"
        },
        search: {
            href: "https://localhost:8080/api/items/search"
        },
        customMethod: {
            href: "https://localhost:8080/api/items/customMethod"
        }
    }   
}

but with the above solution I have it at the root level of my API. If I change RepositoryLinksResource to the Resource, I will have the method on the level of entity. Any ideas/clues how to implement it?

Mathias Dpunkt
  • 11,594
  • 4
  • 45
  • 70
Bartek
  • 41
  • 2

1 Answers1

0

Since you're using Spring HATEOAS, the collection is a PagedResources. Also, I would advise to apply separation of concerns and implement the resource processor in a separate class, i.e. not in the controller.

You need to implement ResourceProcessor<PagedResources<Resource<CustomItem>>>:

@Component
public class CustomItemPageResourceProcessor implements ResourceProcessor<PagedResources<Resource<CustomItem>>> {

@Override
public PagedResources<Resource<CustomItem>> process(PagedResources<Resource<CustomItem>> pagedResources) {
    Link link = BasicLinkBuilder.linkToCurrentMapping()
                                .slash(pagedResources.getId().getHref())
                                .slash("customMethod")
                                .withRel("customMethod");
    pagedResources.add(link);

    return pagedResources;
}

Note that every generated PagedResources<Resource<CustomItem>> will be added the link. I haven't found a way to prevent generating the link when hitting a specific URL, for instance.

Marc Tarin
  • 3,109
  • 17
  • 49
  • Thanks for answer, but this solution works only for repositories which extend PagingAndSortingRepository, in my case I use CrudRepository. – Bartek May 03 '17 at 14:54
  • This information is useful, you should add it to your original post. Anyway, now it all boils down to finding the T type to pass to `ResourceProcessor` maybe `ResourceProcessor>` as suggested [here](http://stackoverflow.com/a/24288077/5873923). – Marc Tarin May 04 '17 at 08:23