Showing posts with label seam. Show all posts
Showing posts with label seam. Show all posts

Thursday, March 4, 2010

Understanding and Comparing Dependency Injection Frameworks

If you have used a modern Dependency Injection (DI) framework like JBoss Seam, Google Guice or CDI (Contexts and Dependency Injection), you might already be familiar with the following line of code:

@Inject MyBean myBean;

But, to really understand how a DI framework works and what makes one different from the other, we are going to build one from scratch. Let’s call it OurDI. Then, we will compare it with some of the most popular DI frameworks out there.

So, let’s start by writing a Quick Start Guide for OurDI that shows how it works.

Quick Start Guide

As any other modern DI framework, OurDI allows you to inject dependencies using annotations as in the following example:

public class UsesInjection {
  @Inject MyBean myBean;
  ... 
}

In order to configure OurDI, all you need to do is to populate a class named Injector with all the objects that can be injected at runtime; each object must be identified by a unique name. In the following example, we are going to configure the Injector with two classes MyBean and AnotherBean, bound to the names “myBean” and “anotherBean” respectively:

public class Main {
  public final static void main(String[] args) {  
    Injector injector = Injector.instance();  
    injector.bind(“myBean”, new MyBean());  
    injector.bind(“anotherBean”, new AnotherBean(); 
  }
}

So, when a method of the UsesInjection class (defined above) is called, a search will be done for the name of the attribute “myBean” on the Injector instance, and the value associated with that name will be injected.

Building the framework

Well, that was a quick Quick Start Guide! Now let's see how OurDI works underneath.

OurDI is composed of two classes and an annotation:

  • A singleton class named Injector, that will store the bound objects.
  • A class named InjectorInterceptor, which will use AOP (Aspect Oriented Programming) to inject the dependencies at runtime.
  • The @Inject annotation.

Let’s take a look at the Injector class:

public class Injector {

  private Map<String,Object> bindings = new HashMap<String,Object>();

  // static instance, private constructor and static instance() method 
 
  public void bind(String name, Object value) {
    bindings.put(name, value);
  }
 
  public Object get(String name) {
    return bindings.get(name);
  }
}

As you can see, Injector is singleton class backed by a Map<String,Object> that binds each object to a unique name. Now, let’s see how injection is done when an @Inject annotation is found.

We can use any AOP library to intercept method calls and look for all the dependencies that need to be injected on the target object. In this case, we are going to use AspectJ:

@Aspect
public class InjectorInterceptor {

  @Around("call(* *.*(..)) && !this(InjectorInterceptor)")
  public Object aroundInvoke(ProceedingJoinPoint joinPoint) throws Throwable {
  
    // this should return the target class
    Class clazz = joinPoint.getTarget().getClass();
  
    // inject fields annotated with @Inject
    for (Field field : clazz.getDeclaredFields()) {
      if (field.isAnnotationPresent(Inject.class)) {
        doInjection(joinPoint.getTarget(), field);
      }
    }
  
    return joinPoint.proceed();
  }
 
  private void doInjection(Object target, Field field) throws IllegalAccessException {
    String name = field.getName();
    field.setAccessible(true);
    field.set(target, Injector.instance().get(name));
  }
}

Before each method call, the aroundInvoke method will be called. It will look at all the fields of the target object to see if it finds any @Inject annotation. For each of the annotated fields, it uses the name of the field to find the corresponding object in the Injector class.

Finally, here is our @Inject annotation:

@Target(value={FIELD})
@Retention(value=RUNTIME)
@Documented
public @interface Inject {}

That’s all! you can check the full source here. Now, let’s check some aspects of our solution and compare them with other popular frameworks out there.

Configuration

In OurDI, we have to manually populate the Injector instance with the objects that are going to be injected. This is similar to Google Guice. However, in Guice, there is no need to use a name and, instead of binding objects, we bind classes:

Injector injector = Guice.createInjector(new Module() {
  public void configure(Binder binder) {
    binder.bind(Notifier.class).to(SendSMS.class);
    binder.bind(Database.class).to(MySqlDatabase.class);
  }
});

JBoss Seam and CDI take a different approach. Instead of binding each class manually, they scan all your classes on bootstrap to populate the “injector”. In JBoss Seam, you will need to register the Seam Servlet Listener on your web.xml; for CDI, no configuration is required (besides the beans.xml descriptor), the application server will do the scanning automatically (one of the benefits of being part of the JEE stack).

Scanning all classes and choosing the ones suitable for injection can take a while. So, Google Guice (and OurDI) will be faster starting up. However, with JBoss Seam or CDI, you won’t have to worry about binding each class/object manually.

Type safety

As you might already have noticed, OurDI will break at runtime with a ClassCastException if the injected object is not of the expected type. The same happens with JBoss Seam, which also uses a name-based approach (components are named using the @Name annotation).

On the other hand, Google Guice and CDI are type safe, meaning that the injected objects are not identified by a name, but by their type.

Overriding/changing implementations

In OurDI, to override/change the implementation of an injected class, all we need to do is change the object bound to the Injector class. This is very similar to Google Guice as shown before.

For JBoss Seam and CDI, we need to provide more information about the classes we want to use. I won’t dive into the details but you can check how this works in the Weld documentation for CDI and in this post for JBoss Seam.

Constructor and method injection

Besides field injection, some DI frameworks provide constructor and method injection to initialize your objects. OurDI doesn’t support any of these, neither JBoss Seam. Both CDI and Google Guice support them.

Injection of external resources

Sometimes, you need to inject things you don’t have control of. For example, DataSources, 3rd party libraries, JNDI resources, etc. OurDI doesn’t support this. JBoss Seam supports it with factories and manager components, Google Guice supports it with provider methods and CDI supports it with producer methods and fields.

Scopes

Scopes, also known as Contexts, are a fundamental part of development. They allow you to define different lifecycles for each object (i.e. request, session, or application). OurDI doesn’t support scopes. However, Google Guice, JBoss Seam and CDI, all support scopes in one way or another. You can read more about scopes and their importance on this post.

You can also check the documentation of scopes for each framework/specification: Google Guice, JBoss Seam and CDI.

Static vs. Dynamic Injection

In OurDI, every time a method is called, it will scan the object to find dependencies that need to be injected. This is called Dynamic Injection and is how JBoss Seam works. The advantage of dynamic injection is that if a dependent object is changed, the new object will be injected in the next method call, so, you’ll always end up with the “correct” instance.

Google Guice and CDI uses Static Injection, which means that injection will only occur once after the object is created. The problem here, as stated above, is that if a dependent object is changed, you will still have the reference to the old object. CDI solves this problem by using proxies that will always point to the correct instance. So, even though it uses static injection (the field is injected only once), it works like dynamic injection.

Lazy Loading of objects

In OurDI, you will need to instantiate all the classes that need to be injected on startup. This is definitely not a good idea as you are loading things in memory that you are not still using. Google Guice, JBoss Seam and CDI all use a lazy loading approach where the objects will be loaded only when needed, which is a good thing.

Aspect Oriented Programming

Most DI frameworks provide some type of method interceptor mechanism that simplifies AOP development, usually with annotations. This is another feature that OurDI lacks! However, Google Guice, JBoss Seam and CDI, all support this feature with a very similar approach.

Integration

Integration with other environments is really simple with OurDI and Google Guice. You just need to configure the Injector on startup and that’s it. JBoss Seam is a complete development platform that integrates multiple technologies and it would be almost impossible to integrate it on a different environment different from JEE. CDI is part of the JEE 6 stack, however, implementations like Weld can run on different environments with the appropriate hookups. 

Conclusion

Ok, let’s face it. Our own DI framework sucks!:

  • It doesn’t support constructor or method injection (or provide an alternate solution).
  • It doesn’t support injection of external resources.
  • It needs all classes to be instantiated on startup.
  • It doesn’t support scopes. 
  • It doesn’t provides a method interceptor mechanism.

However, I hope OurDI was useful enough to compare different DI frameworks. We only talked about Google Guice, JBoss Seam and CDI, but you can do the exercise with any other DI framework out there.

Thursday, February 18, 2010

Overriding a component in JBoss Seam

A few days ago, I was asked to explain how to change/override/mock a component in JBoss Seam. So, here is it.

To override a component in Seam, all you need to do is to create a second component that satisfies the following conditions:

  1. It must have the same name as the component you are overriding.
  2. It must be of the same type than the component you are overriding. Or you will end up with a ClassCastException on injection.
  3. It must have a higher precedence than the component you are overriding.

The first two points need no further explanation. However, the third one raises the following questions: What is the precedence of a component? How do I change it?

The precedence of a component is a numeric attribute all components have, which by default is 20. You can change the precedence of a component using the @Install annotation:

@Name("myBean")
@Install(precedence=40)
public class MyBean {
 ...
}

On startup, if Seam finds more than one component with the same name, it will choose the one with the higher precedence value. If it finds two components with the same name and the same precedence, an Exception is thrown.

Let’s take a look at an example. Suppose that you have an interface called CodeGenerator with two implementations: DefaultCodeGenerator and an alternate MockCodeGenerator.

public interface CodeGenerator {

 public String generateCode();
 
}
@Name("codeGenerator")
public class DefaultCodeGenerator implements CodeGenerator {

 public String generateCode() {
  ...
 }
}
DefaultCodeGenerator. No @Install annotation; it will have a precedence of 20 (the default value).
@Name("codeGenerator")
@Install(precedence=Install.MOCK)
public class MockCodeGenerator implements CodeGenerator {
 
 public String generateCode() {
  ...
 }
}
MockCodeGenerator. Notice that it has the @Install annotation with a precedence of 40 (see the table below).

Now, suppose both DefaultCodeGenerator and MockCodeGenerator are on the classpath and that we have the following injection point:

@Name("testCodeGenerator")
public class TestCodeGenerator {
 ...
 @In
 private CodeGenerator codeGenerator;
 ...
}

Which component will be injected? Seam will choose the one with the higher precedence. In this case: MockCodeGenerator. So, a common usage is to have a separate JAR with the alternate implementation that can be included on the classpath only when needed (i.e. added to the WAR or EAR archive).

Seam defines some predefined precedence values:

Constant Value Description
Install.BUILT_IN 0 Built in Seam components have this precedence.
Install.FRAMEWORK 10  
Install.APPLICATION 20 The default precedence
Install.DEPLOYMENT 30  
Install.MOCK 40 For mock objects used in testing

Note: It is recommended to use one of this constants for the precedence. However, nothing stops you to set a different value.

Using components.xml

Another way of overriding a component in Seam is to define the component in the components.xml descriptor file instead of using the @Name annotation. XML-based configuration is discouraged by Seam but valid anyway. This way you can change the class directly in the XML without re-compiling.

What I usually do is to have a default implementation annotated with the @Name annotation which has the default precedence. When I need to override it, I define a second component in the components.xml descriptor with a higher precedence (this way, I’m only using the XML file to install the alternate implementations). For example, instead of annotating the MockCodeGenerator with @Name and @Install, we could have added it to the components.xml:

<components>
 ...
 <component name="codeGenerator" class="org.test.MockCodeGenerator" precedence="40" />
 ...
</components>

Other options

The @Install annotation is much more powerful than what I’ve just shown you. It allows you to “install” a component only when certain conditions are satisfied. For example:

  • When you are working on debug mode.
  • When a class or group of classes are present on the classpath.
  • When a component or group of components are present on the classpath.

When you are working on your development environment, you might want to mock some components to: simulate external systems you don’t have access to, simulate emails, sms, etc., disable some functionality, etc. For these cases, you can have some components annotated with @Install(debug=true) that override the default ones. They will be installed only when working on debug mode (this setting is configured in components.xml).

More advanced options allow you to install a component if some classes or other components are present on the classpath. You can do some complex stuff here but that is out of the scope of this post.

Finally, you can always rely on @Install(false) which won’t install the component by default. You will have to install it manually in the components.xml descriptor file. Al lot of built-in components of Seam are configured this way so you can install them only when needed.

Conclusion

Seam offers you a variety of ways in which you can override components, or, how Seam calls it, conditionally install components. It offers you so many options, it can sometimes get tricky. However, once understood, it is a very powerful feature.

Sunday, January 17, 2010

From JBoss Seam to CDI (JEE6)

Seam is a popular open source application framework that has led to the creation of CDI (Contexts and Dependency Injection), a specification that is now part of the JEE 6 ecosystem. In this post I’ll show you the architectural similarities and differences between both and how Seam has influenced CDI. So lets start!

Contexts

Contexts are definitely one of the most exciting features of Seam (you can read more about them in this post) and remain in the core of CDISeam defines six stateful contexts: request (event), session, application, page, conversation and business process context. CDI only define 4, leaving page and business process contexts out. However, CDI allows you to define new contexts which was not possible in Seam. You can see an example of creating a context (the equivalent of the page context in Seam) by Steven Verborgh here.

Additionally, CDI now defines a new “dependent” context which allows a bean to have the same context as the bean that declares it. They will share the same lifecycle meaning that “it [the dependent bean] is instantiated when the object it belongs to is created and destroyed when the object it belongs is destroyed”, as stated in the Weld documentation.

Dependency Injection

Even though Seam and CDI both make heavy use of the Dependecy Injection pattern, they take different approaches to implement it. The most notable differences are the following (I’ll explain each one in more detail below):

  • Seam uses a string-based approach to search for components which is not type safe while CDI brings type safety to the limit.
  • Seam uses dynamic injection while CDI uses static injection.

Type safety

In Seam, every component has a name defined by the @Name annotation. When an injection occurs, Seam searches for the name of the component which can lead to runtime exceptions. For example, suppose you have the following component:

@Name("myBean")
public class MyBean {
 ...
}

Now, suppose you mistakenly inject MyBean into a String like this:

@In
private String myBean;

This will compile just fine, but at runtime you will get an exception. In large applications, this is a problem as you will potentially have a lot of bugs at runtime, something you really want to avoid.

CDI implements dependency injection based on the type of the bean like in Google Guice. There is no need to name a bean unless you want to access it from EL, in which case, you will need to annotate your bean with the @Named annotation. Lets look at a simple case of injection in CDI:

public class Bean1 {
 ...
}

public class Bean2 {
 @Inject
 private Bean1 bean1;
 ...
}

When Bean2 gets instantiated, Bean1 will be injected on Bean2. As you can see, there is no need to name the beans.

Static vs. Dynamic Injection

In Seam, injection occurs on each method call. After the method completes, all injected values are desinjected (set to null). This is known as dynamic injection and it has its benefits and drawbacks. The most outstanding benefit is that you can inject components from different contexts (i.e. a request component injected in a conversation component)  and you will always have the “correct” instance on each method call. However, dynamic injection has some problems including performance and null values on concurrency.

CDI uses static injection, meaning that all the values are injected on the creation of the bean and they are not desinjected between method calls. To handle injection of beans from different contexts, it uses proxies that reference the “correct” instance of each bean. A much more elegant solution in my opinion.

Factories

Remember the @Factory annotation in Seam? It allows you to obtain objects that are not Seam components; or it could also be used when you need to perform some custom initialization on a component before returning it. In CDI, there is an equivalent functionality called “producer method”:

@Produces
public User getUser {
      ...
}

Every time a User object is injected, this method will be called to obtain a reference. CDI provides a simpler alternative to a producer method called a producer field:

@Produces
private User user;

Events

In Seam, you can decouple your components using events. Each event must have a name. You can raise an event using the @Raise(“<name_of_event>”) annotation or programmatically using the Events.instance().raiseEvent(“<name_of_event>”) method. To observe for an event, you mark the method you want to be called on the event with the @Observer(“<name_of_event>”) annotation.

CDI grabs this concept from Seam and makes it type safe. So, for raising an event we can obtain an Event object by injection:

@Inject
private Event<User> userEvent;

And then call the fire method on the Event object:

userEvent.fire(user);

Now, for observing an event you use the @Observes annotation:

public void observeUserEvent(@Observes User user) {
 ...
}

Interceptors

Seam relies heavily on interceptors for injection, security, persistence and much more. CDI also provides an interception facility called interceptors bindings, based on the Java Interceptors specification. Furthermore, CDI provides the concept of “decorator”, which is a kind of interceptor for implementing the decorator pattern.

Wrapping up

Let’s take a look at the services provided by CDI and see if they were inspired by Seam:

  • Contexts: heavily inspired by Seam.
  • Dependency Injection: mostly inspired by Google Guice but we have an equivalent in Seam (which is not type safe).
  • EL integration (the #{} notation): completely inspired by Seam.
  • Interceptors: completely inspired by Seam.
  • Events: heavily inspired by Seam but type safe.

Wait a minute! Are these all the services provided by CDI? What about all the out-of-the-box functionality I used to have in Seam (page flows, business process integration, security, scheduling, caching, remoting, etc.)? Don’t worry! Portable Extensions, the only service we are missing in this list, will solve this question, so just keep reading!

Portable Extensions and Seam 3

Besides the services described above, CDI provides a powerful SPI (Service Provider Interface) you can use to create extensions (called Portable Extensions in CDI). This is where Seam 3 enters the game!

Seam 3 will be a set of portable extensions that will provide almost all of the out-of-the-box functionality you actually have in Seam 2. At the time of this writing, Seam 3 is on its first steps and there is no official release yet. However, you can start developing your own portable extensions on top of CDI. Take a look at this post by Matt Corey to start writing your own first portable extension!

Conclusion

CDI has been heavily influenced by Seam with two major architectural changes:

  • Instead of providing everything out-of-the-box as Seam, CDI provides a set of core technologies and a powerful SPI that will enable any one write its own portable extensions.
  • Type safety. This was included in every aspect of CDI (Contexts, DI and events), except for the EL integration.

Remember that Seam is a framework and CDI is a specification (Weld is the Reference Implementation). For more information on CDI, check the Weld documentation and the CDI specification.

Sunday, November 22, 2009

Seam and JSF

In my last post, I talked about Seam contexts and how to use them from your application. Now, I’ll show you how you can access them from JSF, especially how to use the event context correctly. At the end, I’ll give you some tips you may find useful when developing the web tier of your application with Seam and JSF.

Accessing contexts from your JSF pages

In Seam, you can access anything saved in the contexts from a JSF page using the #{} notation. For example, consider the following line of code:

<h:outputText value="#{employee.name}" />

This will search all the stateful contexts for the “employee” key using the Contexts.lookupInStatefulContexts() method as I showed you in my last post. Remember that the context search priority is: event, page, conversation, session, business process and application. If the key is not found in any of the contexts, it will return null. Otherwise, it will try to call the getName() method on the object.

JSF and the event context

The event context is the narrowest of the stateful contexts; it only lasts during a single http request. It is very useful when working with data iteration because Seam binds the iterated variable into the event context. Consider the following code fragment:

<rich:dataTable value="#{employees}" var="employee">
 <rich:column>
  <h:outputText value="#{employee.name}" />
 </rich:column>
 <rich:column>
  <h:outputText value="#{employeeSalaryResolver.netSalary}" />
 </rich:column>
</rich:dataTable>

In line 6 we are calling another component called employeeSalaryResolver to retrieve the net salary of the employee. Seam binds the actual employee object into the event context, so, we can just inject it in the EmployeeSalaryResolver component:

@Name("employeeSalaryResolver")
public class EmployeeSalaryResolver {
 
 @In
 private Employee employee;

 public double getNetSalary() {
  double netSalary = employee.getBaseSalary();
  
  // do other complex calculations (extra hours, bonus, etc.)  
  
  return netSalary;
 }
}

The employee attribute is being injected from the iteration variable (the event context) and used to retrieve the net salary of the employee. This component can be then reused in other use cases.

You can also use the event context to pass information between pages. For example, imagine a component that searches for an employee using the social security number and shows the result in another page.

@Name("searchEmployee")
public class SearchEmployee {
 
 private String ssNumber;
 
 @Out(scope=ScopeType.EVENT,required=false)
 private Employee employee;

 public String search() {
  Employee employee = ...; // search for the employee
  if (employee != null) {
   return "success";
  }
  
  return null; 
 }
}

When the search method is called (from a page I’m not showing) and an employee is found, the searchEmployee component will outject the Employee object to the event context and render the result in another page. The navigation in pages.xml would be something like this:

<page view-id="searchEmployee.xhtml">
 <navigation>
  <rule if-outcome="success">
   <render view-id="searchResult.xhtml"/>
  </rule>
 </navigation>
</page>

If you notice, we are using render tag instead of redirect tag. This will forward the request to the searchResult.xhtml page instead of redirecting, so the event context will not be lost.

Seam and JBoss EL

Standard EL (the #{} notation you use in your JSF pages) does not allow you to call methods with predefined parameters. However, Seam overcomes this limitation by using JBoss EL, which is an extension of the standard EL. For example, in our employees application, suppose we have a list of employees and we want to add an option on each row to fire employees. So, we create a fireEmployee component with a fire method that receives an Employee as an argument.

@Name("fireEmployee")
public class FireEmployee {

 public void fireEmployee(Employee employee) {
  // fire employee
 }
}

Now, we just need to add the action to the employees' page.

<rich:dataTable value="#{employees}" var="employee">
 <rich:column>
  <h:outputText value="#{employee.name}" />
 </rich:column>
 <rich:column>
  <h:outputText value="#{employeeSalaryResolver.netSalary}" />
 </rich:column>
 <rich:column>
  <s:link value="Fire Employee" action="#{fireEmployee.fire(employee)}" />
 </rich:column>
</rich:dataTable>

Really cool feature! Look at the <s:link> tag. Seam introduces some JSF tags to ease development. I won’t describe them here, but if you want, you can check them here.

Tips using Seam and JSF

1. Backing beans

In Seam, you can use EJB’s as your backing beans. However, by default, use JavaBeans (POJO’s). The reason is that you usually bind the backing bean to the page scope, but, if you use EJB Session Beans, you will not be able to do this.

@Name("someBean")
@Scope(ScopeType.PAGE)
@Synchronized
public class SomeBean implements Serializable {

 private static final long serialVersionUID = -2524956479693778917L;

 // your code ...
}

You can also bind your backing beans to the conversation or session scopes when needed. The @Synchronized annotation tells Seam to serialize requests from the backing beans as concurrency may cause some problems occasionally, especially when you are using AJAX calls. A better approach, however, is to use the eventQueue attribute in your richfaces components. See this for more information.

2. Use a naming convention for your components

You have to choose carefully the name you assign to each of your components because as the application starts growing, you may repeat component names and having some conflicts. So, you can use the package as a prefix for the name of the component.

However, if the project is small, you also can use a simpler prefix if you want. For example, you can use the “controller” prefix for your backing beans, “logic” for your business components and “model” for your entities and DAO’s.

3. You can use more than one Backing Bean per page

A lot of people use one backing bean per page. However, I really discourage this at it does not promotes code reusing and increments coupling. For example, if you have something you show in every page, use a separate backing bean and bind it to the session scope instead of retrieving the same information in every page.

Conclusion

Seam allows you to access any component in any context from JSF, this gives you the opportunity to choose how you want to architect your solution with some cool features that help you speed development time.

Friday, November 6, 2009

Understanding Seam Contexts

One of the most exciting features of JBoss Seam is the contextual component model that radically changes the way we design applications. It has become so important, it is now part of the JEE6 specification through the JSR-299. In this post, I will concentrate on explaining how Seam contexts work and how to use them from your code.

You may already be familiar with the request, session and application scopes of the Servlet specification. They are very useful to save and retrieve data but they have a huge limitation: you can only access them from a Servlet/JSP.

JBoss Seam overcomes this limitation by making the scopes (called contexts in Seam) available to the whole application instead of only to Servlets/JSP’s. So, you’ll find request(event), session and application contexts and 3 more they’ve created: page, conversation and business process contexts.

The request(event), session and application contexts work exactly as they do in Servlets/JSP’s so I’ll just skip their explanation. I will, however, explain briefly the page, conversation and business process contexts.

Page Context

The page context is broader than the request context as it spans multiple requests over the same page. This is very useful if you need to make roundtrips to the server to perform validation, bring information, etc. while maintaining the same page state.

Conversation Context

The conversation context is broader than the page context as it can expand to multiple request and pages but narrower than the session context. It is very useful to implement wizards-like interfaces in which the user has to fill data across multiple pages while maintaining the state over the whole process. You control the creation and destruction of each conversation.

Business Process Context

As it name implies, it is used to maintain state information during the execution of a business process instance in jBPM.

Using contexts from your code

You can use the Contexts class to gain access to one of the contexts, defined by the Context interface, and then use the set or get methods to save or retrieve information respectively.

For example, to save the current user information in the session context you use the following code:

User user = new User();
Contexts.getSessionContext().set("user", user);

Then, when you need to retrieve the user information, you use:

User user = (User) Contexts.getSessionContext().get("user");

Really simple, ah? You can also use the @Out and @In annotations in class attributes to save and retrieve information:

@Out(value="user",scope=ScopeType.SESSION)
private User user;

What the @Out annotation is telling Seam is to save the User object in the Session context with the key “user”. Then, you can retrieve the user with the following code:

@In(value="user",scope=ScopeType.SESSION)
private User user;

Again, the @In attribute is telling Seam to inject the User object from the Session context saved with the “user” key. You don’t have to write any getters or setters in your class, Seam will just outject or inject the information whenever an @Out or @In annotation is present. If no object is found under the “user” key, null will be injected.

As you can see, the value attribute of the @In and @Out annotations are used as a key for searching or saving data in the contexts. The scope attribute is used to specify the context in which the value should be injected or outjected. This attributes are optional; so, what happens if we don’t specify them as in the following example?

@In
private String name;

@Out
private User user;

When you don’t specify the value attribute, Seam uses the attribute’s name as key by default. In the preceding code fragment, Seam will use “name” as the key for the @In annotation and “user” for the @Out annotation.

If you don’t specify the scope of an @In annotation, Seam will scan all the contexts in the following order: event, page, conversation, session, business process and application. If the key is not found, it will inject null. You can use this feature programmatically by calling the Contexts.lookupInStatefulContexts() method.

If you don’t specify the scope of an @Out annotation … well, as the @Out JavaDoc states: “If no scope is explicitly specified, the default scope depends upon whether the value is an instance of a Seam component. If it is, the component scope is used. Otherwise, the scope of the component with the @Out attribute is used.” I know, I haven’t talked anything about Seam components as it is not the topic of this article. If you want to know about Seam components read this.

Conclusion

I hope this introduction has given you the basics of Seam contexts. It is a very simple, yet powerful, concept that has to be taken seriously when designing your next applications.