7

In our Spring-Data-Rest Project we have a custom (fuzzy) search on a /buergers/search/findBuergerFuzzy?searchString="..." endpoint.

Is it possible to add a link for it on the /buergers/search endpoint (Without overriding the automatically exposed Repository findBy Methods)?

The Controller exposing the search:

@BasePathAwareController
@RequestMapping("/buergers/search/")
public class BuergerSearchController {

    @Autowired
    QueryService service;

    @RequestMapping(value = "/findBuergerFuzzy", method = RequestMethod.GET)
    public
    @ResponseBody
    ResponseEntity<?> findBuergerFuzzy(PersistentEntityResourceAssembler assembler, @Param("searchString") String searchString) {
        if (searchString.length() < 3)
            throw new IllegalArgumentException("Search String must be at least 3 chars long.");
        List<Buerger> list = service.query(searchString, Buerger.class, new String[]{"vorname", "nachname", "geburtsdatum", "augenfarbe"});
        final List<PersistentEntityResource> collect = list.stream().map(assembler::toResource).collect(Collectors.toList());
        return new ResponseEntity<Object>(new Resources<>(collect), HttpStatus.OK);
    }
}
Peter Müller
  • 273
  • 2
  • 8

2 Answers2

7

UPDATE: This is an outdated workaround answer. Upgrade to Spring HATEOAS 1.0.


Old Workaround:

Digging the spring-data-rest source i found the RepositorySearchesResource which seems to solve the problem.

@Component
public class SearchResourcesProcessor implements ResourceProcessor<RepositorySearchesResource> {

    @Override
    public RepositorySearchesResource process(RepositorySearchesResource repositorySearchesResource) {
        final String search = repositorySearchesResource.getId().getHref();
        final Link findFullTextFuzzy = new Link(search + "/findFullTextFuzzy{?q}").withRel("findFullTextFuzzy");
        repositorySearchesResource.add(findFullTextFuzzy);

        return repositorySearchesResource;
    }
}

Because we generate this code by templates, this is sufficient and fullfills our needs. Make sure to check the comments for the right and safe way.

Peter Müller
  • 273
  • 2
  • 8
  • 3
    You should check `resource.getDomainType()` to make sure your search function only displays at the right resource. `if(ResourceClass.class.equals(resource.getDomainType()))` – Ákos Ratku Sep 28 '15 at 15:24
  • 3
    Your solution is quite dangerous, because you are losing consistency between the mapping of your method (where is it served) and the linking of it (where following the relation will lead). You should use `linkTo` and `methodOn` static methods from Spring Hateoas to avoid that when creating you `Link` – JR Utily Oct 05 '15 at 14:53
  • The answer is too old now – Jess Chen Apr 02 '21 at 05:48
2

Version

migrate-to-1.0.changes

ResourceSupport is now RepresentationModel

Resource is now EntityModel

Resources is now CollectionModel

PagedResources is now PagedModel

Code

The code for new version:

import org.springframework.data.rest.webmvc.RepositorySearchesResource;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.stereotype.Component;

@Component
public class RepositorySearchesProcessor implements RepresentationModelProcessor<RepositorySearchesResource> {

    @Override
    public RepositorySearchesResource process(RepositorySearchesResource model) {
        System.out.println(model.getDomainType());
        model.add(Link.of(model.getRequiredLink("self").getHref() + "/findFullTextFuzzy{?q}").withRel("findFullTextFuzzy"));
        return model;
    }
}

How

About how to find what resource or model you use, after setting breakpoints in each method of RepresentationModel, you maybe find something useful :

enter image description here

Jess Chen
  • 3,136
  • 1
  • 26
  • 35