Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Spring Data JPA, custom methods and inheritance

  1. #1
    Join Date
    May 2011
    Posts
    5

    Question Spring Data JPA, custom methods and inheritance

    I wanted to have some a DAO (MyDAO) extending a base DAO interface (BaseDAO). When using Spring Data JPA (1.0.0M2 or the last nightly build) to implement the DAO, I get the following error:

    Code:
    You have custom methods in interface test.MyDAO but not provided a custom implementation!
    I can workaround this by overriding the method in MyDAO but this is not really nice as it'll require to redefine the methods from BaseDAO in all actual DAOs.

    Is there anyway to force SDJ not to consider my base methods as regular methods, not custom ones?
    Last edited by gabuzo; May 12th, 2011 at 03:55 AM.

  2. #2
    Join Date
    Apr 2011
    Posts
    107

    Default

    You can extend your SDJ DAO with some method.
    Read the "1.4. Custom implementations" section of the reference documentation http://static.springsource.org/sprin...eference/html/

    If you have a problem, paste exemple code so that we can help more efficiently.

  3. #3
    Join Date
    May 2011
    Posts
    5

    Question My issue, with code crumbs ...

    I read the section on custom implementation and my issue is that this customization detection is intrusive.

    Entity:

    Code:
    @Entity
    @NamedQueries({ @NamedQuery(name = "MyEntity.findAllIds", query = "select id from MyEntity") })
    public class MyEntity {
        
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        
        public Long getId() {
            return id;
        }
    }
    The DAO (first version):

    Code:
    public interface MyDAO
        extends JpaRepository<MyEntity, Long> {
        Set<Long> findAllIds();
    }
    In this configuration everything is working fine (at least from the nightly build) thanks to the named query in the entity.

    Now I want to make MyDAO a child of the following interface:
    Code:
    @NoRepositoryBean
    public interface BaseDAO {
        Set<Long> findAllIds();
    }
    So I change MyDAO to the following form:
    Code:
    public interface MyDAO
        extends BaseDAO, JpaRepository<MyEntity, Long> {
    }
    I commented removed the findAllIds method as it is already defined in BaseDAO.

    In this case I get the following error at runtime:
    Code:
    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDAO': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: You have custom methods in interface test.MyDAO but not provided a custom implementation!
        [snip]
    Caused by: java.lang.IllegalArgumentException: You have custom methods in interface test.MyDAO but not provided a custom implementation!
    	at org.springframework.data.repository.support.RepositoryFactorySupport.validate(RepositoryFactorySupport.java:226)
    	at org.springframework.data.repository.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:130)
    	at org.springframework.data.repository.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:107)
    	at org.springframework.data.repository.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:36)
    	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    	... 9 more
    Of course I can workaround this by keeping the findAllIds declaration in both BaseDAO and MyDAO but this is definitely redundant and error prone.

  4. #4
    Join Date
    Apr 2011
    Posts
    107

    Default

    Have you defined a class 'MyDaoImpl that implements BaseDAO' in the same package as MyDao ?
    Did you scan/add this bean into spring configuration?

  5. #5
    Join Date
    May 2011
    Posts
    5

    Default

    Quote Originally Posted by gwa View Post
    Have you defined a class 'MyDaoImpl that implements BaseDAO' in the same package as MyDao ?
    Did you scan/add this bean into spring configuration?
    No I didn't but that's my point, the standard implementation fits me so I don't want to be forced to define a custom implementation.

  6. #6
    Join Date
    Apr 2011
    Posts
    107

    Default

    So you want to declare a method in BaseDAO which not extends JpaRepository and that this method will be generated automatically by spring data jpa...

  7. #7
    Join Date
    May 2011
    Posts
    5

    Default

    Quote Originally Posted by gwa View Post
    So you want to declare a method in BaseDAO which not extends JpaRepository and that this method will be generated automatically by spring data jpa...
    It's OK for me to have BaseDAO extend JpaRepository (probably better actually) but it does not change anything. I get the same error after changing BaseDAO to:

    Code:
    @NoRepositoryBean
    public interface BaseDAO
        extends JpaRepository<MyEntity, Long> {
        Set<Long> findAllIds();
    }

  8. #8
    Join Date
    Apr 2006
    Location
    Dresden, Germany
    Posts
    483

    Default

    Adding functionality to all repository proxies requires some more effort. It's documented in detail here: http://static.springsource.org/sprin...l-repositories

  9. #9
    Join Date
    May 2011
    Posts
    5

    Post

    Quote Originally Posted by Oliver Gierke View Post
    Adding functionality to all repository proxies requires some more effort. It's documented in detail here: http://static.springsource.org/sprin...l-repositories
    Yup but I don't want to create any custom implementation. The default implementation through the use of named queries fits me really fine. I just want to find a way to make Spring-Data-JPA create the normal implementation even if the method is defined only in the parent class.

  10. #10
    Join Date
    May 2011
    Posts
    16

    Default

    I am with gabuzo. I understand the steps required to implement a common method by creating an interface with a common method, then implementation and finally configuring the repository factory to create an instance of the the custom implementation containing the common method. The question that remains is what if the custom method is a finder that is normally automatically implemented for me?

    In other words, instead of having T findByXX<String s) in every one of my repository interfaces, I want to move this finder to the base interface, but still have the standard repository behavior implementing the findByXX for me automagically.

    I want to go from this:
    Code:
    @Repository("brandRepository")
    @Transactional
    public interface BrandRepository extends JpaRepository<Brand, Long> {
      @Transactional
      public Brand findByCode(String code);
    }
    to this:
    Code:
    @Repository("brandRepository")
    @Transactional
    public interface BrandRepository extends BaseRepository<Brand> {
    }
    where BaseRepository looks like this:

    Code:
    @Transactional
    public interface BaseRepository<T extends BaseModel> extends JpaRepository<T, Long> {
      @Transactional
      public T findByCode(String code);
    }
    Can I still somehow use the automatic finder generation to implement findByCode, or do I have to write my own QUERY implementation?

    Thanks.
    -AP_

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •