SeamFramework.orgCommunity Documentation

Chapter 16. Portable extensions

16.1. The BeanManager object
16.2. The Bean interface
16.3. The Context interface

CDI is intended to be a foundation for frameworks, extensions and integration with other technologies. Therefore, CDI exposes a set of SPIs for the use of developers of portable extensions to CDI. For example, the following kinds of extensions were envisaged by the designers of CDI:

More formally, according to the spec:

A portable extension may integrate with the container by:

  • Providing its own beans, interceptors and decorators to the container

  • Injecting dependencies into its own objects using the dependency injection service

  • Providing a context implementation for a custom scope

  • Augmenting or overriding the annotation-based metadata with metadata from some other source

The nerve center for extending CDI is the BeanManager object.

The BeanManager interface lets us obtain beans, interceptors, decorators, observers and contexts programmatically.

public interface Manager {

   public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx);
   public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx);
   public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual);
   public Set<Bean<?>> getBeans(Type beanType, Annotation... bindings);
   public Set<Bean<?>> getBeans(String name);
   public <X> Bean<? extends X> getMostSpecializedBean(Bean<X> bean);
   public Bean<?> getPassivationCapableBean(String id);
   public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans);
   public void validate(InjectionPoint injectionPoint);
   public void fireEvent(Object event, Annotation... bindings);
   public <T> Set<ObserverMethod<?, T>> resolveObserverMethods(T event, Annotation... bindings);
   public List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... bindings);
   public List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings);
   public boolean isScope(Class<? extends Annotation> annotationType);
   public boolean isNormalScope(Class<? extends Annotation> annotationType);
   public boolean isPassivatingScope(Class<? extends Annotation> annotationType);
   public boolean isQualifier(Class<? extends Annotation> annotationType);
   public boolean isInterceptorBindingType(Class<? extends Annotation> annotationType);
   public boolean isStereotype(Class<? extends Annotation> annotationType);
   public Set<Annotation> getInterceptorBindingTypeDefinition(Class<? extends Annotation> bindingType);
   public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype);
   public Context getContext(Class<? extends Annotation> scopeType);
   public ELResolver getELResolver();
   public ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory);
   public <T> AnnotatedType<T> createAnnotatedType(Class<T> type);
   public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type);
}

We can obtain an instance of BeanManager via injection:

@Inject BeanManager beanManager

Java EE components may obtain an instance of BeanManager from JNDI by looking up the name java:comp/BeanManager. Any operation of BeanManager may be called at any time during the execution of the application.

Let's study some of the interfaces exposed by the BeanManager.

Instances of the interface Bean represent beans. There is an instance of Bean registered with the BeanManager object for every bean in the application.

public interface Bean<T> extends Contextual<T> {

   public Set<Type> getTypes();
   public Set<Annotation> getQualifiers();
   public Class<? extends Annotation> getScope();
   public String getName();
   public Set<Class<? extends Annotation>> getStereotypes();
   public Class<?> getBeanClass();
   public boolean isAlternative();
   public boolean isNullable();
   public Set<InjectionPoint> getInjectionPoints();
}

It's possible to implement the Bean interface and register instances by calling AfterBeanDiscovery.addBean() (AfterBeanDiscovery is a built-in event type that an extension can observe) to provide support for new kinds of beans, beyond those defined by the CDI specification. For example, we could use the Bean interface to allow objects managed by another framework to be injected into beans.

There are two subinterfaces of Bean defined by the CDI specification: Interceptor and Decorator.

The Context interface supports addition of new scopes to CDI, or extension of the built-in scopes to new environments.

public interface Context {

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

For example, we might implement Context to add a business process scope to CDI, or to add support for the conversation scope to an application that uses Wicket.