Tuesday, March 3, 2015

Using Spring boot and returning paged JSON DTO list

I currently work on a REST application, for collecting and providing agregated datas.

The REST way (relying on Spring JPA and hateoas technical stack), was chosen because it fit well for many data provider.
But for a few datas this approach does not fit.

In fact most of datas published in a REST fashion have their own dedicated @Repository and @Entity
  • the collected data 
  • the calculated data
But monitoring datas which are volatile data view, should be expose too and those one :
  • Does not have @Repository
  • Does not have @Entity
  • Comes from @Query using Join and returning DTO
  • Should be provided as paged resource.
For those one standard REST  @RepositoryRestResource does not fit.

To acheive this goal  :

first produce your DTO and build the query :

@Query("SELECT new dataKeeper.pojo.datadirectory.DTOKeeperData(art, data)"
  + " FROM KeeperDataDirectory AS data INNER JOIN  data.artifact AS art " )
 List<DTOKeeperData> findKeeperDataDirectoryArtifact();

Then we want paging for our data so :
  • add to Query the parameter "countQuery",
  • add Pageable parameter  to interface method
  • and return Page instead of List

@Query(value = "SELECT new dataKeeper.pojo.datadirectory.DTOKeeperData"
  + " (art, data) "
  + " FROM KeeperDataDirectory AS data INNER JOIN  data.artifact AS art ",
  countQuery="SELECT count(data) FROM KeeperDataDirectory AS data INNER JOIN"
  + "  data.artifact AS art ")
 Page<DTOKeeperData> findAllDataDir(Pageable pageable );



At this point, this method does not work from a REST client. The error is :
{
  "cause": null,
  "message": "Cannot create self link for class dataKeeper.pojo.datadirectory.DTOKeeperData!
     No persistent entity found!"
}
And it's true... the DTO has no Entity... As I define this method in a @RepositoryRestResource spring wait for an entity. Another point, this request is declared by Spring hateoas.... So I create a new Class extending Repository and put the query in it and then create (or use) a Controller (@Controller). This controller
  • define (in our case) the page size
  • handle our request for data on a specific url containing the page number we want to load.

@Controller
public class KeeperDataController {
    private static final int PAGE_SIZE = 30;
    static Logger logger = Logger.getLogger(KeeperDataController.class);

    @Autowired
    KeeperDataDirectoryRepository sddr;
  
    @RequestMapping(value = "keeperdatadir/dto/all/{pageNumber}", method = RequestMethod.GET)
    public @ResponseBody Page<DTOKeeperData> getDto(@PathVariable Integer pageNumber){
        Pageable pageable = new PageRequest (pageNumber - 1, PAGE_SIZE);
        Page<DTOKeeperData> dtos = sddr.findAllDataDir(pageable);
    return dtos;
  }
}

When returning Page you will have access to Total page, number of element and a list of DTO element.

No comments:

Post a Comment