EJB 3.0 Injecting The Correct Implementation

When using stateless and stateful session beans I often find that I’m creating one interface per one implementation, which will be enhanced with the release of the 3.1 spec and implicit interfaces. Anyway on one of the occasions I had actually had multiple implementations of an interface that I wanted to inject, this made me stop and think how do I that!! It turns out it was pretty simple with a few annotations.

On your class that is implementing the interface you need to use the name attribute: –


@Stateful(name="xxx.AssetTypeOverrideService")
public class AssetTypeOverrideService implements OverrideService{

@Stateful(name="xxxRuleTypeOverrideService")
public class RuleTypeOverrideService implements OverrideService {

Then on the bean you want inject these into you use:


@EJB(beanName="xxx.AssetTypeOverrideService")
private OverrideService assetOverrideService;
	
@EJB(beanName="xxx.RuleTypeOverrideService")
private OverrideService ruleTypeOverrideService;

The name can be anything you want I just think it’s logical to keep it the same as the class and the beanName obviously is the same value of the bean you want to inject that has the correct implementation.

It seems easy now but it did make me stop and think.

Advertisements

EJB 3.0 Interceptors

I wanted to carry out some processing when an entity was committed to the db, I could of used the lifecycle annotation @PostPersist in the bean itself but that that would go against leaky abstraction (see post Non-anaemic models). Anywho it was pretty simple to get this working all that I had to use were a couple of annotations.

The first @EntityListerners which accepts an array of classes that will become your event handlers:

@EntityListeners(ErrorListener.class)
public class SystemError implements Serializable {

The next is to annotate the methods in your listener class that will handle the various events. The annotations that can be used are:

    @PrePersist Executed before the entity manager persist operation is actually executed or cascaded. This call is synchronous with the persist operation.
    @PreRemove Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
    @PostPersist Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed.
    @PostRemove Executed after the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
    @PreUpdate Executed before the database UPDATE operation.
    @PostUpdate Executed after the database UPDATE operation.
    @PostLoad Eexecuted after an entity has been loaded into the current persistence context or an entity has been refreshed.

Note that if you are using EJB dependency injection it won’t work in your listener as it’s not managed by your container buy you can use jndi: –

Context ctx = new InitialContext();
XXXService service = (XXXService) ctx.lookup("EARNAME/XXXServiceBean/local");

Joda with JPA

I have to work with a few legacy databases that are used by several different apps (apparently the database is a perfect integration point), and I want to use the Joda api in my persistence. In this example the date is actually stored as a string, genius! I’m going to use LocalDate as the string doesn’t store the time element. If you are lucky enough and the database is actually storing date time check this post out Joda With DateTime

To start with a create a simple helper class that converts String to LocalDate and LocatDate to String

public static LocalDate createLocalDateForString(String dateString){
  DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
  return StringUtils.isEmpty(value) ? null :  fmt.parseDateTime(dateString).toLocalDate();	
}
    
    public static String createStringForLocalDate(LocalDate date){
    	return date.toString("yyyyMMdd"); 
    }

Next is to create your own user type. This is done by implementing org.hibernate.usertype.UserType. The main methods I’m implement are

public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
			throws HibernateException, SQLException {
		LocalDate result = null;
		String dateAsString = rs.getString(names[0]);
		if(!rs.wasNull()){
			result = StringUtils.isNotEmpty(dateAsString) ? DateHelper.createLocalDateForString(dateAsString) : null;
		}
		return result;
	}

public void nullSafeSet(PreparedStatement statement, Object value, int index)
			throws HibernateException, SQLException {
		if(value == null){
			statement.setNull(index, SQL_TYPES[0]);
		}else{
			String dateAsString = DateHelper.createStringForLocalDate((LocalDate)value);
			statement.setString(index, dateAsString);
		}
}

All that is left is to add the annotation to each of your entity properties that you want to use as LocalDate.

@org.hibernate.annotations.Type(type = "xxx.LocalDateUserType")