Announcement Announcement Module
Collapse
No announcement yet.
Adding custom behavior to a single repo AND all repos? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Adding custom behavior to a single repo AND all repos?

    Hi all,

    I was reading the reference guide on adding custom behavior, and it is straightforward when it comes to adding custom behavior to all repositories, and it is straightforward when it comes to adding custom behavior to a specific repository. However, I need to do both: add custom behavior to a specific repository that is already receiving global custom behavior.

    Let's say that I've extended JpaRepository with my own interface, call it MyRepo, with a few methods of my own & and an implementation MyRepoImpl, so that all Spring Data repositories get that behavior:
    Code:
    <jpa:repositories base-package="com.foobar.domain" factory-class="com.foobar.springdata.jpa.MyRepoImplFactoryBean"/>
    Now, some of my repositories, on a case-by-case basis, need to have additional custom methods. Let's say FooRepo, managing entities of type Foo, needs a custom-implemented method. Let's say I define an interface FooOps,
    Code:
    public interface FooOps { void doSomethingAbout(Foo foo); }
    and implement this method in a Spring bean class FooOperations. Note that I'm intentionally not using the "Impl" suffix here to force explicit configuration. Let's also say that FooOperations has other dependencies.
    Code:
    public class FooOperations implements FooOps {
      
      protected BarService barService;
    
      public FooOperations(BarService barService) { this.barService = barService; }
    
      public void doSomethingAbout(Foo foo) {
        barService.blip(foo.getBlazzle()); // or whatever...
      }
    }
    How do I configure SD JPA to create a FooRepo and make it get behavior from both MyRepoImpl and FooOperations (a Spring bean with dependencies), but have all my other repositories get behavior just from MyRepoImpl?

    Thanks,
    Matthew

  • #2
    [bump] I'm still wondering how to do this. Anyone out there know how?

    Comment


    • #3
      Have you followed the instructions in the reference documentation? If no, do so? If yes, what exactly does not work? What kind of exception are you seeing?

      At a quick glance the FooOperations class has to be named FooRepoImpl (as outlined in the documentation) to be picked up unless you configure a different repository-impl-postfix in the namespace.

      Comment


      • #4
        Originally posted by Oliver Gierke View Post
        Have you followed the instructions in the reference documentation?
        Of course.
        If no, do so?
        N/A
        If yes, what exactly does not work? What kind of exception are you seeing?
        No exception. Compilation failure. The methods I expect to see on the repo are not there. I'll illustrate by modifying your spring-data-jpa-example project. See attached.
        At a quick glance the FooOperations class has to be named FooRepoImpl (as outlined in the documentation) to be picked up unless you configure a different repository-impl-postfix in the namespace.
        The name FooOperations was intentional because I was asking specifically about the configuration.

        Attached is a modified version of your spring-data-jpa-examples that illustrates the issue that I'm having. Extract it, change to the spring-data-jpa-example directory and run "mvn clean test -Dtest=NewUserRepositorySample". First, you'll see the compilation errors. It wouldn't be a bad idea to do a directory diff against the virgin version of spring-data-jpa-example so you can easily see what I changed.

        Thanks,
        Matthew

        Comment


        • #5
          If you think you have a useful addition to what's already in the examples, please open a ticket in the Github tracker and attach a pull request. From the attached source code only I couldn't quite figure out what you're shooting for. Beyond that it seems the Github issue tracker already contains an issue and a pull request with a customization example.

          I don't think I'll be going down to make your sample compile. That shouldn't be too hard to figure out yourself especially as the reference documentation of the latest release contains a reworked chapter on the customization that should have the code examples straight now.

          Regarding the naming of the types: be sure to read the reference documentation closely. This section [0] explains why it either *has to be* <code>Impl</code> or you have to configure it explicitly on the namespace element.

          Beyond that, let's keep the conversation in the forums. Being pinged on multiple different ways just increases communication complexity and makes it harder to keep track of what's going on. I'll look at the discussions here as time permits, not as I get emails.

          Thanks!

          [0] http://static.springsource.org/sprin...tory-behaviour

          Comment


          • #6
            Originally posted by Oliver Gierke View Post
            If you think you have a useful addition to what's already in the examples, please open a ticket in the Github tracker and attach a pull request.
            Ok, will do.

            I don't think I'll be going down to make your sample compile. That shouldn't be too hard to figure out yourself especially as the reference documentation of the latest release contains a reworked chapter on the customization that should have the code examples straight now.
            Ok, I'll distill it to one question:
            Inside a method of your example's UserRepositoryImpl, how would you get a reference to SD JPA's implementation of UserRepository?

            It's not available from "this", since UserRepositoryImpl doesn't implement UserRepository.

            I think the answer is to inject SD JPA's UserRepository implementation into UserRepositoryImpl like this:
            Code:
            class UserRepositoryImpl implements UserRepositoryCustom {
            
                @PersistenceContext
                private EntityManager em;
            
            
                @Autowired
                private UserRepository delegate; // inject SD JPA's implementation here
                ...
            Then, with a reference to SD JPA's implementation around, you can use it if needed.

            Another option is to declare that my custom repo interface extends the one that SD JPA implements, then define a POJO that implements my custom repo interface. It means that I can avoid using any FactoryBeans at all:
            Code:
            @NoRepositoryBean
            public interface UserRepositoryCustom extends UserRepository {
              List<User> myCustomBatchOperation();
            }
            Code:
            class UserRepositoryImpl implements UserRepositoryCustom {
            
                @PersistenceContext
                private EntityManager em;
            
            
                protected UserRepository delegate;
            
                @Autowired
                public UserRepositoryImpl(UserRepository delegate) {
                  this.delegate = delegate;
                }
            
                public List<User> myCustomBatchOperation() {
            
                    // can use injected UserRepository here if needed
            
            
                    CriteriaQuery<User> criteriaQuery =
                            em.getCriteriaBuilder().createQuery(User.class);
            
            
                    return em.createQuery(criteriaQuery).getResultList();
                }
            
                // implement UserRepository via delegation to injected delegate here...
            }
            Code:
            <jpa:repositories base-package="org.springframework.data.jpa.example.repository" />
            
            <bean id="myCustomUserRepository" class="org.springframework.data.jpa.example.repository.UserRepositoryImpl"/>
            Now I can use myCustomUserRepository anywhere a UserRepository or a UserRepositoryCustom is needed. Thoughts?

            Comment

            Working...
            X