How to use Container Dependency Injection in a RAP application

How to use Container Dependency Injection in a RAP application

Container Dependency Injection (CDI) allows us to inject one or more components (or services) into a dependent object. Usually it makes the code cleaner, as it separates the creation of the injected objects from the component’s own behavior. Recently I’ve made a simple RAP standalone application to play together with CDI without problems. First, let’s create our RAP entry point class:

<pre lang="java">public class HelloWorld extends AbstractEntryPoint {
  @Inject
  private EJBService ejbService;
  @Override
  public void createContents( Composite parent ) {
    Label label = new Label( parent, SWT.NONE );
    label.setText( ejbService.sayHello() );
  }
}</pre>

The entry point class is using an injected EJB service. The code of the service is simple:

<pre lang="java">@Stateless
public class EJBService {
  public String sayHello() {
    return "Hello World from EJB-Service";
  }
}</pre>

The last and the most important class is the application configuration. Usually, it looks like this:

<pre lang="java">public class HelloWorldConfiguration implements ApplicationConfiguration {
  public void configure( Application application ) {
    Map<String, String> properties = new HashMap<String, String>();
    properties.put( WebClient.PAGE_TITLE, "Simple RAP CDI Example" );
    application.setOperationMode( OperationMode.JEE_COMPATIBILITY );
    application.addEntryPoint( "/hello", HelloWorld.class, null );
  }
}</pre>

Unfortunately, the dependency injection is not working and the ejbService is always null. What is the problem? In order to make the dependency injection operational, the instance of entry point must be created with BeanManager. RAP provides a not so commonly known interface EntryPointFactory, which can be used to customize the creation of the entry point. Instead of adding entry point by its class, we will use EntryPointFactory. Our application configuration is changed to:

<pre lang="java">public class HelloWorldConfiguration implements ApplicationConfiguration {
  public void configure( Application application ) {
    Map<String, String> properties = new HashMap<String, String>();
    properties.put( WebClient.PAGE_TITLE, "Simple RAP CDI Example" );
    application.setOperationMode( OperationMode.JEE_COMPATIBILITY );
    application.addEntryPoint( "/hello", new CDIEntryPointFactory(), null );
  }
}</pre>

where CDIEntryPointFactory is using BeanManager to create the instance of the entry point.

<pre lang="java">public class CDIEntryPointFactory implements EntryPointFactory {
  private final BeanManager manager;
  public CDIEntryPointFactory() {
    manager = getBeanManager();
  }
  @SuppressWarnings("unchecked")
  @Override
  public EntryPoint create() {
    if( manager != null ) {
      Set<Bean<?>> beans = manager.getBeans( HelloWorld.class );
      Bean bean = ( Bean )manager.resolve( beans );
      CreationalContext context = manager.createCreationalContext( bean );
      return ( HelloWorld )manager.getReference( bean,
                                                 bean.getBeanClass(),
                                                 context );
    }
    return null;
  }
  private BeanManager getBeanManager() {
    try {
      InitialContext context = new InitialContext();
      return ( BeanManager )context.lookup( "java:comp/BeanManager" );
    } catch( Exception ex ) {
    }
    return null;
  }
}</pre>

The code above is tested in WildFly 8.2.

RAP 3.0 will be released together with Eclipse Mars in June 2015.
Stay in the loop! Follow @EclipseSource on Twitter.

No Comments

Sorry, the comment form is closed at this time.