Bijection is said to be one of the most powerful and compelling features of Seam. But with great power often comes great confusion.
Bijection: dependency injection expanded
Nowadays, the subject of dependency injection (DI) is kind of hot in the world of developing. It is a design pattern which provides a mechanism to inject objects into a class, rather than relying on the class itself to create the object. Being so, the object is loosely coupled from the rest of the application and eliminates lookup logic within the class. Despite these great benefits, DI has a major drawback. Injections are namely static and do not reflect the changing state of the application over time.
Seam meets this limitation by introducing a mechanism called bijection, which is the combination of injection and outjection. Outjection is the opposite of injection and enables to promote the value of a certain component property so that it can be used by other components. In general, bijection is the two-way injection and outjection interaction between Seam components and the Seam managed context.
Under bijection, the wiring of dependencies is done continuously throughout the lifetime of a component instance, not just when the instance is created.-- Dan Allen, Seam in Action, ISBN 1933988401
Unlike DI, bijection is dynamic and happens every time the instance of the component is invoked, not just at creation time. Being so, it allows to fully focus on the business logic instead of wiring components together. Obviously, Seam bijection is a powerful and flexible mechanism which offers some great benefits.
How to make use of bijection?
To use the bijection mechanism, Seam provides two main annotations. @In to inject a component and @Out to allow a certain property to be injected by another component.
Let’s have a look at a simple example:
@Name("userAction")
public class UserAction {
@In protected EntityManager entityManager;
@Out protected User user;
public String view(Long userId) {
user = entityManager.find(User.class, userId);
return "/profile.xhtml";
}
}
When the view-method is invoked, Seam first iterates over all properties marked with an @In annotation. In this example, only the EntityManager needs to be injected in order to get the necessary user information. Seam then tries to find the EntityManager in the context container, and injects it when found. Otherwise, an error is thrown.
When the body of our method is executed, Seam iterates over all properties again. This time it looks for the @Out annotation. The value of these properties is then promoted to context variables in the context container. In our example, we want to outject the found user with its given userId. Finally, the properties that made use of injection are cleared again in order to have a clean state for the next invocation. The user with given userId can now be injected by other components.
Bijection in Salesmen
Since all our search queries are centralized in the BasicSearchBean, it is often necessary to make use of this bean by other components. Therefore, bijection is what we need!
Suppose we want to get the UserAccount with a certain username. Initially, we made use of the BasicSearchBean by just creating a new instance of it.
public void doSomething(String username){
private UserAccount account;
BasicSearchBean search = new BasicSearchBean();
account=search.findUserAccount(username);
account.doSomething();
}
However, this did not work. The BasicSearchBean instance could not find our UserAccount since the dependencies related to the EntityManager were not handled appropriate.
We then came up with the following solution to solve this issue:
@In EntityManager entityManager
public void doSomething(String username){
private UserAccount account;
BasicSearchBean search = new BasicSearchBean();
account=search.findUserAccount(username, entityManager);
account.doSomething();
}
What we did was to pass our current EntityManager to the BasicSearchBean which could then execute the search query on that EntityManager. This worked well, but it didn’t feel right though.
The solution was to make use of the bijection mechanism provided by Seam to inject the BasicSearchBean into our component. Being so, all necessary dependencies are treated properly.
@In(create=true) BasicSearch search
public void doSomething(String username){
private UserAccount account;
account=search.findUserAccount(username);
account.doSomething();
}
Please note that we do not inject the BasicSearchBean itself but only its interface. Moreover, we set create=true to denote that the component may be created in case that it would not be available in the context container.
By using bijection, we can now make use of all BasicSearch functionallity without handling the necessary dependencies. Indeed, Seam bijection is a great mechanism and offers a lot of benefits and power to let you fully focus on the business logic of your application.
Sources:
- http://www.mastertheboss.com/en/seam/65-jboss-seam-tutorial-part-2.html
- http://www.infoq.com/articles/jboss-seam
- http://msdn.microsoft.com/en-us/magazine/cc163739.aspx
- Seam in Action by Dan Allen, 2009 - ISBN 1933988401
No comments:
Post a Comment