Adding more information to the HATEOAS response in Spring Boot Data Rest
Asked Answered
D

2

6

I have the following REST controller.

@RepositoryRestController
@RequestMapping(value = "/booksCustom")
public class BooksController extends ResourceSupport {

    @Autowired
    public BooksService booksService;

    @Autowired
    private PagedResourcesAssembler<Books> booksAssembler;

    @RequestMapping("/search")
    public HttpEntity<PagedResources<Resource<Books>>> search(@RequestParam(value = "q", required = false) String query, @PageableDefault(page = 0, size = 20) Pageable pageable) {
        pageable = new PageRequest(0, 20);

        Page<Books> booksResult = BooksService.findBookText(query, pageable);

        return new ResponseEntity<PagedResources<Resource<Books>>>(BooksAssembler.toResource(BooksResult), HttpStatus.OK);

    }

My Page<Books> BooksResult = BooksService.findBookText(query, pageable); is backed by SolrCrudRepository. When it is run BookResult has several fields in it, the content field and several other fields, one being highlighted. Unfortunately the only thing I get back from the REST response is the data in the content field and the metadata information in the HATEOAS response (e.g. page information, links, etc.). What would be the proper way of adding the highlighted field to the response? I'm assuming I would need to modify the ResponseEntity, but unsure of the proper way.

Edit:

Model:

@SolrDocument(solrCoreName = "Books_Core")
public class Books {
    @Field
    private String id;

    @Field
    private String filename;

    @Field("full_text")
    private String fullText;

    //Getters and setters omitted 
    ...
}

When a search and the SolrRepository is called (e.g. BooksService.findBookText(query, pageable);) I get back these objects.

enter image description here

However, in my REST response I only see the "content". I would like to be able to add the "highlighted" object to the REST response. It just appears that HATEOAS is only sending the information in the "content" object (see below for the object).

{
  "_embedded" : {
    "solrBooks" : [ {
      "filename" : "ABookName",
      "fullText" : "ABook Text"
    } ]
  },
  "_links" : {
    "first" : {
      "href" : "http://localhost:8080/booksCustom/search?q=ABook&page=0&size=20"
    },
    "self" : {
      "href" : "http://localhost:8080/booksCustom/search?q=ABook"
    },
    "next" : {
      "href" : "http://localhost:8080/booksCustom/search?q=ABook&page=0&size=20"
    },
    "last" : {
      "href" : "http://localhost:8080/booksCustom/search?q=ABook&page=0&size=20"
    }
  },
  "page" : {
    "size" : 1,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

Just so you can get a full picture, this is the repository that is backing the BooksService. All the service does is call this SolrCrudRepository method.

public interface SolrBooksRepository extends SolrCrudRepository<Books, String> {

    @Highlight(prefix = "<highlight>", postfix = "</highlight>", fragsize = 20, snipplets = 3)
    HighlightPage<SolrTestDocuments> findBookText(@Param("fullText") String fullText, Pageable pageable);

}
Disproof answered 2/12, 2016 at 23:52 Comment(6)
Since something seems to be different between content and highlighted you should show us the source code for Books. An actual snippet of the actual result and the result you expect/want might help to.Womanhood
Please make variable and field names lower case. Upper case names look like class names to Java developers.Womanhood
Would help if you post your Books entity class.Eardrum
@JensSchauder. Thanks. I added the information you suggestion and a few additional items that I thought would help.Disproof
How did you solved this problem?Disparate
@Disparate I was using Page<Books> instead of HighlightPage to create the response page. Page obviously doesn't contain content which was causing the highlighted portion to be truncated. Solution is below.Disproof
D
4

I was using Page<Books> instead of HighlightPage to create the response page. Page obviously doesn't contain content which was causing the highlighted portion to be truncated. I ended up creating a new page based off of HighlightPage and returning that as my result instead of Page.

@RepositoryRestController
@RequestMapping(value = "/booksCustom")
public class BooksController extends ResourceSupport {

    @Autowired
    public BooksService booksService;

    @Autowired
    private PagedResourcesAssembler<Books> booksAssembler;

    @RequestMapping("/search")
    public HttpEntity<PagedResources<Resource<HighlightPage>>> search(@RequestParam(value = "q", required = false) String query, @PageableDefault(page = 0, size = 20) Pageable pageable) {

        HighlightPage solrBookResult = booksService.findBookText(query, pageable);
        Page<Books> highlightedPages = new PageImpl(solrBookResult.getHighlighted(), pageable, solrBookResult.getTotalElements());
        return new ResponseEntity<PagedResources<Resource<HighlightPage>>>(booksAssembler.toResource(highlightedPages), HttpStatus.OK); 
    }

Probably a better way of doing this, but I couldn't find anything that would do what I wanted it to do without having a change a ton of code. Hope this helps!

Disproof answered 13/2, 2017 at 16:37 Comment(3)
Thanks, but thats what probably is not suitable for us. Thanks!Disparate
No problem! Would be curious as to how you solve the problem. Good luck.Disproof
I ve added my solution, maybe it will help you.Disparate
D
8

Ok, here is how I did it: I wrote mine HighlightPagedResources

public class HighlightPagedResources<R,T> extends PagedResources<R> {

    private List<HighlightEntry<T>> phrases;

    public HighlightPagedResources(Collection<R> content, PageMetadata metadata, List<HighlightEntry<T>> highlightPhrases, Link... links) {
        super(content, metadata, links);
        this.phrases = highlightPhrases;
    }

    @JsonProperty("highlighting")
    public List<HighlightEntry<T>> getHighlightedPhrases() {
        return phrases;
    }
}

and HighlightPagedResourcesAssembler:

public class HighlightPagedResourcesAssembler<T> extends PagedResourcesAssembler<T> {

    public HighlightPagedResourcesAssembler(HateoasPageableHandlerMethodArgumentResolver resolver, UriComponents baseUri) {
        super(resolver, baseUri);
    }


    public <R extends ResourceSupport> HighlightPagedResources<R,T> toResource(HighlightPage<T> page, ResourceAssembler<T, R> assembler) {
        final PagedResources<R> rs = super.toResource(page, assembler);
        final Link[] links = new Link[rs.getLinks().size()];
        return new HighlightPagedResources<R, T>(rs.getContent(), rs.getMetadata(), page.getHighlighted(), rs.getLinks().toArray(links));
    }
}

I had to add to my spring RepositoryRestMvcConfiguration.java:

@Primary
@Bean
public HighlightPagedResourcesAssembler solrPagedResourcesAssembler() {
    return new HighlightPagedResourcesAssembler<Object>(pageableResolver(), null);
}

In cotroller I had to change PagedResourcesAssembler for newly implemented one and also use new HighlightPagedResources in request method:

@Autowired
private HighlightPagedResourcesAssembler<Object> highlightPagedResourcesAssembler;

@RequestMapping(value = "/conversations/search", method = POST)

public HighlightPagedResources<PersistentEntityResource, Object> findAll(
        @RequestBody ConversationSearch search,
        @SortDefault(sort = FIELD_LATEST_SEGMENT_START_DATE_TIME, direction = DESC) Pageable pageable,
        PersistentEntityResourceAssembler assembler) {

    HighlightPage page = conversationRepository.findByConversationSearch(search, pageable);
    return highlightPagedResourcesAssembler.toResource(page, assembler);
}

RESULT:

  {
  "_embedded": {
    "conversations": [
    ..our stuff..
    ]
  },
  "_links": {
    ...as you know them...
  },
  "page": {
    "size": 1,
    "totalElements": 25,
    "totalPages": 25,
    "number": 0
  },
  "highlighting": [
    {
      "entity": {
        "conversationId": "a2127d01-747e-4312-b230-01c63dacac5a",
        ...
      },
      "highlights": [
        {
          "field": {
            "name": "textBody"
          },
          "snipplets": [
            "Additional XXX License for YYY Servers DCL-2016-PO0422 \n   \n<em>hi</em> bodgan  \n    \nwe urgently need the",
            "Additional XXX License for YYY Servers DCL-2016-PO0422\n \n<em>hi</em> bodgan\n \nwe urgently need the permanent"
          ]
        }
      ]
    }
  ]
}
Disparate answered 14/2, 2017 at 16:45 Comment(0)
D
4

I was using Page<Books> instead of HighlightPage to create the response page. Page obviously doesn't contain content which was causing the highlighted portion to be truncated. I ended up creating a new page based off of HighlightPage and returning that as my result instead of Page.

@RepositoryRestController
@RequestMapping(value = "/booksCustom")
public class BooksController extends ResourceSupport {

    @Autowired
    public BooksService booksService;

    @Autowired
    private PagedResourcesAssembler<Books> booksAssembler;

    @RequestMapping("/search")
    public HttpEntity<PagedResources<Resource<HighlightPage>>> search(@RequestParam(value = "q", required = false) String query, @PageableDefault(page = 0, size = 20) Pageable pageable) {

        HighlightPage solrBookResult = booksService.findBookText(query, pageable);
        Page<Books> highlightedPages = new PageImpl(solrBookResult.getHighlighted(), pageable, solrBookResult.getTotalElements());
        return new ResponseEntity<PagedResources<Resource<HighlightPage>>>(booksAssembler.toResource(highlightedPages), HttpStatus.OK); 
    }

Probably a better way of doing this, but I couldn't find anything that would do what I wanted it to do without having a change a ton of code. Hope this helps!

Disproof answered 13/2, 2017 at 16:37 Comment(3)
Thanks, but thats what probably is not suitable for us. Thanks!Disparate
No problem! Would be curious as to how you solve the problem. Good luck.Disproof
I ve added my solution, maybe it will help you.Disparate

© 2022 - 2024 — McMap. All rights reserved.