Spring Roo
  1. Spring Roo
  2. ROO-2903

Allow GWT Request to directly invoke JPA repository

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 1.2.0.M1
    • Fix Version/s: None
    • Component/s: GWT
    • Labels:
      None

      Description

      Execute the following script:

      project --topLevelPackage com.foo.roo2903
      jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY 
      entity jpa --class ~.server.domain.Thing --activeRecord false
      field string --fieldName name
      repository jpa --interface ~.repository.ThingRepository --entity ~.server.domain.Thing
      
      web gwt setup
      web gwt all --proxyPackage ~.client.proxy --requestPackage ~.client.request

      The resultant app fails to compile, as the generated com.foo.roo2903.client.request.ThingRequest interface does not contain the necessary CRUD methods (in fact, that interface is empty):

      [ERROR] The method findThingEntries(int, int) is undefined for the type ThingRequest
      [ERROR] The method save(ThingProxy) is undefined for the type ThingRequest
      [ERROR] The method save(ThingProxy) is undefined for the type ThingRequest
      [ERROR] The method count() is undefined for the type ThingRequest
      [ERROR] The method delete(ThingProxy) is undefined for the type ThingRequest

        Issue Links

          Activity

          Hide
          Andrew Swan added a comment -

          Fixing this ticket is not just a case of applying normal layer method lookup; we also have to address the discrepancy between how GWT request types are written and how our repositories are generated, namely that:

          1. The GWT request classes are coded in the following style when using a repository:
            @RooGwtRequest(value = "com.example.Thing", exclude = ...)
            @ServiceName(value = "com.example.ThingRepository", locator = ...)
            public interface ThingRequest extends RequestContext {
            
                SomeReturnType someMethod(...);
                ...
            }
          2. This means that GWT will invoke the "someMethod" method on the ThingRepository instance, with the relevant arguments.
          3. However, our Spring Data JPA repositories do not have a "find entries" method like our active record entities do. Instead, the way we find entries using a repository (e.g. from Spring MVC) is via its PageRequest API, as follows:
            int pageNumber = firstResult / maxResults;
            List<Thing> things = thingRepository.findAll(new org.springframework.data.domain.PageRequest(pageNumber, maxResults)).getContent();
          4. The above code snippet with its calculation of the page number and creation of an anonymous PageRequest is obviously not expressible as a method name in a GWT request class.
          5. We therefore need to encapsulate the above code into a new "findEntries" repository method, by:
            • Introducing the "findEntries(int, int)" method declaration into the ThingRepository interface via the existing ThingRepository_Roo_Jpa_Repository ITD,
            • Creating an empty ThingRepositoryImpl.java file, and
            • Creating a ThingRepositoryImpl_Roo_Jpa_Repository ITD (via a new MetadataProvider) that introduces the above implementation code into the ThingRepositoryImpl class file.
          Show
          Andrew Swan added a comment - Fixing this ticket is not just a case of applying normal layer method lookup; we also have to address the discrepancy between how GWT request types are written and how our repositories are generated, namely that: The GWT request classes are coded in the following style when using a repository: @RooGwtRequest(value = "com.example.Thing" , exclude = ...) @ServiceName(value = "com.example.ThingRepository" , locator = ...) public interface ThingRequest extends RequestContext { SomeReturnType someMethod(...); ... } This means that GWT will invoke the "someMethod" method on the ThingRepository instance, with the relevant arguments. However, our Spring Data JPA repositories do not have a "find entries" method like our active record entities do. Instead, the way we find entries using a repository (e.g. from Spring MVC) is via its PageRequest API, as follows: int pageNumber = firstResult / maxResults; List<Thing> things = thingRepository.findAll( new org.springframework.data.domain.PageRequest(pageNumber, maxResults)).getContent(); The above code snippet with its calculation of the page number and creation of an anonymous PageRequest is obviously not expressible as a method name in a GWT request class. We therefore need to encapsulate the above code into a new "findEntries" repository method, by: Introducing the "findEntries(int, int)" method declaration into the ThingRepository interface via the existing ThingRepository_Roo_Jpa_Repository ITD, Creating an empty ThingRepositoryImpl.java file, and Creating a ThingRepositoryImpl_Roo_Jpa_Repository ITD (via a new MetadataProvider) that introduces the above implementation code into the ThingRepositoryImpl class file.
          Hide
          Andrew Swan added a comment -

          The workaround in the meantime is to add a service layer in addition to the repository layer. Roo will detect the new layer and:

          • rewire GWT to invoke it
          • scaffold the service to delegate to the repository
          Show
          Andrew Swan added a comment - The workaround in the meantime is to add a service layer in addition to the repository layer. Roo will detect the new layer and: rewire GWT to invoke it scaffold the service to delegate to the repository
          Hide
          Kay Roesler added a comment -

          Using service layer does not work either, Alan marked my ticket as duplicate to this one. Here again the script showing the broken pagination:

          project --topLevelPackage foo.bar
          jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
          entity jpa --class ~.domain.Entry --testAutomatically
          field string name
          service --interface ~.service.EntryService --entity ~.domain.Entry
          repository jpa --interface ~.repository.EntryRepository --entity ~.domain.Entry
          web gwt setup
          web gwt all --proxyPackage ~.client.proxy --requestPackage ~.client.request

          Show
          Kay Roesler added a comment - Using service layer does not work either, Alan marked my ticket as duplicate to this one. Here again the script showing the broken pagination: project --topLevelPackage foo.bar jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY entity jpa --class ~.domain.Entry --testAutomatically field string name service --interface ~.service.EntryService --entity ~.domain.Entry repository jpa --interface ~.repository.EntryRepository --entity ~.domain.Entry web gwt setup web gwt all --proxyPackage ~.client.proxy --requestPackage ~.client.request

            People

            • Assignee:
              Unassigned
              Reporter:
              Alan Stewart
            • Votes:
              5 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated: