Chapter 6. Scopes and contexts

Associated with every scope type is a context object. The context object determines the lifecycle and visibility of instances of all beans with that scope. In particular, the context object defines:

The context implementation collaborates with the container via the Context and Contextual interfaces to create and destroy contextual instances.

6.1. The Contextual interface

The interface javax.enterprise.context.spi.Contextual defines operations to create and destroy contextual instances of a certain type. Any implementation of Contextual is called a contextual type. In particular, the Bean interface defined in Section 11.1, “The Bean interface” extends Contextual, so all beans are contextual types.

public interface Contextual<T> {
    public T create(CreationalContext<T> creationalContext);
    public void destroy(T instance, CreationalContext<T> creationalContext);
}
  • create() is responsible for creating new contextual instances of the type.

  • destroy() is responsible for destroying instances of the type. In particular, it is responsible for destroying all dependent objects of an instance.

If an exception occurs while creating an instance, the exception is rethrown by the create() method. If the exception is a checked exception, it must be wrapped and rethrown as an (unchecked) CreationException.

If an exception occurs while destroying an instance, the exception must be caught by the destroy() method.

If the application invokes a contextual instance after it has been destroyed, the behavior is undefined.

The container and portable extensions may define implementations of the Contextual interface that do not extend Bean, but it is not recommended that applications directly implement Contextual.

6.1.1. The CreationalContext interface

The interface javax.enterprise.context.spi.CreationalContext provides operations that are used by the Contextual implementation during instance creation and destruction.

public interface CreationalContext<T> {
    public void push(T incompleteInstance);
    public void release();
}
  • push() registers an incompletely initialized contextual instance the with the container. A contextual instance is considered incompletely initialized until it is returned by the create() method.

  • release() destroys all dependent objects, as defined in Section 6.4.1, “Dependent objects”, of the instance which is being destroyed, by passing each dependent object to the destroy() method of its Contextual object.

The implementation of Contextual is not required to call push(). However, for certain bean scopes, invocation of push() between instantiation and injection helps the container minimize the use of client proxy objects (which would otherwise be required to allow circular dependencies).

If Contextual.create() calls push(), it must also return the instance passed to push().

Contextual.create() should use the given CreationalContext when obtaining contextual references to inject, as defined in Section 6.5.3, “Contextual reference for a bean”, in order to ensure that any dependent objects are associated with the contextual instance that is being created.

Contextual.destroy() should call release() to allow the container to destroy dependent objects of the contextual instance.

6.2. The Context interface

The javax.enterprise.context.spi.Context interface provides an operation for obtaining contextual instances with a particular scope of any contextual type. Any instance of Context is called a context object.

The context object is responsible for creating and destroying contextual instances by calling operations of the Contextual interface.

The Context interface is called by the container and may be called by portable extensions. It should not be called directly by the application.

public interface Context {
    public Class<? extends Annotation> getScope();
    boolean isActive();
    public <T> T get(Contextual<T> bean);
    public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext);
}

The method getScope() returns the scope type of the context object.

At a particular point in the execution of the program a context object may be active with respect to the current thread. When a context object is active the isActive() method returns true. Otherwise, we say that the context object is inactive and the isActive() method returns false.

The get() method obtains contextual instances of the contextual type represented by the given instance of Contextual. The get() method may either:

  • return an existing instance of the given contextual type, or

  • if no CreationalContext is given, return a null value, or

  • if a CreationalContext is given, create a new instance of the given contextual type by calling Contextual.create(), passing the given CreationalContext, and return the new instance.

If the context object is inactive, the get() method must throw a ContextNotActiveException.

The get() method may not return a null value unless no CreationalContext is given, or Contextual.create() returns a null value.

The get() method may not create a new instance of the given contextual type unless a CreationalContext is given.

The context object is responsible for destroying any contextual instance it creates by passing the instance to the destroy() method of the Contextual object representing the contextual type. A destroyed instance must not subsequently be returned by the get() method.

The context object must pass the same instance of CreationalContext to Contextual.destroy() that it passed to Contextual.create() when it created the instance.

6.3. Normal scopes and pseudo-scopes

Most scopes are normal scopes. The context object for a normal scope type is a mapping from each contextual type with that scope to an instance of that contextual type. There may be no more than one mapped instance per contextual type per thread. The set of all mapped instances of contextual types with a certain scope for a certain thread is called the context for that scope associated with that thread.

A context may be associated with one or more threads. A context with a certain scope is said to propagate from one point in the execution of the program to another when the set of mapped instances of contextual types with that scope is preserved.

The context associated with the current thread is called the current context for the scope. The mapped instance of a contextual type associated with a current context is called the current instance of the contextual type.

The get() operation of the context object for an active normal scope returns the current instance of the given contextual type.

At certain points in the execution of the program a context may be destroyed. When a context is destroyed, all mapped instances belonging to that context are destroyed by passing them to the Contextual.destroy() method.

Contexts with normal scopes must obey the following rule:

Suppose beans A, B and Z all have normal scopes. Suppose A has an injection point x, and B has an injection point y. Suppose further that both x and y resolve to bean Z according to the rules of typesafe resolution. If a is the current instance of A, and b is the current instance of B, then both a.x and b.y refer to the same instance of Z. This instance is the current instance of Z.

Any scope that is not a normal scope is called a pseudo-scope. The concept of a current instance is not well-defined in the case of a pseudo-scope.

All normal scopes must be explicitly declared @NormalScope, to indicate to the container that a client proxy is required.

All pseudo-scopes must be explicitly declared @Scope, to indicate to the container that no client proxy is required.

All scopes defined by this specification, except for the @Dependent pseudo-scope, are normal scopes.

6.4. Dependent pseudo-scope

The @Dependent scope type is a pseudo-scope. Beans declared with scope type @Dependent behave differently to beans with other built-in scope types.

When a bean is declared to have @Dependent scope:

  • No injected instance of the bean is ever shared between multiple injection points.

  • Any instance of the bean injected into an object that is being created by the container is bound to the lifecycle of the newly created object.

  • When a Unified EL expression in a JSF or JSP page that refers to the bean by its EL name is evaluated, at most one instance of the bean is instantiated. This instance exists to service just a single evaluation of the EL expression. It is reused if the bean EL name appears multiple times in the EL expression, but is never reused when the EL expression is evaluated again, or when another EL expression is evaluated.

  • Any instance of the bean that receives a producer method, producer field, disposer method or observer method invocation exists to service that invocation only.

  • Any instance of the bean injected into method parameters of a disposer method or observer method exists to service the method invocation only (except for observer methods of container lifecycle events).

Every invocation of the get() operation of the Context object for the @Dependent scope with a CreationalContext returns a new instance of the given bean.

Every invocation of the get() operation of the Context object for the @Dependent scope with no CreationalContext returns a null value.

The @Dependent scope is always active.

6.4.1. Dependent objects

Many instances of beans with scope @Dependent belong to some other bean or Java EE component class instance and are called dependent objects.

  • Instances of decorators and interceptors are dependent objects of the bean instance they decorate.

  • An instance of a bean with scope @Dependent injected into a field, bean constructor or initializer method is a dependent object of the bean or Java EE component class instance into which it was injected.

  • An instance of a bean with scope @Dependent injected into a producer method is a dependent object of the producer method bean instance that is being produced.

  • An instance of a bean with scope @Dependent obtained by direct invocation of an Instance is a dependent object of the instance of Instance.

6.4.2. Destruction of objects with scope @Dependent

Dependent objects of a contextual instance are destroyed when Contextual.destroy() calls CreationalContext.release(), as defined in Section 6.1.1, “The CreationalContext interface”.

Additionally, the container must ensure that:

  • all dependent objects of a non-contextual instance of a bean or other Java EE component class are destroyed when the instance is destroyed by the container,

  • all @Dependent scoped contextual instances injected into method parameters of an observer method of any container lifecycle event, as defined in Section 11.5, “Container lifecycle events”, is destroyed after all observers of the BeforeShutdown event complete,

  • all @Dependent scoped contextual instances injected into method parameters of a disposer method or observer method of any other event are destroyed when the invocation completes,

  • any @Dependent scoped contextual instance created to receive a producer method, producer field, disposer method or observer method invocation is destroyed when the invocation completes, and

  • all @Dependent scoped contextual instances created during evaluation of a Unified EL expression in a JSP or JSF page are destroyed when the evaluation completes.

Finally, the container is permitted to destroy any @Dependent scoped contextual instance at any time if the instance is no longer referenced by the application (excluding weak, soft and phantom references).

6.4.3. Dependent pseudo-scope and Unified EL

Suppose a Unified EL expression in a JSF or JSP page refers to a bean with scope @Dependent by its EL name. Each time the EL expression is evaluated:

  • the bean is instantiated at most once, and

  • the resulting instance is reused for every appearance of the EL name, and

  • the resulting instance is destroyed when the evaluation completes.

Portable extensions that integrate with the container via Unified EL should also ensure that these rules are enforced.

6.5. Contextual instances and contextual references

The Context object is the ultimate source of the contextual instances that underly contextual references.

6.5.1. The active context object for a scope

From time to time, the container must obtain an active context object for a certain scope type. The container must search for an active instance of Context associated with the scope type.

  • If no active context object exists for the scope type, the container throws a ContextNotActiveException.

  • If more than one active context object exists for the given scope type, the container must throw an IllegalStateException.

If there is exactly one active instance of Context associated with the scope type, we say that the scope is active.

6.5.2. Contextual instance of a bean

From time to time, the container must obtain a contextual instance of a bean. The container must:

  • obtain the active context object for the bean scope, then

  • obtain an instance of the bean by calling Context.get(), passing the Bean instance representing the bean and an instance of CreationalContext.

From time to time, the container attempts to obtain a contextual instance of a bean that already exists, without creating a new contextual instance. The container must determine if the scope of the bean is active and if it is:

  • obtain the active context object for the bean scope, then

  • attempt to obtain an existing instance of the bean by calling Context.get(), passing the Bean instance representing the bean without passing any instance of CreationalContext.

If the scope is not active, or if Context.get() returns a null value, there is no contextual instance that already exists.

A contextual instance of any of the built-in kinds of bean defined in Chapter 3, Programming model is considered an internal container construct, and it is therefore not strictly required that a contextual instance of a built-in kind of bean directly implement the bean types of the bean. However, in this case, the container is required to transform its internal representation to an object that does implement the bean types expected by the application before injecting or returning a contextual instance to the application.

For a custom implementation of the Bean interface defined in Section 11.1, “The Bean interface”, the container calls getScope() to determine the bean scope.

6.5.3. Contextual reference for a bean

From time to time, the container must obtain a contextual reference for a bean and a given bean type of the bean. A contextual reference implements the given bean type and all bean types of the bean which are Java interfaces. A contextual reference is not, in general, required to implement all concrete bean types of the bean.

Contextual references must be obtained with a given CreationalContext, allowing any instance of scope @Dependent that is created to be later destroyed.

  • If the bean has a normal scope and the given bean type cannot be proxied by the container, as defined in Section 5.4.1, “Unproxyable bean types”, the container throws an UnproxyableResolutionException.

  • If the bean has a normal scope, then the contextual reference for the bean is a client proxy, as defined in Section 5.4, “Client proxies”, created by the container, that implements the given bean type and all bean types of the bean which are Java interfaces.

  • Otherwise, if the bean has a pseudo-scope, the container must obtain a contextual instance of the bean. If the bean has scope @Dependent, the container must associate it with the CreationalContext.

The container must ensure that every injection point of type InjectionPoint and qualifier @Default of any dependent object instantiated during this process receives:

  • an instance of InjectionPoint representing the injection point into which the dependent object will be injected, or

  • a null value if it is not being injected into any injection point.

6.5.4. Contextual reference validity

A contextual reference for a bean is valid only for a certain period of time. The application should not invoke a method of an invalid reference.

The validity of a contextual reference for a bean depends upon whether the scope of the bean is a normal scope or a pseudo-scope.

  • Any reference to a bean with a normal scope is valid as long as the application maintains a hard reference to it. However, it may only be invoked when the context associated with the normal scope is active. If it is invoked when the context is inactive, a ContextNotActiveException is thrown by the container.

  • Any reference to a bean with a pseudo-scope (such as @Dependent) is valid until the bean instance to which it refers is destroyed. It may be invoked even if the context associated with the pseudo-scope is not active. If the application invokes a method of a reference to an instance that has already been destroyed, the behavior is undefined.

6.5.5. Injectable references

From time to time, the container must obtain an injectable reference for an injection point. The container must:

For certain combinations of scopes, the container is permitted to optimize the above procedure:

However, in performing these optimizations, the container must respect the rules of injectable reference validity.

6.5.6. Injectable reference validity

Injectable references to a bean must respect the rules of contextual reference validity, with the following exceptions:

  • A reference to a bean injected into a field, bean constructor or initializer method is only valid until the object into which it was injected is destroyed.

  • A reference to a bean injected into a producer method is only valid until the producer method bean instance that is being produced is destroyed.

  • A reference to a bean injected into a disposer method or observer method is only valid until the invocation of the method completes.

The application should not invoke a method of an invalid injected reference. If the application invokes a method of an invalid injected reference, the behavior is undefined.

6.6. Passivation and passivating scopes

The temporary transfer of the state of an idle object held in memory to some form of secondary storage is called passivation. The transfer of the passivated state back into memory is called activation.

6.6.1. Passivation capable beans

A bean is called passivation capable if the container is able to temporarily transfer the state of any idle instance to secondary storage.

  • As defined by the EJB specification, all stateful session beans are passivation capable. Stateless and singleton session beans are not passivation capable.

  • A managed bean is passivation capable if and only if the bean class is serializable and all interceptors and decorators of the bean are serializable.

  • A producer method is passivation capable if and only if it never returns a value which is not passivation capable at runtime. A producer method with a primitive return type or a return type that implements or extends Serializable is passivation capable. A producer method with a return type that is declared final and does not implement Serializable is not passivation capable.

  • A producer field is passivation capable if and only if it never refers to a value which is not passivation capable at runtime. A producer field with a primitive type or a type that implements or extends Serializable is passivation capable. A producer field with a type that is declared final and does not implement Serializable is not passivation capable.

A custom implementation of Bean is passivation capable if it implements the interface PassivationCapable. An implementation of Contextual that is not a bean is passivation capable if it implements both PassivationCapable and Serializable.

public interface PassivationCapable {
    public String getId();
}

The getId() method must return a value that uniquely identifies the instance of Bean or Contextual. It is recommended that the string contain the package name of the class that implements Bean or Contextual.

6.6.2. Passivation capable dependencies

A bean is called a passivation capable dependency if any contextual reference for that bean is preserved when the object holding the reference is passivated and then activated.

The container must guarantee that:

  • all session beans are passivation capable dependencies,

  • all beans with normal scope are passivation capable dependencies,

  • all passivation capable beans with scope @Dependent are passivation capable dependencies,

  • all resources are passivation capable dependencies, and

  • the built-in beans of type Instance, Event, InjectionPoint and BeanManager are passivation capable dependencies.

A custom implementation of Bean is a passivation capable dependency if it implements PassivationCapable or if getScope() returns a normal scope type.

6.6.3. Passivating scopes

A passivating scope requires that:

  • beans with the scope are passivation capable, and

  • implementations of Contextual passed to any context object for the scope are passivation capable.

Passivating scopes must be explicitly declared @NormalScope(passivating=true).

For example, the built-in session and conversation scopes defined in Section 6.7, “Context management for built-in scopes” are passivating scopes. No other built-in scopes are passivating scopes.

6.6.4. Validation of passivation capable beans and dependencies

For every bean which declares a passivating scope, and for every stateful session bean, the container must validate that the bean truly is passivation capable and that, in addition, its dependencies are passivation capable.

If a managed bean which declares a passivating scope:

  • is not passivation capable,

  • has a non-transient injected field, bean constructor parameter or initializer method parameter that does not resolve to a passivation capable dependency, or

  • has an interceptor or decorator with a non-transient injected field, bean constructor parameter or initializer method parameter that does not resolve to a passivation capable dependency,

then the container automatically detects the problem and treats it as a deployment problem.

If a stateful session bean:

  • has a non-transient injected field, bean constructor parameter or initializer method parameter that does not resolve to a passivation capable dependency, or

  • has an interceptor or decorator with a non-transient injected field, bean constructor parameter or initializer method parameter that does not resolve to a passivation capable dependency,

then the container automatically detects the problem and treats it as a deployment problem.

If a producer method declares a passivating scope and:

  • the container is able to determine that it is not passivation capable by inspecting its return type, or

  • has a parameter that does not resolve to a passivation capable dependency,

then the container automatically detects the problem and treats it as a deployment problem.

If a producer field declares a passivating scope and:

  • the container is able to determine that it is not passivation capable by inspecting its type,

then the container automatically detects the problem and treats it as a deployment problem.

In some cases, the container is not able to determine whether a producer method or field is passivation capable. If a producer method or field which declares a passivating scope returns an unserializable object at runtime, the container must throw an IllegalProductException. If a producer method or field of scope @Dependent returns an unserializable object for injection into an injection point that requires a passivation capable dependency, the container must throw an IllegalProductException

For a custom implementation of Bean, the container calls getInjectionPoints() to determine the injection points, and InjectionPoint.isTransient() to determine whether the injection point is a transient field.

If a bean which declares a passivating scope type, or any stateful session bean, has a decorator which is not a passivation capable dependency, the container automatically detects the problem and treats it as a deployment problem.

6.7. Context management for built-in scopes

The container provides an implementation of the Context interface for each of the built-in scopes.

The built-in context object is active during servlet, web service and EJB invocations, or in the case of the conversation context object, for JSF requests. For other kinds of invocations, a portable extension may define a custom context object for any or all of the built-in scopes. For example, a third-party web application framework might provide a conversation context object for the built-in conversation scope.

The context associated with a built-in normal scope propagates across local, synchronous Java method calls, including invocation of EJB local business methods. The context does not propagate across remote method invocations or to asynchronous processes such as JMS message listeners or EJB timer service timeouts.

6.7.1. Request context lifecycle

The request context is provided by a built-in context object for the built-in scope type @RequestScoped. The request scope is active:

  • during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the container calls any ServletRequestListener or AsyncListener,

  • during any Java EE web service invocation,

  • during any asynchronous observer method notification,

  • during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB timeout method and during message delivery to any EJB message-driven bean, and

  • during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment.

The request context is destroyed:

  • at the end of the servlet request, after the service() method, all doFilter() methods, and all requestDestroyed() and onComplete() notifications return,

  • after the web service invocation completes,

  • after the asynchronous observer notification completes,

  • after the EJB remote method invocation, asynchronous method invocation, timeout or message delivery completes, or

  • after the message delivery to the MessageListener completes.

6.7.2. Session context lifecycle

The session context is provided by a built-in context object for the built-in passivating scope type @SessionScoped. The session scope is active:

  • during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the container calls any HttpSessionListener, AsyncListener or ServletRequestListener.

The session context is shared between all servlet requests that occur in the same HTTP session. The session context is destroyed when the HTTPSession times out, after all HttpSessionListeners have been called, and at the very end of any request in which invalidate() was called, after all filters and ServletRequestListeners have been called.

6.7.3. Application context lifecycle

The application context is provided by a built-in context object for the built-in scope type @ApplicationScoped. The application scope is active:

  • during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the container calls any ServletContextListener, HttpSessionListener, AsyncListener or ServletRequestListener,

  • during any Java EE web service invocation,

  • during any asynchronous observer method notification,

  • during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB timeout method and during message delivery to any EJB message-driven bean,

  • during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment, and

  • when the disposer method or @PreDestroy callback of any bean with any normal scope other than @ApplicationScoped is called.

The application context is shared between all servlet requests, asynchronous observer method notifications, web service invocations, EJB remote method invocations, EJB asynchronous method invocations, EJB timeouts and message deliveries to message-driven beans that execute within the same application. The application context is destroyed when the application is shut down.

6.7.4. Conversation context lifecycle

The conversation context is provided by a built-in context object for the built-in passivating scope type @ConversationScoped. The conversation scope is active:

  • during all standard lifecycle phases of any JSF faces or non-faces request.

The conversation context provides access to state associated with a particular conversation. Every JSF request has an associated conversation. This association is managed automatically by the container according to the following rules:

  • Any JSF request has exactly one associated conversation.

  • The conversation associated with a JSF request is determined at the beginning of the restore view phase and does not change during the request.

Any conversation is in one of two states: transient or long-running.

  • By default, a conversation is transient

  • A transient conversation may be marked long-running by calling Conversation.begin()

  • A long-running conversation may be marked transient by calling Conversation.end()

All long-running conversations have a string-valued unique identifier, which may be set by the application when the conversation is marked long-running, or generated by the container.

If the conversation associated with the current JSF request is in the transient state at the end of a JSF request, it is destroyed, and the conversation context is also destroyed.

If the conversation associated with the current JSF request is in the long-running state at the end of a JSF request, it is not destroyed. Instead, it may be propagated to other requests according to the following rules:

  • The long-running conversation context associated with a request that renders a JSF view is automatically propagated to any faces request (JSF form submission) that originates from that rendered page.

  • The long-running conversation context associated with a request that results in a JSF redirect (a redirect resulting from a navigation rule or JSF NavigationHandler) is automatically propagated to the resulting non-faces request, and to any other subsequent request to the same URL. This is accomplished via use of a GET request parameter named cid containing the unique identifier of the conversation.

  • The long-running conversation associated with a request may be propagated to any non-faces request via use of a GET request parameter named cid containing the unique identifier of the conversation. In this case, the application must manage this request parameter.

When no conversation is propagated to a JSF request, the request is associated with a new transient conversation.

All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries.

In the following cases, a propagated long-running conversation cannot be restored and reassociated with the request:

  • When the HTTP servlet session is invalidated, all long-running conversation contexts created during the current session are destroyed, after the servlet service() method completes.

  • The container is permitted to arbitrarily destroy any long-running conversation that is associated with no current JSF request, in order to conserve resources.

The conversation timeout, which may be specified by calling Conversation.setTimeout() is a hint to the container that a conversation should not be destroyed if it has been active within the last given interval in milliseconds.

If the propagated conversation cannot be restored, the container must associate the request with a new transient conversation and throw an exception of type javax.enterprise.context.NonexistentConversationException from the restore view phase of the JSF lifecycle. The application may handle this exception using the JSF ExceptionHandler.

The container ensures that a long-running conversation may be associated with at most one request at a time, by blocking or rejecting concurrent requests. If the container rejects a request, it must associate the request with a new transient conversation and throw an exception of type javax.enterprise.context.BusyConversationException from the restore view phase of the JSF lifecycle. The application may handle this exception using the JSF ExceptionHandler.

6.7.5. The Conversation interface

The container provides a built-in bean with bean type Conversation, scope @RequestScoped, and qualifier @Default, named javax.enterprise.context.conversation.

public interface Conversation {
   public void begin();
   public void begin(String id);
   public void end();
   public String getId();
   public long getTimeout();
   public void setTimeout(long milliseconds);
   public boolean isTransient();
}
  • begin() marks the current transient conversation long-running. A conversation identifier may, optionally, be specified. If no conversation identifier is specified, an identifier is generated by the container.

  • end() marks the current long-running conversation transient.

  • getId() returns the identifier of the current long-running conversation, or a null value if the current conversation is transient.

  • getTimeout() returns the timeout, in milliseconds, of the current conversation.

  • setTimeout() sets the timeout of the current conversation.

  • isTransient() returns true if the conversation is marked transient, or false if it is marked long-running.

If any method of Conversation is called when the conversation scope is not active, a ContextNotActiveException is thrown.

If end() is called, and the current conversation is marked transient, an IllegalStateException is thrown.

If begin() is called, and the current conversation is already marked long-running, an IllegalStateException is thrown.

If begin() is called with an explicit conversation identifier, and a long-running conversation with that identifier already exists, an IllegalArgumentException is thrown.