Using generics in Spring Data JPA repositories












22















I have a number of simple object types that need to be persisted to a database. I am using Spring JPA to manage this persistence. For each object type I need to build the following:



import org.springframework.data.jpa.repository.JpaRepository;

public interface FacilityRepository extends JpaRepository<Facility, Long> {
}


public interface FacilityService {
public Facility create(Facility facility);
}

@Service
public class FacilityServiceImpl implements FacilityService {

@Resource
private FacilityRepository countryRepository;

@Transactional
public Facility create(Facility facility) {
Facility created = facility;
return facilityRepository.save(created);
}
}


It occurred to me that it may be possible to replace the multiple classes for each object type with three generics based classes, thus saving a lot of boilerplate coding. I am not exactly sure how to go about it and in fact if it is a good idea?










share|improve this question





























    22















    I have a number of simple object types that need to be persisted to a database. I am using Spring JPA to manage this persistence. For each object type I need to build the following:



    import org.springframework.data.jpa.repository.JpaRepository;

    public interface FacilityRepository extends JpaRepository<Facility, Long> {
    }


    public interface FacilityService {
    public Facility create(Facility facility);
    }

    @Service
    public class FacilityServiceImpl implements FacilityService {

    @Resource
    private FacilityRepository countryRepository;

    @Transactional
    public Facility create(Facility facility) {
    Facility created = facility;
    return facilityRepository.save(created);
    }
    }


    It occurred to me that it may be possible to replace the multiple classes for each object type with three generics based classes, thus saving a lot of boilerplate coding. I am not exactly sure how to go about it and in fact if it is a good idea?










    share|improve this question



























      22












      22








      22


      10






      I have a number of simple object types that need to be persisted to a database. I am using Spring JPA to manage this persistence. For each object type I need to build the following:



      import org.springframework.data.jpa.repository.JpaRepository;

      public interface FacilityRepository extends JpaRepository<Facility, Long> {
      }


      public interface FacilityService {
      public Facility create(Facility facility);
      }

      @Service
      public class FacilityServiceImpl implements FacilityService {

      @Resource
      private FacilityRepository countryRepository;

      @Transactional
      public Facility create(Facility facility) {
      Facility created = facility;
      return facilityRepository.save(created);
      }
      }


      It occurred to me that it may be possible to replace the multiple classes for each object type with three generics based classes, thus saving a lot of boilerplate coding. I am not exactly sure how to go about it and in fact if it is a good idea?










      share|improve this question
















      I have a number of simple object types that need to be persisted to a database. I am using Spring JPA to manage this persistence. For each object type I need to build the following:



      import org.springframework.data.jpa.repository.JpaRepository;

      public interface FacilityRepository extends JpaRepository<Facility, Long> {
      }


      public interface FacilityService {
      public Facility create(Facility facility);
      }

      @Service
      public class FacilityServiceImpl implements FacilityService {

      @Resource
      private FacilityRepository countryRepository;

      @Transactional
      public Facility create(Facility facility) {
      Facility created = facility;
      return facilityRepository.save(created);
      }
      }


      It occurred to me that it may be possible to replace the multiple classes for each object type with three generics based classes, thus saving a lot of boilerplate coding. I am not exactly sure how to go about it and in fact if it is a good idea?







      java spring jpa spring-data spring-data-jpa






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Sep 2 '15 at 12:34









      Oliver Drotbohm

      55.5k10170171




      55.5k10170171










      asked Oct 17 '13 at 3:20









      skymanskyman

      1,00521640




      1,00521640
























          1 Answer
          1






          active

          oldest

          votes


















          60














          First of all, I know we're raising the bar here quite a bit but this is already tremendously less code than you had to write without the help of Spring Data JPA.



          Second, I think you don't need the service class in the first place, if all you do is forward a call to the repository. We recommend using services in front of the repositories if you have business logic that needs orchestration of different repositories within a transaction or has other business logic to encapsulate.



          Generally speaking, you can of course do something like this:



          interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

          @Query("select p from #{#entityName} p where ?1 member of p.categories")
          Iterable<T> findByCategory(String category);

          Iterable<T> findByName(String name);
          }


          This will allow you to use the repository on the client side like this:



          class MyClient {

          @Autowired
          public MyClient(ProductRepository<Car> carRepository,
          ProductRepository<Wine> wineRepository) { … }
          }


          and it will work as expected. However there are a few things to notice:



          This only works if the domain classes use single table inheritance. The only information about the domain class we can get at bootstrap time is that it will be Product objects. So for methods like findAll() and even findByName(…) the relevant queries will start with select p from Product p where…. This is due to the fact that the reflection lookup will never ever be able to produce Wine or Car unless you create a dedicated repository interface for it to capture the concrete type information.



          Generally speaking, we recommend creating repository interfaces per aggregate root. This means you don't have a repo for every domain class per se. Even more important, a 1:1 abstraction of a service over a repository is completely missing the point as well. If you build services, you don't build one for every repository (a monkey could do that, and we're no monkeys, are we? ;). A service is exposing a higher level API, is much more use-case drive and usually orchestrates calls to multiple repositories.



          Also, if you build services on top of repositories, you usually want to enforce the clients to use the service instead of the repository (a classical example here is that a service for user management also triggers password generation and encryption, so that by no means it would be a good idea to let developers use the repository directly as they'd effectively work around the encryption). So you usually want to be selective about who can persist which domain objects to not create dependencies all over the place.



          Summary



          Yes, you can build generic repositories and use them with multiple domain types but there are quite strict technical limitations. Still, from an architectural point of view, the scenario you describe above should even pop up as this means you're facing a design smell anyway.






          share|improve this answer





















          • 4





            This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

            – Willie Wheeler
            Oct 18 '13 at 6:43






          • 1





            Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

            – Oliver Drotbohm
            Oct 18 '13 at 6:48






          • 1





            I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

            – Eddie B
            Jan 12 '14 at 14:50











          • @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

            – agpt
            May 6 '14 at 11:59













          • That's a new question, not a comment, isn't it?

            – Oliver Drotbohm
            May 7 '14 at 11:57











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19417670%2fusing-generics-in-spring-data-jpa-repositories%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          60














          First of all, I know we're raising the bar here quite a bit but this is already tremendously less code than you had to write without the help of Spring Data JPA.



          Second, I think you don't need the service class in the first place, if all you do is forward a call to the repository. We recommend using services in front of the repositories if you have business logic that needs orchestration of different repositories within a transaction or has other business logic to encapsulate.



          Generally speaking, you can of course do something like this:



          interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

          @Query("select p from #{#entityName} p where ?1 member of p.categories")
          Iterable<T> findByCategory(String category);

          Iterable<T> findByName(String name);
          }


          This will allow you to use the repository on the client side like this:



          class MyClient {

          @Autowired
          public MyClient(ProductRepository<Car> carRepository,
          ProductRepository<Wine> wineRepository) { … }
          }


          and it will work as expected. However there are a few things to notice:



          This only works if the domain classes use single table inheritance. The only information about the domain class we can get at bootstrap time is that it will be Product objects. So for methods like findAll() and even findByName(…) the relevant queries will start with select p from Product p where…. This is due to the fact that the reflection lookup will never ever be able to produce Wine or Car unless you create a dedicated repository interface for it to capture the concrete type information.



          Generally speaking, we recommend creating repository interfaces per aggregate root. This means you don't have a repo for every domain class per se. Even more important, a 1:1 abstraction of a service over a repository is completely missing the point as well. If you build services, you don't build one for every repository (a monkey could do that, and we're no monkeys, are we? ;). A service is exposing a higher level API, is much more use-case drive and usually orchestrates calls to multiple repositories.



          Also, if you build services on top of repositories, you usually want to enforce the clients to use the service instead of the repository (a classical example here is that a service for user management also triggers password generation and encryption, so that by no means it would be a good idea to let developers use the repository directly as they'd effectively work around the encryption). So you usually want to be selective about who can persist which domain objects to not create dependencies all over the place.



          Summary



          Yes, you can build generic repositories and use them with multiple domain types but there are quite strict technical limitations. Still, from an architectural point of view, the scenario you describe above should even pop up as this means you're facing a design smell anyway.






          share|improve this answer





















          • 4





            This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

            – Willie Wheeler
            Oct 18 '13 at 6:43






          • 1





            Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

            – Oliver Drotbohm
            Oct 18 '13 at 6:48






          • 1





            I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

            – Eddie B
            Jan 12 '14 at 14:50











          • @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

            – agpt
            May 6 '14 at 11:59













          • That's a new question, not a comment, isn't it?

            – Oliver Drotbohm
            May 7 '14 at 11:57
















          60














          First of all, I know we're raising the bar here quite a bit but this is already tremendously less code than you had to write without the help of Spring Data JPA.



          Second, I think you don't need the service class in the first place, if all you do is forward a call to the repository. We recommend using services in front of the repositories if you have business logic that needs orchestration of different repositories within a transaction or has other business logic to encapsulate.



          Generally speaking, you can of course do something like this:



          interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

          @Query("select p from #{#entityName} p where ?1 member of p.categories")
          Iterable<T> findByCategory(String category);

          Iterable<T> findByName(String name);
          }


          This will allow you to use the repository on the client side like this:



          class MyClient {

          @Autowired
          public MyClient(ProductRepository<Car> carRepository,
          ProductRepository<Wine> wineRepository) { … }
          }


          and it will work as expected. However there are a few things to notice:



          This only works if the domain classes use single table inheritance. The only information about the domain class we can get at bootstrap time is that it will be Product objects. So for methods like findAll() and even findByName(…) the relevant queries will start with select p from Product p where…. This is due to the fact that the reflection lookup will never ever be able to produce Wine or Car unless you create a dedicated repository interface for it to capture the concrete type information.



          Generally speaking, we recommend creating repository interfaces per aggregate root. This means you don't have a repo for every domain class per se. Even more important, a 1:1 abstraction of a service over a repository is completely missing the point as well. If you build services, you don't build one for every repository (a monkey could do that, and we're no monkeys, are we? ;). A service is exposing a higher level API, is much more use-case drive and usually orchestrates calls to multiple repositories.



          Also, if you build services on top of repositories, you usually want to enforce the clients to use the service instead of the repository (a classical example here is that a service for user management also triggers password generation and encryption, so that by no means it would be a good idea to let developers use the repository directly as they'd effectively work around the encryption). So you usually want to be selective about who can persist which domain objects to not create dependencies all over the place.



          Summary



          Yes, you can build generic repositories and use them with multiple domain types but there are quite strict technical limitations. Still, from an architectural point of view, the scenario you describe above should even pop up as this means you're facing a design smell anyway.






          share|improve this answer





















          • 4





            This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

            – Willie Wheeler
            Oct 18 '13 at 6:43






          • 1





            Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

            – Oliver Drotbohm
            Oct 18 '13 at 6:48






          • 1





            I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

            – Eddie B
            Jan 12 '14 at 14:50











          • @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

            – agpt
            May 6 '14 at 11:59













          • That's a new question, not a comment, isn't it?

            – Oliver Drotbohm
            May 7 '14 at 11:57














          60












          60








          60







          First of all, I know we're raising the bar here quite a bit but this is already tremendously less code than you had to write without the help of Spring Data JPA.



          Second, I think you don't need the service class in the first place, if all you do is forward a call to the repository. We recommend using services in front of the repositories if you have business logic that needs orchestration of different repositories within a transaction or has other business logic to encapsulate.



          Generally speaking, you can of course do something like this:



          interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

          @Query("select p from #{#entityName} p where ?1 member of p.categories")
          Iterable<T> findByCategory(String category);

          Iterable<T> findByName(String name);
          }


          This will allow you to use the repository on the client side like this:



          class MyClient {

          @Autowired
          public MyClient(ProductRepository<Car> carRepository,
          ProductRepository<Wine> wineRepository) { … }
          }


          and it will work as expected. However there are a few things to notice:



          This only works if the domain classes use single table inheritance. The only information about the domain class we can get at bootstrap time is that it will be Product objects. So for methods like findAll() and even findByName(…) the relevant queries will start with select p from Product p where…. This is due to the fact that the reflection lookup will never ever be able to produce Wine or Car unless you create a dedicated repository interface for it to capture the concrete type information.



          Generally speaking, we recommend creating repository interfaces per aggregate root. This means you don't have a repo for every domain class per se. Even more important, a 1:1 abstraction of a service over a repository is completely missing the point as well. If you build services, you don't build one for every repository (a monkey could do that, and we're no monkeys, are we? ;). A service is exposing a higher level API, is much more use-case drive and usually orchestrates calls to multiple repositories.



          Also, if you build services on top of repositories, you usually want to enforce the clients to use the service instead of the repository (a classical example here is that a service for user management also triggers password generation and encryption, so that by no means it would be a good idea to let developers use the repository directly as they'd effectively work around the encryption). So you usually want to be selective about who can persist which domain objects to not create dependencies all over the place.



          Summary



          Yes, you can build generic repositories and use them with multiple domain types but there are quite strict technical limitations. Still, from an architectural point of view, the scenario you describe above should even pop up as this means you're facing a design smell anyway.






          share|improve this answer















          First of all, I know we're raising the bar here quite a bit but this is already tremendously less code than you had to write without the help of Spring Data JPA.



          Second, I think you don't need the service class in the first place, if all you do is forward a call to the repository. We recommend using services in front of the repositories if you have business logic that needs orchestration of different repositories within a transaction or has other business logic to encapsulate.



          Generally speaking, you can of course do something like this:



          interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

          @Query("select p from #{#entityName} p where ?1 member of p.categories")
          Iterable<T> findByCategory(String category);

          Iterable<T> findByName(String name);
          }


          This will allow you to use the repository on the client side like this:



          class MyClient {

          @Autowired
          public MyClient(ProductRepository<Car> carRepository,
          ProductRepository<Wine> wineRepository) { … }
          }


          and it will work as expected. However there are a few things to notice:



          This only works if the domain classes use single table inheritance. The only information about the domain class we can get at bootstrap time is that it will be Product objects. So for methods like findAll() and even findByName(…) the relevant queries will start with select p from Product p where…. This is due to the fact that the reflection lookup will never ever be able to produce Wine or Car unless you create a dedicated repository interface for it to capture the concrete type information.



          Generally speaking, we recommend creating repository interfaces per aggregate root. This means you don't have a repo for every domain class per se. Even more important, a 1:1 abstraction of a service over a repository is completely missing the point as well. If you build services, you don't build one for every repository (a monkey could do that, and we're no monkeys, are we? ;). A service is exposing a higher level API, is much more use-case drive and usually orchestrates calls to multiple repositories.



          Also, if you build services on top of repositories, you usually want to enforce the clients to use the service instead of the repository (a classical example here is that a service for user management also triggers password generation and encryption, so that by no means it would be a good idea to let developers use the repository directly as they'd effectively work around the encryption). So you usually want to be selective about who can persist which domain objects to not create dependencies all over the place.



          Summary



          Yes, you can build generic repositories and use them with multiple domain types but there are quite strict technical limitations. Still, from an architectural point of view, the scenario you describe above should even pop up as this means you're facing a design smell anyway.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 5 '16 at 12:44









          Mubin

          3,02011334




          3,02011334










          answered Oct 18 '13 at 6:30









          Oliver DrotbohmOliver Drotbohm

          55.5k10170171




          55.5k10170171








          • 4





            This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

            – Willie Wheeler
            Oct 18 '13 at 6:43






          • 1





            Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

            – Oliver Drotbohm
            Oct 18 '13 at 6:48






          • 1





            I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

            – Eddie B
            Jan 12 '14 at 14:50











          • @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

            – agpt
            May 6 '14 at 11:59













          • That's a new question, not a comment, isn't it?

            – Oliver Drotbohm
            May 7 '14 at 11:57














          • 4





            This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

            – Willie Wheeler
            Oct 18 '13 at 6:43






          • 1





            Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

            – Oliver Drotbohm
            Oct 18 '13 at 6:48






          • 1





            I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

            – Eddie B
            Jan 12 '14 at 14:50











          • @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

            – agpt
            May 6 '14 at 11:59













          • That's a new question, not a comment, isn't it?

            – Oliver Drotbohm
            May 7 '14 at 11:57








          4




          4





          This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

          – Willie Wheeler
          Oct 18 '13 at 6:43





          This is really useful information. It would be great to include this kind of higher-level design guidance in the actual reference materials if it's not already there. Like "best practices" callouts or something.

          – Willie Wheeler
          Oct 18 '13 at 6:43




          1




          1





          Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

          – Oliver Drotbohm
          Oct 18 '13 at 6:48





          Well, this is software architecture and design 1:1. If we included such stuff in the reference documentation, where should we stop then? ;)

          – Oliver Drotbohm
          Oct 18 '13 at 6:48




          1




          1





          I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

          – Eddie B
          Jan 12 '14 at 14:50





          I'm facing this very scenario in the design of an application now... providing a 'dto' and a 'repo' for each model... It doesn't smell right.

          – Eddie B
          Jan 12 '14 at 14:50













          @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

          – agpt
          May 6 '14 at 11:59







          @OliverGierke When I am trying to expose my SD Neo4j repository using Spring Data REST where my neo4j repository is exactly the same as above, its not generating _embedded field and throwing 500 error... else repository with proper Domain class is working fine.. any workout there ?

          – agpt
          May 6 '14 at 11:59















          That's a new question, not a comment, isn't it?

          – Oliver Drotbohm
          May 7 '14 at 11:57





          That's a new question, not a comment, isn't it?

          – Oliver Drotbohm
          May 7 '14 at 11:57


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19417670%2fusing-generics-in-spring-data-jpa-repositories%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          TypeError: fit_transform() missing 1 required positional argument: 'X'