@@ -447,10 +447,14 @@ We might start with something like this, a mix of UI and persistence logic:
447447
448448[source,java]
449449----
450- @Path("/") @Produces("application/json")
450+ @Path("/")
451+ @Produces("application/json")
451452public class BookResource {
452453
453- @GET @Path("book/{isbn}")
454+ private final SessionFactory sessionfactory = .... ;
455+
456+ @GET
457+ @Path("book/{isbn}")
454458 public Book getBook(String isbn) {
455459 var book = sessionFactory.fromTransaction(session -> session.find(Book.class, isbn));
456460 return book == null ? Response.status(404).build() : book;
@@ -473,18 +477,25 @@ Let's now consider a slightly more complicated case.
473477
474478[source,java]
475479----
476- @Path("/") @Produces("application/json")
480+ @Path("/")
481+ @Produces("application/json")
477482public class BookResource {
478483 private static final int RESULTS_PER_PAGE = 20;
479484
480- @GET @Path("books/{titlePattern}/{page:\\d+}")
481- public List<Book> findBooks(String titlePattern, int page) {
482- var books = sessionFactory.fromTransaction(session -> {
483- return session.createSelectionQuery("from Book where title like ?1 order by title", Book.class)
484- .setParameter(1, titlePattern)
485- .setPage(Page.page(RESULTS_PER_PAGE, page))
486- .getResultList();
487- });
485+ private final SessionFactory sessionfactory = .... ;
486+
487+ @GET
488+ @Path("books/{titlePattern}/{pageNumber:\\d+}")
489+ public List<Book> findBooks(String titlePattern, int pageNumber) {
490+ var page = Page.page(RESULTS_PER_PAGE, pageNumber);
491+ var books =
492+ sessionFactory.fromTransaction(session -> {
493+ var findBooksByTitle = "from Book where title like ?1 order by title";
494+ return session.createSelectionQuery(findBooksByTitle, Book.class)
495+ .setParameter(1, titlePattern)
496+ .setPage(page)
497+ .getResultList();
498+ });
488499 return books.isEmpty() ? Response.status(404).build() : books;
489500 }
490501
@@ -498,9 +509,9 @@ Let's hit the code with our favorite thing, the Extract Method refactoring. We o
498509
499510[source,java]
500511----
501- static List<Book> findBooksTitled(Session session,
502- String titlePattern, Page page) {
503- return session.createSelectionQuery("from Book where title like ?1 order by title" , Book.class)
512+ static List<Book> findBooksTitled(Session session, String titlePattern, Page page) {
513+ var findBooksByTitle = "from Book where title like ?1 order by title";
514+ return session.createSelectionQuery(findBooksByTitle , Book.class)
504515 .setParameter(1, titlePattern)
505516 .setPage(page)
506517 .getResultList();
@@ -522,13 +533,13 @@ We need a place to put the annotation, so let's move our query method to a new c
522533 query = "from Book where title like :title order by title")
523534class Queries {
524535
525- static List<Book> findBooksTitled(Session session,
526- String titlePattern, Page page) {
536+ static List<Book> findBooksTitled(Session session, String titlePattern, Page page) {
527537 return session.createQuery(Queries_._findBooksByTitle_) //type safe reference to the named query
528538 .setParameter("title", titlePattern)
529539 .setPage(page)
530540 .getResultList();
531541 }
542+
532543}
533544----
534545
@@ -546,11 +557,13 @@ Whatever the case, the code which orchestrates a unit of work usually just calls
546557[source,java]
547558----
548559@GET
549- @Path("books/{titlePattern}")
550- public List<Book> findBooks(String titlePattern) {
551- var books = sessionFactory.fromTransaction(session ->
552- Queries.findBooksTitled(session, titlePattern,
553- Page.page(RESULTS_PER_PAGE, page)));
560+ @Path("books/{titlePattern}/{pageNumber:\\d+}")
561+ public List<Book> findBooks(String titlePattern, int pageNumber) {
562+ var page = Page.page(RESULTS_PER_PAGE, pageNumber);
563+ var books =
564+ sessionFactory.fromTransaction(session ->
565+ // call handwritten query method
566+ Queries.findBooksTitled(session, titlePattern, page));
554567 return books.isEmpty() ? Response.status(404).build() : books;
555568}
556569----
@@ -567,7 +580,9 @@ Suppose we simplify `Queries` to just the following:
567580
568581[source,java]
569582----
583+ // a sort of proto-repository, this interface is never implemented
570584interface Queries {
585+ // a HQL query method with a generated static "implementation"
571586 @HQL("where title like :title order by title")
572587 List<Book> findBooksTitled(String title, Page page);
573588}
@@ -579,11 +594,13 @@ We can call it just like we were previously calling our handwritten version:
579594[source,java]
580595----
581596@GET
582- @Path("books/{titlePattern}")
583- public List<Book> findBooks(String titlePattern) {
584- var books = sessionFactory.fromTransaction(session ->
585- Queries_.findBooksTitled(session, titlePattern,
586- Page.page(RESULTS_PER_PAGE, page)));
597+ @Path("books/{titlePattern}/{pageNumber:\\d+}")
598+ public List<Book> findBooks(String titlePattern, int pageNumber) {
599+ var page = Page.page(RESULTS_PER_PAGE, pageNumber);
600+ var books =
601+ sessionFactory.fromTransaction(session ->
602+ // call the generated query method "implementation"
603+ Queries_.findBooksTitled(session, titlePattern, page));
587604 return books.isEmpty() ? Response.status(404).build() : books;
588605}
589606----
@@ -592,32 +609,37 @@ In this case, the quantity of code eliminated is pretty trivial.
592609The real value is in improved type safety.
593610We now find out about errors in assignments of arguments to query parameters at compile time.
594611
595- This is all quite nice so far, but at this point you're probably wondering whether we could use dependency injection to obtain an _instance_ of the `Queries` interface.
612+ This is all quite nice so far, but at this point you're probably wondering whether we could use dependency injection to obtain an _instance_ of the `Queries` interface, and have this object take care of obtaining its own `Session` .
596613Well, indeed we can.
597614What we need to do is indicate the kind of session the `Queries` interface depends on, by adding a method to retrieve the session.
615+ Observe, again, that we're _still_ not attempting to hide the `Session` from the client code.
598616
599617[source,java]
600618----
619+ // a true repository interface with generated implementation
601620interface Queries {
602- EntityManager entityManager();
621+ // declare the kind of session backing this repository
622+ Session session();
603623
624+ // a HQL query method with a generated implementation
604625 @HQL("where title like :title order by title")
605626 List<Book> findBooksTitled(String title, Page page);
606627}
607628----
608629
609- The `Queries` interface is now considered a _repository_, and we may use CDI to inject the repository implementation generated by Hibernate Processor:
630+ The `Queries` interface is now considered a _repository_, and we may use CDI to inject the repository implementation generated by Hibernate Processor.
631+ Also, since I guess we're now working in some sort of container environment, we'll let the container manage transactions for us.
610632
611633[source,java]
612634----
613- @Inject Queries queries;
635+ @Inject Queries queries; // inject the repository
614636
615637@GET
616- @Path("books/{titlePattern}")
638+ @Path("books/{titlePattern}/{pageNumber:\\d+} ")
617639@Transactional
618- public List<Book> findBooks(String titlePattern) {
619- var books = queries.findBooksTitled(session, titlePattern,
620- Page.page(RESULTS_PER_PAGE, page));
640+ public List<Book> findBooks(String titlePattern, int pageNumber ) {
641+ var page = Page.page(RESULTS_PER_PAGE, pageNumber);
642+ var books = queries.findBooksTitled(session, titlePattern, page); // call the repository method
621643 return books.isEmpty() ? Response.status(404).build() : books;
622644}
623645----
0 commit comments