Raedwald
Raedwald

Reputation: 48712

EJB3Unit demands a business interface for @LocalBean

I'm trying to get to grips with EJB3Unit, to unit test an EJB 3.1 stateless bean, but EJB3Unit complains because my EJB does not have a "business interface". But I thought all this "business interface" stuff was a relic of EJB 2, so I should not need it. Is this because I'm using EJB3Unit incorrectly? What do I have to do to get EJB3Unit to work for my unit test?

My EJB is essentially this:

package uk.co.nildram.badamson.aoc4;

@Stateless
@LocalBean
public class AocService {

   @PersistenceContext(unitName = "aoc4")
   private EntityManager entityManager;

   // Other code
}

My unit test class is essentially this:

package uk.co.nildram.badamson.aoc4;

public final class AocServiceTest extends BaseSessionBeanFixture<AocService> {

   private static final Class<?>[] USED_ENTITY_BEANS = {};

   public AocServiceTest() {
      super(AocService.class, USED_ENTITY_BEANS);
   }

   @Test
   public void testCreateSessionBean() {
      final AocService bean = getBeanToTest();
      checkInvariants(bean);
   }

   public static void checkInvariants(final AocService service) {
      // assertions
   }

   // Other code

}

The unit tests fail because of the following exception:

 java.lang.IllegalStateException: No business interface found on class 'uk/co/nildram/badamson/aoc4/AocService'.
at  com.bm.ejb3metadata.annotations.helper.bean.session.SessionBusinessInterfaceFinder.resolve(SessionBusinessInterfaceFinder.java:86)
at com.bm.ejb3metadata.annotations.helper.bean.SessionBeanHelper.resolve(SessionBeanHelper.java:69)
at com.bm.ejb3metadata.annotations.helper.ResolverHelper.resolve(ResolverHelper.java:91)
at com.bm.ejb3metadata.MetadataAnalyzer.analyze(MetadataAnalyzer.java:82)
at com.bm.ejb3metadata.MetadataAnalyzer.analyzeClasses(MetadataAnalyzer.java:49)
at com.bm.ejb3metadata.MetadataAnalyzer.initialize(MetadataAnalyzer.java:36)
at com.bm.ejb3metadata.annotations.metadata.MetaDataCache.getMetaData(MetaDataCache.java:129)
at com.bm.ejb3metadata.annotations.metadata.MetaDataCache.getDynamicModuleCreator(MetaDataCache.java:105)
at com.bm.creators.SessionBeanFactory.getInjector(SessionBeanFactory.java:78)
at com.bm.creators.SessionBeanFactory.createSessionBean(SessionBeanFactory.java:60)
at com.bm.testsuite.BaseSessionBeanFixture.setUp(BaseSessionBeanFixture.java:92)
at junit.framework.TestCase.runBare(TestCase.java:132)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

The code throwing the exception seems to be http://ejb3unit.sourceforge.net/xref/com/bm/ejb3metadata/annotations/helper/bean/session/SessionBusinessInterfaceFinder.html. That indeed seems to be demanding a "javax/ejb" interface. But I have a @LocalBean, so my class should not require any interfaces.

Upvotes: 2

Views: 1805

Answers (1)

Mikko Maunu
Mikko Maunu

Reputation: 42114

Remote and local business interface are part of EJB 3.x (introduced in EJB 3.0), not relic from EJB 2.x. What you are referencing as relic is maybe EJB 2.x remote and local home interfaces - those ones that forced to extend javax.ejb.EJBHome/EJBLocalHome and forced to provide create-methods.

You use concept of no-interface view (no separate business interfaces) which is part of EJB 3.1 and EJB3Unit supports only EJB 3.0 and that's why it doesn't work. You need interface that is annoted with @Local or @Remote and make AocService to implement it and then use AocService via it's interface.

EJB 3.1 specification uses following terminology:

Terminology note: This specification uses the term remote business interface to refer to the business interface of an EJB 3.x session bean that supports remote access. The term remote interface is used to refer to the remote component interface of the EJB 2.1 client view. The term local business interface refers to the local business interface of an EJB 3.x session bean that supports local access. The term local interface is used to refer to the local component interface of the EJB 2.1 client view.

Example with EJB 3.x remote business interface, local business interface and no-interface view:

@javax.ejb.Local
public interface LocalBusinessInterface {
}

@javax.ejb.Remote
public interface RemoteBusinessInterface {
}

//@LocalBean is annotation that was introduced in EJB 3.1
//according Javadoc it "Designates that a session bean exposes a 
//no-interface view."
//When bean does not implement other interfaces, using @LocalBean
//is redundant, because beans without any interfaces expose no-interface view
//by default.
@LocalBean
@Stateless
public class BeanImplementation 
    implements LocalBusinessInterface, RemoteBusinessInterface {
}

Upvotes: 2

Related Questions