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
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:
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:
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) |
TODO
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.
TODO
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:
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 | @Install(false) |
@Vetoor @Alternative |
installation dependencies | @Install(dependencies = "foo") |
@Requires("javax.persistence.EntityManager")Note that class-level dependencies are supported only |
bean selection based component ordering (precedence) | @Install(precedence = MOCK) |
@Alternativeor Alternative stereotype or @Specializes |
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:
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
See the CDI specification for more details.
Seam 2 provides a consistent use of the Expression Language within Java code. EL expressions can be used in
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.
log.info(expressions.evaluateMethodExpression("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.
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.
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.
@RequestParameter 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 | @Logger(“foo.bar”) private Log log; |
@Inject @Category(“foo.bar”) 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:
Besides the traditional approach to logging, Solder provides support for typed loggers
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.
Seam 2 provides an XML configuration layer that allows:
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:
The configuration can either be specified directly in the beans.xml file or in a file called seam-beans.xml.
Seam 2 configuration can be overridden using property settings. These settings can be read from system properties, servlet context parameters and the seam.properties 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 | Events.instance().raiseEvent(“foo”); |
@Inject private Event<Foo> event; // in code event.fire(new Foo()); |
Observing an event | @Observer("foo") 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) |
---|---|---|
Synchronous | Events.instance() .raiseEvent(“foo”); |
public void observe(@Observes Foo foo) { } |
Transaction success phase | Events.instance() .raiseTransactionSuccessEvent(“foo”); |
public void observe(@Observes(during = TransactionPhase.AFTER_SUCCESS) Foo foo) { } |
Transaction completion phase | Events.instance() .raiseTransactionCompletionEvent(“foo”); |
public void observe(@Observes(during = TransactionPhase.AFTER_COMPLETION) Foo foo) { } |
Asynchronous | Events.instance() .raiseTransactionCompletionEvent(“foo”); |
No direct alternative. Can be implemented using EJB @Asynchronous methods. @Stateless public clazz FooObserver { @Asynchronous public void observe(@Observes Foo foo) { } } |
Timed | Events.instance() .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: