Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

This page contains a catalog of migration notes and recommendations when moving from Seam 2 to Seam 3.


Sticky forum thread about migration

Scopes / Contexts

Seam 2 provides a fixed set of contexts. These are listed in the table below. Any java type can be stored in a context. Session and conversation contexts require the values to be serializable. In Seam 2, the scope of a component is defined using one of the values of the ScopeType enumeration, e.g. @Scope(ScopeType.SESSION).

CDI provides a similar set of contexts. This set can be extended by additional scopes provided by portable extensions that implement the required SPI. In CDI, each scope has an associated annotation, which consists of the scope name plus Scoped, e.g. @SessionScoped.

CDI scopes are split into two groups:

  • Normal scopes - Implemented using dynamic proxies - the client receives a dynamic proxy for the contextual object. Everytime a method is invoked on a proxy, the container guarantees that the method is invoked on the actual contextual instance. Most of the built-in CDI scopes are normal scopes.
  • Pseudo-scopes - Client proxies are not required for pseudo-scopes. CDI provides single built-in pseudo-scope - @Dependent

As a result of using dynamic proxies for implementing normal scopes (every scope except for @Dependent), every managed bean bound to a normal scope is required to be proxyable. The exact definition of a proxyable bean is defined in the specification. This may be a problem for legacy applications that use unproxyable beans (e.g. an instance of java.lang.String bound to the session scope). The problem can be solved by:

  • making the bean proxyable (e.g. adding a non-private no-arg constructor or removing the final modifier of a class or method) or
  • creating a holder object that wraps the unproxyable object but is itself proxyable or
  • using @Dependent scope instead of a normal scope if possible

Names of corresponding scopes:

Seam 2 scope name CDI/Seam 3 scope name
Event Request
Session Session
Stateless No direct corresponding scope. The stateless scope is using primarily for Stateless Session Beans (EJB) in Seam 2. A Stateless session bean can be bound to the @Dependent context in a CDI application.
No direct match Dependent - new instance for each injection point.
Application Application
Page View
Conversation No direct corresponding scope. For long conversations, the corresponding scope is Conversation. For temporary conversations, the closest corresponding scope is Flash (but not the same). But there is no scope which would be automatically converted when stopping/starting a long-running conversation.(TODO: expand)
No direct match Conversation - covers only long-running conversations, where the boundaries are explicitly set by the programmer. (TODO: expand)
No direct match Flash - spans two requests. Survives a redirect. (TODO: expand)




In Seam 2, it is quite common to use JPA entities as Seam managed objects. Take the User entity from the booking application as an example. Such entity is instantiated by Seam and stored in the session context. Its values are bound to a form in a JSF page using EL expressions and filled by an application user. Finally, the managed object is passed to the EntityManager and persisted in the database.

Since Seam 2 stores direct references to bean objects in its contexts, the approach above works fine for non-intercepted entities (which entities usually are).

CDI uses different memory model (TODO write a chapter on this difference). Everytime an application code accesses a reference to a CDI-managed bean stored in a normal context, it actually accesses a dynamic client proxy. Since proxy classes are different from the original classes of the entity, they cannot be used in the persist() method of the EntityManager. Therefore, never use entities as CDI managed beans.

Although this may seem like a major limitation, it is not the case. Most of the time, there is not need for JPA entities to support dependency injection nor they need to be interceptor. The only services really useful to entities is storing them in a context. CDI supports this in form of a producer field or method. The common approach is to use a stateful manager object for instantiating and holding the reference to a scoped entity. See the Registrar component of the Seam 3 booking application as an example.



@Install - Conditional installation

Seam 2 offers the @Install annotation for controlling whether a given bean should be installed or not. The following concepts are supported and can be configured using the annotation:

  • explicit prevention from installation
  • installation dependencies
  • bean selection based component ordering (precedence)

The CDI specification itself does not define a single replacement for all the functionality represented by the @Install annotation. Instead, the concepts are implemented separately.

Concept Seam 2 CDI / Seam 3
explicit prevention from installation
installation dependencies
@Install(dependencies = "foo")
Note that class-level dependencies are supported only
bean selection based component ordering (precedence)
@Install(precedence = MOCK)
or Alternative stereotype or


Seam 2 provides the @Startup annotation that can be applied to an application or session scoped component. A @Startup-annotated component is instantiated immediately after the context is started up, instead of instantiating the component lazily when first needed by a client.

There are two possible alternatives in Java EE 6:

  • EJB Singleton beans - which can be marked to be instantiated eagerly at application startup using the @Startup annotation. Combined with the fact that these components can benefit from declarative transaction management, these components are good candidates for performing database imports, etc.
  • Observing Solder's events which notify the component when the application starts or when the request or session context is activated due to a servlet request.

Initialization and lifecycle callbacks

Seam 2 supports standard @PostConstruct and @PreDestroy annotations for designating post-initialization and pre-destruction callbacks. Besides, Seam-specific alternatives (@Create and @Destroy) with identical semantics are supported.

CDI only supports the standard annotations. If using the Seam-specific ones in a legacy application, the easiest solution is to replace them with the standard ones.

Besides, CDI provides richer initialization facilities such as

  • dependency injection using the bean constructor (which allow for using dependency injection in immutable objects)
  • dependency injection using initializers methods

See the CDI specification for more details.

EL evaluation

Seam 2 provides a consistent use of the Expression Language within Java code. EL expressions can be used in

  • Logger messages
  • EntityManager queries
  • JSF messages

Currently, Seam 3 lacks similar level of consistency. When migrating legacy applications, the simplest migration path is to use the Expressions component and wrap each occurrence of string containing EL expression with a call to Expressions."Registered new user #{user.username}"));


We should plan to have a chapter dedicated to navigation (e.g., pages.xml and s:button/s:link) as JSF 2 takes a very different approach.

UI components

Many of the UI components in Seam 2 have been assimilated by JSF 2 or RichFaces. There are UI components that remain. We should have a clear mapping and identify components that have reached EOL.

Special injection

Besides injecting a component using the @In annotation, Seam 2 provides access to special injectable objects. These are listed below


The @RequestParameter annotation triggers injection of an HTTP request parameter. The parameter name can be set explicitly as a value of the annotation or can be implied from the name of an injection point.

private Long id;

In Seam 3, the same functionality is provided by Solder's @RequestParam.

@Inject @RequestParam
private Long id;

Besides request parameters, Solder also supports injection of header parameters of an HTTP request.

Note that injection of multi-valued parameters into collections or arrays is not currently supported in Solder (See SOLDER-295)


Seam 2 provides a built-in logger implementation. It is a thin wrapper that delegates to an available logging framework (log4j or JDK logging). Besides, it provides extra features such as EL expression evaluation.

In Seam 3, Solder provides a built-in logger which uses JBoss Logging internally. Similarly to Seam 2, a logger instance can be injected easily.

Seam 2 Seam 3
Obtaining a logger instance
private Log log;
@Inject @Category(“”)
private Logger log;
or use factory method for static fields
private static Logger log = Logger.getLogger(Bean.class);
Logging a message
log.debug("Creating new order for user: #0", user.username());
log.debugv("Creating new order for user: {0}", user.username());

Note that:

  • the old format of parameter placeholders (e.g. #0) is no longer supported. You can use either MessageFormat or Formatter syntax instead.
  • EL evaluation is not supported. The Expressions utility bean can be used for evaluating EL expressions programmatically.
  • CDI does not support static injection. As a result, a logger reference should either be injected into a non-static or a static field should be initialized using logger factory

Besides the traditional approach to logging, Solder provides support for typed loggers

@DataModel* - (@DataModel, @DataModelSelection, @DataModelSelectionIndex)

In the old JSF 1.x days, due to limitations of the Expression Language, it was common to use data collections wrapped within DataModel objects from a JSF data table. This allowed the backing bean to obtain the selected row of the data table on postback.

Seam 2 makes this task easier by wrapping data collections within appropriate DataModel subclass automatically. In addition, once a data model row is selected, the selected item (or selected row number) can be injected by Seam.

In Java EE 6, the Expression Language Specification evolved and allows parameters to be passed to EL method expressions. This approach should be used as a replacement for the @DataModel* functionality. Seam 3 does not provide a substitute for the @DataModel* functionality.


This section describes how to migrate your bean configuration.

XML Configuration

Seam 2 provides an XML configuration layer that allows:

  • selected types of meta-data to be overridden for an existing bean (scope, precedence, ...)
  • registration of new beans
  • initial values of a bean to be specified

This is done either in the global components.xml file or in fine-grained configuration files.

In Seam 3, Solder provides an XML configuration extension. Compared to Seam 2, this extension supports a superset of features:

  • adding / removing of beans
  • modification of metadata of existing beans - any metadata information that can be expressed using annotations can be expressed using XML as well (e.g. injection point, producer method or observer method metadata )
  • initial values of a bean including inline bean declarations

The configuration can either be specified directly in the beans.xml file or in a file called seam-beans.xml.

Other ways of configuration

Seam 2 configuration can be overridden using property settings. These settings can be read from system properties, servlet context parameters and the file.

Seam 3 currently does not provide this level of integration between the XML layer and property-like configuration facilities. Nevertheless, access to the all source of configuration mentioned above is provided at some level:


Both Seam 2 and CDI beans may produce and consume events in order to communicate with other beans. Unlike method invocation, events allow for decoupled architecture with no compile-time dependency.

In Seam 2, the type of an event is represented by a string value. Observer methods may observer one or more event types. An observer method is notified when an event of a matching type is fired. An event can carry additional objects which are passed as method parameters to the observer method. Synchronous delivery, as well as other types such as asynchronous, timed and transaction-bound delivery modes are supported - these are summarized below.

Unlike Seam 2, the process of observer method resolution is type-safe in CDI. A CDI event is represented by a payload (any Java object) and a set of qualifiers. The Java types of the event payload together with qualifiers to determine which observer methods are notified of the event (See observer resolution rules).

Seam 2 CDI
Raising event
private Event<Foo> event;

// in code Foo());
Observing an event
public void observe() {
public void observe(@Observes Foo foo)

The CDI specification itself supports both synchronous delivery of events as well as transactional observer methods which are invoked in specific points in a life-cycle of a transaction. Unlike Seam 2, where an entire event can be bound to a specific transaction phase, it’s the observer method which declares the transaction phase in case of CDI. As a result, observer method invocations for the same event may be executed in different phases of a transaction, which is not possible with Seam 2.

Asynchronous and timed delivery of events is not covered by the CDI specification. These types of event delivery can be implemented either using facilities provided by other parts of the Java EE platform (EJB) or by portable extensions.

Delivery mode Seam 2 - Raising events (observing is always same as above) CDI - Observing events (raising is always same as above)
public void observe(@Observes Foo foo)
Transaction success phase
public void observe(@Observes(during = TransactionPhase.AFTER_SUCCESS) Foo foo)
Transaction completion phase
public void observe(@Observes(during = TransactionPhase.AFTER_COMPLETION) Foo foo)
No direct alternative. Can be implemented using EJB @Asynchronous methods.
public clazz FooObserver {

   public void observe(@Observes Foo foo)
   .raiseTimedEvent(“foo”, new Schedule(1000l));
No direct alternative. Can be implemented using EJB TimerService.


In the Java EE specification version 6, the concept of interceptors was extracted into a separate specification. As a result, not only EJBs but any CDI-managed beans can benefit from this facility.

If you used interceptors in Seam 2, migration is very straightforward. The names and semantics of most of the annotations remain unchanged. If you used meta annotations to bind interceptors to your beans in Seam 2, this idea (slightly modified) made it into the specification and is now know as an interceptor binding.

Note that:

  • It’s not possible to declare relative ordering of interceptors anymore (if my interceptor should be invoked before or after another interceptor). Interceptors must be globally activated and ordered in the beans.xml file.
  • Stateless interceptors - the performance optimization Seam 2 used is not supported in CDI. Interceptors always share the life cycle with the bean they intercept.