Question
What criteria should be used when deciding between:
specifying a dependency with an annotation, and
specifying a dependency with a more specific interface
Example
Suppose I have:
interface FooLoader {
Foo loadById(long id);
}
class DBFooLoader implements FooLoader {
... jdbc etc. etc. ...
}
class CachingFooLoader implements FooLoader {
...
#Inject
public CachingFooLoader(FooLoader delegate) {
this.delegate = delegate;
}
...
}
Suppose I want to bind FooLoader to CachingFooLoader, I have [at least] two ways to wire this:
Use an annotation binding
Change:
public CachingFooLoader(FooLoader delegate)
to:
public CachingFooLoader(#NonCaching FooLoader delegate)
and then:
bind(FooLoader.class).annotatedWith(NonCaching.class).to(DBFooLoader.class);
Create a more specific interface
Change:
public CachingFooLoader(FooLoader delegate)
to:
public CachingFooLoader(NonCachingFooLoader delegate)
where NonCachingFooLoader simply extends FooLoader, and then have DBFooLoader implement NonCachingFooLoader, and wire up accordingly.
My thoughts
I am drawn to using an annotation binding for multiple reasons:
Keys can be more easily reused than interfaces, which decreases the combinatorial explosion that interfaces would suffer from.
It is less invasive: configuration stays in Guice modules, rather than "poisoning" classes.
However, creating a more specific interface has its advantages too:
Interfaces have more meaning. Typically only Guice will read the annotation, where as interfaces are used for much more.
So, what criteria should be used to determine which approach to take?
(Spring users, as far as I can tell, this is what you guys call qualifiers.)
Use specific interfaces only if it makes sense, i.e. they have to offer a different API and thus other classes will use them in a specific way.
If they offer the same "service" in different ways, then use only one common interface and differentiate implementations with annotations.
Related
In my Spring Boot app, I have events that should be reported in various ways, depending on the environment.
I defined interface IReporter and several implementations, namely LogReporter, EmailReporter, RpcReporter. Also new implementations may appear in future.
Now I want my events to be reported using a subset of reporters. The subset must be specified in the app configuration as the following (for example):
events.reporters=LogReporter,EmailReporter
or
events.reporters=${EVENT_REPORTERS}
or something similar.
As a result, I would like the component that handles events (say class EventHandler) to have magically injected List<IReporter> myReporters containing only the necessary implementations.
And, of course, if a new implementation is created, the only thing to update must be the app configuration (not the code of EventHandler).
I'm familiar with injecting all available implementations, only a #Primary implementation, or a specific one picked with #Qualifier. But looks like these do not solve my problem.
class EventHandler {
#Value("${events.reporter}")
List<String> requiredImplementation;
#Autowired
List<IReporter> myReporters;
public List<IReporter> getRequiredImplementation() {
return myReporters.stream()
.filter(reporter -> requiredImplementation.contains(reporter.getClass().getSimpleName()))
.collect(Collectors.toList());
}
}
EDIT:
One option I could think if we want framework to autowire only the required beans, we can explore #ConditionalOnExpression.
For instance:
#Component
#ConditionalOnExpression("#{'${events.reporter}'.contains('LogReporter')}")
Class LogReporter {
}
#Component
#ConditionalOnExpression("#{'${events.reporter}'.contains('EmailReporter')}")
Class EmailReporter {
}
I'm using Spring's CrudRepository in combination with the annotation #RepositoryRestResource to implement a simple CRUD-app that can be used throught a RESTful API. I now want to add an AspectJ pointcut on my repository, so that some functionalities will be executed whenever a CRUD-method from the interface is called.
First, I extend Spring's CrudRepository to add some custom functionalities in my own interface:
#RepositoryRestResource(collectionResourceRel = "customers", path = "customers")
public interface CustomerRestRepository extends CrudRepository<Customer, Integer>{
Customer findOneByGuid(#Param("customerGuid") String customerGuid);
//Other custom methods.
}
Everything is working fine and I'm able to call this method via my REST client. I do not have to implement the interface CustomerRestRepository since Spring is doing the job as a miracle in behind. This is one of the crucial advantages of extending Springs's CrudRepository.
The problem, I'm facing now, is to add an AspectJ pointcut on this custom method findOneByGuid() that will, for example, log every call of the method after it's execution.
What I've tried by so far is:
#Aspect
public aspect AfterCustomerCrudAspect {
#Pointcut(
"execution(* com.x.y.z.CustomerRestRepository.findOneByGuid(..))")
public void customerCrudMethod() {}
#AfterReturning("customerCrudMethod()")
public void doSomething() {
//Do something
}
}
I've also tried:
1) execution(* com.x.y.z.CustomerRestRepository+.findOneByGuid(..))
2) execution(* org.springframework.data.repository.Repository+.*(..))
3) within(com.x.y.z.CustomerRestRepository)
4) annotation(RepositoryRestResource)
...and many others I do not remember. All with the same frustrating result: The advice is never applied.
By the way, I do not face any exceptions and if I try execution(* *.*(..)), the advice is working well - but, of course, not limited to the method findOneByGuid(). Thus, I think my code is correct in general.
I know that it is not possible to set pointcuts on interfaces. But since I do not have to implement the interface CustomerRestRepository by my own to get things working, I need to find a way to set a pointcut on an interface's method - or to find some other solution.
Well, one possible solution to that would be to implement the interface CustomerRestRepository. But then I've to do all the implementation work for the repository by my own and skip using the advantages of Spring's CrudRepository.
Thus, my question is, if there is a possibility to set a AspectJ pointcut on methods in a Spring CrudRepository.
Many thanks in advance for all the answers.
Well, I solved my problem in a different way.
Sometimes, things are less complicated than expected. Adding an AspectJ pointcut on a Spring CRUD-repository to execute some functionalities, whenever an entity is changed was not the best idea. (And at the best of my knowledge, it is not possible at all.)
There is a much more easier way to implement my requirement: The package javax.persistence provides the annotation #EntityListeners that suites perfectly to this job. So, annotate the entity class with the listener and implement the needed functionalities within the listener class:
#Entity
#EntityListeners(CustomerEntityListener.class)
//#Table, #NamedQueries and other stuff ...
public class Customer implements Serializable {
...
}
Implementation of the EntityListener:
public class CustomerEntityListener {
#PostPersist
public void customerPostPersist(Customer customer) {
//Add functionalities
}
}
The EntityListeneralso provides annotation for #PostUpdate, #PostRemove and so on - visit this site for more information.
I was just starting a new coding project. I may be ahead of myself, but I've gotten kinda stuck. I wanted to implement an Abstract Factory for the GUI, similar to the example on Wikipedia. However various systems have their own parameters for creating windows. At present I have come up with the following solutions to my dilemma:
Create a type which varies based on compiler directives
Don't use compiler directives and just put everything in a type that contains every possible data member
Create a polymorphic hierarchy and use dynamic casting inside each window function
Use some sort of intermediate singleton that holds the information. This seems esp. unhelpful and would likely also involve casting.
Use a different pattern, such as builder instead.
My objective is to create high level interfaces that are uniform, so that creating a window, etc. is the same for all platforms.
I hesitate to do #5 simply because it seems like this would be a common enough problem that there should already be a solution. This is just a toy, so it's more about learning than building a practical application. I know I could use existing code bases, but that wouldn't achieve my real objective.
Thanks in advance.
I think, it depends on the situation. But how about using abstract factory with builder (inside factory) and decorator with some default values for GUI componets, where decorator will have same interface for similar components from different GUI libraries and extends class from GUI library.
After reading more I've realized I can use Dependency Injection to create the concrete factory first. Since entry point knows what kind of factory it's using, that can be passed to the client. I can't believe I didn't see it before, but I don't think that Dependency Injection "clicked" until now.
I would put the system-specific parameters in the constructor for each abstract factory.
public interface WindowFactory {
public Window build();
}
public class WindowsWindowFactory implements WindowFactory {
private param1, param2, param3;
public WindowsWindowFactory(param1,param2,param3) {} // set params
public Window build() {} // use params
}
public class LinuxWindowFactory implements WindowFactory {
private param1, param2;
public LinuxWindowFactory(param1,param2) {} // set params
public Window build() {} // use params
}
I found out that there is an interface called GraphRepository. I have a repository for users implementing a homemade interface that does its job, but I was wondering, shouldn't I implement GraphRepository instead ? Even if it will be quite long to implement and some methods will be useless, I think it is a standard and I already re-coded a lot of methods that are defined in this interface.
So should I write "YAGNI" code or not respect the standard ?
What is your advice ?
you don't need to actually implement GraphRepository but extend it. the principals of Spring-Data is that all the boiler-plate CRUD code is taken care of (by proxying at startup time) so all you have to do is create an interface for your specific entity extending GraphRepository and then add only specific methods that you require.
for example; if i have an entity CustomerNode, to create standard CRUD methods, i can create a new interface CustomerNodeRepository extends GraphRepository<CustomerNode,Long>. all the methods from GraphRepository (e.g. save, findAll, findOne, delete, deleteAll, etc.) are now accessible from CustomerNodeRepository and implemented by Spring-Data-Neo4J without having to write a single line of implementation code.
the pattern now allows you to work on your specific repository code (e.g. findByNameAndDateOfBirth) rather than the simple CRUD stuff.
Spring-Data package is very useful for repository interaction. it can reduce huge amounts of code (have seen 80%+ reduction in code lines) and would highly recommend using it
edit: implementing custom execution
if you want to add your own custom behavior to a Repository method, you create the concept of merging interfaces and custom implementation. for example, lets say i want to create a method called findCustomerNodeBySomeStrangeCriteria and to do this, i actually want to link off to a relational database to perform the function.
first we define a separate, standalone interface that only includes our 'extra' method.
public interface CustomCustomerNodeRepository {
List<CustomerNode> findCustomerNodeBySomeStrangeCriteria(Object strangeCriteria);
}
next we update our normal interface to extend not only GraphRepository, but our new custom one too
public interface CustomerNodeRepository extends GraphRepository<CustomerNode,Long>, CustomCustomerNodeRepository {
}
the last piece, is to actually implement our findCustomerNodeBySomeStrangeCriteria method
public class CustomerNodeRepositoryImpl implements CustomCustomerNodeRepository {
public List<CustomerNode> findCustomerNodeBySomeStrangeCriteria(Object criteria) {
//implementation code
}
}
so, there's a couple of points to note;
we create a separate interface to define any custom methods that have custom implementations (as distinct from Spring-Data compatible "findBy..." methods)
our CustomerNodeRepository interface (our 'main' interface) extends both the GraphRepository and our 'custom' one
we implement only the 'custom' method in a class that implements only the custom interface
the 'custom' implementation class must (by default) be called our 'main' interface Impl to be picked up by Spring Data (so in this case CustomNodeRepositoryImpl)
under the covers, Spring Data delivers a proxy implementation of CustomerNodeRepository as a merge of the auto-built GraphRepository and our class implementing CustomCustomerNodeRepository. the reason for the name of the class is to allow Spring Data to pick it up easily/successfully (this can be overwritten so it doesn't look for *Impl)
I don't know so much about DDD repository pattern but the implementation in Spring is confusion me.
public interface PersonRepository extends JpaRepository<Person, Long> { … }
As the interface extends JpaRepository (or MongoDBRepository...), if you change from one db to another, you have to change the interface as well.
For me an interface is there to provide some abstraction, but here it's not so much abstract...
Do you know why Spring-Data works like that?
You are right, an Interface is an abstraction about something that works equals for all implementing classes, from an outside point of view.
And that is exactly what happens here:
JpaRepository is a common view of all your JPA Repositories (for all the different Entities), while MongoDBRepository is the same for all MongoDB Entities.
But JpaRepository and MongoDBRepository have nothing in common, except the stuff that is defined in there common super Interfaces:
org.springframework.data.repository.PagingAndSortingRepository
org.springframework.data.repository.Repository
So for me it looks normal.
If you use the classes that implement your Repository then use PagingAndSortingRepository or Repository if you want to be able to switch from an JPA implementation to an Document based implementation (sorry but I can not imagine such a use case - anyway). And of course your Repository implementation should implement the correct interface (JpaRepository, MongoDBRepository) depending on what it is.
The reasoning behind this is pretty clearly stated in this blog post http://blog.springsource.com/2011/02/10/getting-started-with-spring-data-jpa/.
Defining this interface serves two purposes: First, by extending JpaRepository we get a bunch of generic CRUD methods into our type that allows saving Accounts, deleting them and so on. Second, this will allow the Spring Data JPA repository infrastructure to scan the classpath for this interface and create a Spring bean for it.
If you do not trust sources so close to the source (pun intended) it might be a good idea to read this post as well http://www.brucephillips.name/blog/index.cfm/2011/3/25/Using-Spring-Data-JPA-To-Reduced-Data-Access-Coding.
What I did not need to code is an implementation of the PersonRepository interface. Spring will create an implementation of this interface and make a PersonRepository bean available to be autowired into my Service class. The PersonRepository bean will have all the standard CRUD methods (which will be transactional) and return Person objects or collection of Person objects. So by using Spring Data JPA, I've saved writing my own implementation class.
Until M2 of Spring Data we required users to extend JpaRepository due to the following reasons:
The classpath scanning infrastructure only picked up interfaces extending that interface as one might use Spring Data JPA and Spring Data Mongo in parallel and have both of them pointed to the very same package it would not be clear which store to create the proxy for. However since RC1 we simply leave that burden to the developer as we think it's a rather exotic case and the benefit of just using Repository, CrudRepository or the like outweights the effort you have to take in the just described corner case. You can use exclude and include elements in the namespace to gain finer-grained control over this.
Until M2 we had transactionality applied to the CRUD methods by redeclaring the CRUD methods and annotating them with #Transactional. This decision in turn was driven by the algorithm AnnotationTransactionAttributeSource uses to find transaction configuration. As we wanted to provide the user with the possibility to reconfigure transactions by just redeclaring a CRUD method in the concrete repository interface and applying #Transactional on it. For RC1 we decided to implement a custom TransactionAttributeSource to be able to move the annotations back to the repository CRUD implementation.
Long story short, here's what it boils down to:
As of RC1 there's no need to extend the store specific repository interface anymore, except you want to…
Use List-based access to findAll(…) instead of the Iterable-based one in the more core repository interfaces (allthough you could simply redeclare the relevant methods in a common base interface to return Lists as well)
You want to make use of the JPA-specific methods like saveAndFlush(…) and so on.
Generally you are much more flexible regarding the exposure of CRUD methods since RC1 as you can even only extend the Repository marker interface and selectively add the CRUD methods you want to expose. As the backing implementation will still implement all of the methods of PagingAndSortingRepository we can still route the calls to the instance:
public interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
List<T> findAll();
T findOne(ID id);
}
public interface UserRepository extends MyBaseRepository<User, Long> {
List<T> findByUsername(String username);
}
In that example we define MyBaseRepository to only expose findAll() and findOne(…) (which will be routed into the instance implementing the CRUD methods) and the concrete repository adding a finder method to the two CRUD ones.
For more details on that topic please consult the reference documentation.