Java EE CDI - Inject beans from external (3rd party) libraries example

23 June 2013
By Gonçalo Marques
In this tutorial we will see how to inject beans from external - or 3d party - libraries in Java EE CDI

Introduction

When we need an external JAR to be scanned by a Java EE container for CDI beans we must define the JAR as a target for CDI bean scanning, ie. via beans.xml file. What if the JAR is provided by an external - or 3d party - entity?

It may not be suitable at all to modify the 3rd party JAR in what matters to library maintenance for future versions compatibility. In this tutorial we will see how we can overcome this restriction and inject beans from 3d party libraries.

This tutorial considers the following environment:

  1. JDK 1.7.0.21
  2. Weld 1.1.10

Weld is the CDI reference implementation

Injecting a simple bean from a 3rd party library

We start this tutorial by showing how we may inject a SimpleEmail instance from Apache Commons Email library. Usually one creates a SimpleEmail instance like the following:

Creating a SimpleEmail instance

SimpleEmail simpleEmail = new SimpleEmail();

What if we want to be able to inject SimpleEmail bean instances by using the @Inject annotation? We may write a producer method to achieve this goal:

SimpleEmail producer

package com.byteslounge.cdi.producer;

import javax.enterprise.inject.Produces;

import org.apache.commons.mail.SimpleEmail;

public class CommonsEmailProducer {

  @Produces
  public SimpleEmail simpleEmailProducer(){
    return new SimpleEmail();
  }
  
}

Now we may inject the SimpleEmail bean in a CDI fashion:

Injecting SimpleEmail bean

@Inject
private SimpleEmail simpleEmail;



If you are not familiar with CDI producer methods you should also read the following tutorial: Java EE CDI Producer methods tutorial.

Passing initialization parameters

We may also need to pass initialization parameters to external library beans. Supposing we want to enable injection of FTPClient beans from Apache Commons Net library. We may give the ability for bean clients to specify the FTP server hostname, obtaining an already connected FTPClient instance.

We start to specify an annotation to be used along with bean injection:

CommonsFtpHostname annotation

package com.byteslounge.cdi.producer;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(FIELD)
public @interface CommonsFtpHostname {

  String value();

}

Now a CDI producer method that creates FTPClient instances taking the annotation into account:

FTPClient producer

package com.byteslounge.cdi.producer;

import java.io.IOException;
import java.net.SocketException;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;

import org.apache.commons.net.ftp.FTPClient;

public class CommonsNetProducer {

  @Produces
  public FTPClient ftpClientProducer(InjectionPoint ip) 
    throws SocketException, IOException{
    
    Annotated annotated = ip.getAnnotated();
    FTPClient ftpClient = new FTPClient();
    
    // Get annotation
    CommonsFtpHostname commonsFtpHostname = 
      annotated.getAnnotation(CommonsFtpHostname.class);
    
    // If FTP server hostname was supplied we
    // provide an already connected FTP client
    if(commonsFtpHostname != null){
      ftpClient.connect(commonsFtpHostname.value());
    }
    
    return ftpClient;
  }
  
}

Now we may inject the FTPClient bean while specifying the server hostname:

Injecting FTPClient bean

@Inject
@CommonsFtpHostname(value = "ftp.domain.com")
private FTPClient ftpClient;



Note: The just mentioned FTPClient producer is used as an example of initialization parameters for this tutorial. If this was a real scenario we should take care of closing the connection after usage. This could be done using CDI disposer methods as mentioned in: Java EE CDI Disposer methods example.

A very common use case

There is a very common use case of 3rd party library bean injection that consists in injecting a Logger instance. The producer may look like the following:

Logger producer

package com.byteslounge.cdi.producer;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggerProducer {

  @Produces
  public Logger loggerProducer(InjectionPoint ip){
    return LoggerFactory.getLogger(
      ip.getMember().getDeclaringClass().getName());
  }
}

Now we may inject the Logger simply as:

Injecting the Logger

@Inject
private Logger logger;

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: