You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by Paul Spencer <pa...@mindspring.com> on 2007/11/25 04:45:54 UTC

Problems getting EJB via annotation in test class.

I am trying to test an EJB3 using annotation.  The problem is the 
injected value is always null.  In my junit test, I setup the OpenEJB 
environment, and then get the EJB via a JNDI lookup and then via an 
annotated test class.  The JNDI lookup always works.

I suspect this is a simple configuration error, but I am not sure where 
the error is.

Below are copies of the tests, maven pom, and annotated test class.

Suggestions?

Paul Spencer

***
* pom.xml
***
<project>
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.foo.helloworld</groupId>
     <artifactId>helloworld-master-pom</artifactId>
     <version>1.0-SNAPSHOT</version>
     <relativePath>../helloworld/pom.xml</relativePath>
   </parent>
   <artifactId>helloworld-ejb</artifactId>
   <name>Hello World EJB</name>
   <packaging>ejb</packaging>

   <build>
   <plugins>
     <plugin>
     <artifactId>maven-ejb-plugin</artifactId>
     <configuration>
       <ejbVersion>3.0</ejbVersion>
       <generateClient>true</generateClient>
     </configuration>
     </plugin>
   </plugins>
   </build>
   <dependencies>
     <dependency>
       <groupId>org.apache.openejb</groupId>
       <artifactId>openejb-ejbd</artifactId>
       <version>3.0.0-SNAPSHOT</version>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.openejb</groupId>
       <artifactId>openejb-core</artifactId>
       <version>3.0.0-SNAPSHOT</version>
       <scope>test</scope>
     </dependency>

   </dependencies>
   <repositories>
     <repository>
       <id>openejb-3rdparty-builds</id>
       <name>3rd Party Build Repository</name>
       <url>http://svn.apache.org/repos/asf/openejb/repo/</url>
       <releases>
         <enabled>true</enabled>
       </releases>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
     </repository>
     <repository>
       <id>Apache Snapshot Repo</id>
       <name>Apache Snapshot Repo</name>
       <url>http://people.apache.org/repo/m2-snapshot-repository/</url>
       <releases>
         <enabled>true</enabled>
       </releases>
       <snapshots>
         <enabled>true</enabled>
       </snapshots>
     </repository>
   </repositories>
</project>



***
* Annotated test class
***
class MyTestClass {
		@EJB
		CompanyAdminLocal localBean;

		@EJB(name="CompanyAdminImplRemote")
		CompanyAdminRemote remoteBean;

		@EJB
		CompanyAdminImpl defaultBean;

		public CompanyAdminLocal getLocalBean() {
			return localBean;
		}

		public CompanyAdminRemote getRemoteBean() {
			return remoteBean;
		}

		public CompanyAdmin getDefaultBean() {
			return defaultBean;
		}

	}

***
* Unit Test
***
public class CompanyAdminBeanEjbTest extends TestCase {
	InitialContext localContext;
	InitialContext remoteContext;

	protected void setUp() throws Exception {
		Properties properties = new Properties();
		properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
				"org.apache.openejb.client.LocalInitialContextFactory");
		properties.setProperty("openejb.deployments.classpath.include",
				".*beans.*");
		properties.setProperty("openejb.deployments.classpath.exclude",
				".*telephone.*");
		properties.setProperty("openejb.embedded.remotable", "true");

		new InitialContext(properties);
		Properties localProperties = new Properties();
		localProperties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
				"org.apache.openejb.client.LocalInitialContextFactory");
		localContext = new InitialContext(localProperties);

		Properties remoteProperties = new Properties();
		remoteProperties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
				"org.apache.openejb.client.LocalInitialContextFactory");
		remoteContext = new InitialContext(remoteProperties);
	}

	public void testLocalCompanyAdminBean() throws Exception {

		CompanyAdmin companyAdmin = (CompanyAdmin) localContext
				.lookup("CompanyAdminImplLocal");
		assertNotNull("Has CompanyAdminBean", companyAdmin);
	}

	public void testRemoteCompanyAdminBean() throws Exception {

		CompanyAdmin companyAdmin = (CompanyAdmin) remoteContext
				.lookup("CompanyAdminImplRemote");
		assertNotNull("Has CompanyAdminBean", companyAdmin);
	}

	public void testLocalMyTestClass() throws Exception {

		MyTestClass testClass = new MyTestClass();
		assertNotNull("Has local bean", testClass.getLocalBean());
	}

	public void testRemoteMyTestClass() throws Exception {

		MyTestClass testClass = new MyTestClass();
		assertNotNull("Has Remote bean", testClass.getRemoteBean());
	}

	public void testDefaultMyTestClass() throws Exception {

		MyTestClass testClass = new MyTestClass();
		assertNotNull("Has Remote bean", testClass.getDefaultBean());
	}

	public void testCompanyName() throws Exception {

		CompanyAdminLocal companyAdmin = (CompanyAdminLocal) localContext
				.lookup("CompanyAdminBean");

		String newName = "New Company Name";
		companyAdmin.setCompanyName(newName);
		assertEquals("Company Name", newName, companyAdmin.getCompanyName());
	}
}

Re: Problems getting EJB via annotation in test class.

Posted by David Blevins <da...@visi.com>.
Thanks Jacek!

-David

On Nov 26, 2007, at 1:27 PM, Jacek Laskowski wrote:

> On Nov 26, 2007 10:21 PM, Paul Spencer <pa...@mindspring.com>  
> wrote:
>
>> Right now just the knowledge of how things work is enough.
>
> You can track it in http://issues.apache.org/jira/browse/OPENEJB-728 -
> Standard JUnit TestCase subclass with dependency injection
> annotations.
>
> Jacek
>
> -- 
> Jacek Laskowski
> http://www.JacekLaskowski.pl
>


Re: Problems getting EJB via annotation in test class.

Posted by Jacek Laskowski <ja...@laskowski.net.pl>.
On Nov 26, 2007 10:21 PM, Paul Spencer <pa...@mindspring.com> wrote:

> Right now just the knowledge of how things work is enough.

You can track it in http://issues.apache.org/jira/browse/OPENEJB-728 -
Standard JUnit TestCase subclass with dependency injection
annotations.

Jacek

-- 
Jacek Laskowski
http://www.JacekLaskowski.pl

Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
David Blevins wrote:
> 
> On Nov 26, 2007, at 11:26 AM, Paul Spencer wrote:
> 
>> David,
>> To summarize things:
>>
>> Relative to testing EJBs inside a Maven executed JUnit test, any 
>> object instantiated by a class inside a JUnit test case is not 
>> "container managed" thus the  object will not receive the benefit of 
>> DI. EJB known to the embedded EJB container, ejbd in this case, and 
>> instantiated within that container will receive the benefit of DI, but 
>> the beans must be retrieve by the test class via a JNDI lookup.
>>
>> Now I can stop beating my head against the wall :)
> 
> Right :)
> 
> What I was just typing up in another email is that we would like to find 
> some way to support what you were trying to do; a standard JUnit 
> TestCase subclass with dependency injection annotations.
> 
<snip>
> 
> Would something like that work for you or is the knowledge that the test 
> case would be relying on something outside the (current) EJB spec enough 
> to make those lookups look not so bad?
> 

Right now just the knowledge of how things work is enough.

> -David
> 
> 
> 

Paul Spencer

Re: Problems getting EJB via annotation in test class.

Posted by David Blevins <da...@visi.com>.
On Nov 26, 2007, at 11:26 AM, Paul Spencer wrote:

> David,
> To summarize things:
>
> Relative to testing EJBs inside a Maven executed JUnit test, any  
> object instantiated by a class inside a JUnit test case is not  
> "container managed" thus the  object will not receive the benefit of  
> DI. EJB known to the embedded EJB container, ejbd in this case, and  
> instantiated within that container will receive the benefit of DI,  
> but the beans must be retrieve by the test class via a JNDI lookup.
>
> Now I can stop beating my head against the wall :)

Right :)

What I was just typing up in another email is that we would like to  
find some way to support what you were trying to do; a standard JUnit  
TestCase subclass with dependency injection annotations.

An option I've suggested in the past would be something simple like  
this.

public class EjbDiTest extends TestCase {
	
    @EJB private DataReaderLocal dataReaderLocal;
    @EJB private DataReaderRemote dataReaderRemote;

    private InitialContext initialContext;

    protected void setUp() throws Exception {
        Properties properties = new Properties();
        properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,  
"org.apache.openejb.client.LocalInitialContextFactory");
         
properties.setProperty("openejb.deployments.classpath.include",  
".*injection.*");

        properties.put("openejb.inject", this);  // <------ you give  
us a reference to your test case

        initialContext = new InitialContext(properties);
    }
}

Then we do the injection on your test case.

Internally, it's much trickier as we'd like to support not just @EJB  
but also @Resource and the rules that make those two annotations work  
can get pretty complex.  The way the code is written now, we'd  
essentially have to treat the test case as an app client and run it  
through deployment where all its references to ejbs and datasources,  
etc. would get resolved.

That's one theory anyway.

Would something like that work for you or is the knowledge that the  
test case would be relying on something outside the (current) EJB spec  
enough to make those lookups look not so bad?

-David



Re: Problems getting EJB via annotation in test class.

Posted by Jacek Laskowski <ja...@laskowski.net.pl>.
On Nov 26, 2007 8:26 PM, Paul Spencer <pa...@mindspring.com> wrote:

> Relative to testing EJBs inside a Maven executed JUnit test, any object
> instantiated by a class inside a JUnit test case is not "container
> managed" thus the  object will not receive the benefit of DI. EJB known
> to the embedded EJB container, ejbd in this case, and instantiated
> within that container will receive the benefit of DI, but the beans must
> be retrieve by the test class via a JNDI lookup.

Exactly. Nice we got it straightened out ;-) I wonder if we could
introduce a feature to help people run annotated tests. I think the
only way to achieve it would be to run the tests with a java agent
that would intercept test class loading. Any other ideas?

Jacek

-- 
Jacek Laskowski
http://www.JacekLaskowski.pl

Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
David,
To summarize things:

Relative to testing EJBs inside a Maven executed JUnit test, any object 
instantiated by a class inside a JUnit test case is not "container 
managed" thus the  object will not receive the benefit of DI. EJB known 
to the embedded EJB container, ejbd in this case, and instantiated 
within that container will receive the benefit of DI, but the beans must 
be retrieve by the test class via a JNDI lookup.

Now I can stop beating my head against the wall :)

Thank you David and Jacek

Paul Spencer

  David Blevins wrote:
> 
> On Nov 25, 2007, at 2:09 PM, Paul Spencer wrote:
> 
>> I am trying to access the many forms of the EJB, some may be incorrect 
>> an need to be removed from the test.
>>
>> Since the test is using OpenEJB as an embedded server, why is the test 
>> class not considered as a DI target?
>>
>> My intent is to test the EJB in the same manor as an application would 
>> use the EJB.  This includes the use of DI.  Is my implementation 
>> consistent with my intent?
> 
> As Jacek points out of you'd like to test your EJBs from the perspective 
> of another application, you'd have to put your test logic in an actual 
> application (ejb and/or interceptor) and execute it from your test case.
> 
> The EJB 3.0 specification only covers dependency injection for classes 
> managed by a container:
>  - servlets, servlet filters, listeners
>  - a javaee app client ran by an app client container
>  - ejb session beans or interceptors
> 
> In the EJB 3.1 expert group we plan to introduce some way for 
> non-managed objects (objects not instantiated or run by a container) to 
> get dependency injection.  No details on how that will be done just yet, 
> however I can nearly guarantee it'll be in the form of some code you 
> have to execute on your object after you construct it, i.e. all the 
> injection won't magically be done on the "new MyClass()" call.
> 
> We definitely discussed the magical "new" in EJB 3.0 in reference to JPA 
> and decided against using anything like that because the only possible 
> way to support it is through byte-code manipulation.  At the time 
> byte-code manipulation was only possible via using some vendor tool at 
> build time or dynamically using a vendor javaagent specified on the 
> command line, both of which are fairly complicated and diminish the 
> simplicity we were going for.  Things are different with Java 6 so maybe 
> we'll see some magic news in Java EE some day.
> 
> -David
> 
> 
> 


Re: Problems getting EJB via annotation in test class.

Posted by David Blevins <da...@visi.com>.
On Nov 25, 2007, at 2:09 PM, Paul Spencer wrote:

> I am trying to access the many forms of the EJB, some may be  
> incorrect an need to be removed from the test.
>
> Since the test is using OpenEJB as an embedded server, why is the  
> test class not considered as a DI target?
>
> My intent is to test the EJB in the same manor as an application  
> would use the EJB.  This includes the use of DI.  Is my  
> implementation consistent with my intent?

As Jacek points out of you'd like to test your EJBs from the  
perspective of another application, you'd have to put your test logic  
in an actual application (ejb and/or interceptor) and execute it from  
your test case.

The EJB 3.0 specification only covers dependency injection for classes  
managed by a container:
  - servlets, servlet filters, listeners
  - a javaee app client ran by an app client container
  - ejb session beans or interceptors

In the EJB 3.1 expert group we plan to introduce some way for non- 
managed objects (objects not instantiated or run by a container) to  
get dependency injection.  No details on how that will be done just  
yet, however I can nearly guarantee it'll be in the form of some code  
you have to execute on your object after you construct it, i.e. all  
the injection won't magically be done on the "new MyClass()" call.

We definitely discussed the magical "new" in EJB 3.0 in reference to  
JPA and decided against using anything like that because the only  
possible way to support it is through byte-code manipulation.  At the  
time byte-code manipulation was only possible via using some vendor  
tool at build time or dynamically using a vendor javaagent specified  
on the command line, both of which are fairly complicated and diminish  
the simplicity we were going for.  Things are different with Java 6 so  
maybe we'll see some magic news in Java EE some day.

-David



Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
Jacek Laskowski wrote:
> On Nov 25, 2007 11:09 PM, Paul Spencer <pa...@mindspring.com> wrote:
> 
>> Since the test is using OpenEJB as an embedded server, why is the test
>> class not considered as a DI target?
> 
> if (test class == ejb class && test case == interceptor class) {
>   // the test class *is* a target of DI machinery
> } else {
>   // do nothing with it, just load the class and provide to other
> classes with no DI-related changes
> }
>

I need to think about this.  I start a new thread if I have questions.

>> My intent is to test the EJB in the same manor as an application would
>> use the EJB.  This includes the use of DI.  Is my implementation
>> consistent with my intent?
> 
> Have you considered checking out the openejb examples from
> http://svn.apache.org/repos/asf/openejb/trunk/openejb3/examples/?
> Unless you have, I'd strongly recommend doing so as there're quite a
> few examples of how ejbs look like and work in openejb. There's
> nothing specific to openejb in them so they should work in other ejb
> containers with no changes. You can read about them  on
> http://openejb.apache.org/examples.html. If you're not satisfied with
> them, write what you're after and I'll create one for you (consider it
> a New Year present ;-))

I have attached a modified version of the EjbDependencyTest that 
illustrates how I want to test my EJBs.

> 
> Jacek
> 

Thank you,
Paul Spencer


Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
David Blevins wrote:
> 
> On Nov 26, 2007, at 12:51 AM, Jacek Laskowski wrote:
> 
>> On Nov 25, 2007 11:09 PM, Paul Spencer <pa...@mindspring.com> 
>> wrote:
>>
>>> Since the test is using OpenEJB as an embedded server, why is the test
>>> class not considered as a DI target?
>>
>> if (test class == ejb class && test case == interceptor class) {
>>  // the test class *is* a target of DI machinery
>> }
> 
> Well the tricky thing about that statement is that if the "test class" 
> is an ejb or interceptor, it's no longer a JUnit test class (i.e. 
> something run by junit).  But the statement is correct in that you can 
> put test *logic* in an ejb or interceptor which is deployed in the 
> embedded container along with the app you'd like to test.
>
This seems opposite from my experience, although the result may be the 
same.  If a class exists in Maven's test class path, i.e. 
target/test-classes, then that class will not have fields set via DI.  I 
posted a sample test, which is a modification of one of OpenEJB's 
examples, in this thread. The post is dated  26-nov-2007 @ 06:53 EST.

> -David
> 
> 

Paul Spencer

Re: Problems getting EJB via annotation in test class.

Posted by David Blevins <da...@visi.com>.
On Nov 26, 2007, at 12:51 AM, Jacek Laskowski wrote:

> On Nov 25, 2007 11:09 PM, Paul Spencer <pa...@mindspring.com>  
> wrote:
>
>> Since the test is using OpenEJB as an embedded server, why is the  
>> test
>> class not considered as a DI target?
>
> if (test class == ejb class && test case == interceptor class) {
>  // the test class *is* a target of DI machinery
> }

Well the tricky thing about that statement is that if the "test class"  
is an ejb or interceptor, it's no longer a JUnit test class (i.e.  
something run by junit).  But the statement is correct in that you can  
put test *logic* in an ejb or interceptor which is deployed in the  
embedded container along with the app you'd like to test.

-David


Re: Problems getting EJB via annotation in test class.

Posted by Jacek Laskowski <ja...@laskowski.net.pl>.
On Nov 25, 2007 11:09 PM, Paul Spencer <pa...@mindspring.com> wrote:

> Since the test is using OpenEJB as an embedded server, why is the test
> class not considered as a DI target?

if (test class == ejb class && test case == interceptor class) {
  // the test class *is* a target of DI machinery
} else {
  // do nothing with it, just load the class and provide to other
classes with no DI-related changes
}

> My intent is to test the EJB in the same manor as an application would
> use the EJB.  This includes the use of DI.  Is my implementation
> consistent with my intent?

Have you considered checking out the openejb examples from
http://svn.apache.org/repos/asf/openejb/trunk/openejb3/examples/?
Unless you have, I'd strongly recommend doing so as there're quite a
few examples of how ejbs look like and work in openejb. There's
nothing specific to openejb in them so they should work in other ejb
containers with no changes. You can read about them  on
http://openejb.apache.org/examples.html. If you're not satisfied with
them, write what you're after and I'll create one for you (consider it
a New Year present ;-))

Jacek

-- 
Jacek Laskowski
http://www.JacekLaskowski.pl

Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
Jacek Laskowski wrote:
> On Nov 25, 2007 3:04 PM, Paul Spencer <pa...@mindspring.com> wrote:
> 
>> 2) My source code, specifically the definition of CompanyAdminLocal,
>> CompanyAdminReport, and CompanyAdminImpl match the injection example.
> 
> That's correct, but the class - MyTestClass - that uses the local,
> remote and impl (?) interfaces is not considered as DI target and
> openejb (and any ejb3 container) doesn't inject ejbs into it.

I am trying to access the many forms of the EJB, some may be incorrect 
an need to be removed from the test.

Since the test is using OpenEJB as an embedded server, why is the test 
class not considered as a DI target?

My intent is to test the EJB in the same manor as an application would 
use the EJB.  This includes the use of DI.  Is my implementation 
consistent with my intent?

> 
<snip>
> 
> Jacel
> 

Paul Spencer

Re: Problems getting EJB via annotation in test class.

Posted by Jacek Laskowski <ja...@laskowski.net.pl>.
On Nov 25, 2007 3:04 PM, Paul Spencer <pa...@mindspring.com> wrote:

> 2) My source code, specifically the definition of CompanyAdminLocal,
> CompanyAdminReport, and CompanyAdminImpl match the injection example.

That's correct, but the class - MyTestClass - that uses the local,
remote and impl (?) interfaces is not considered as DI target and
openejb (and any ejb3 container) doesn't inject ejbs into it.

There's yet another possible solution I didn't test out myself - an
application client. If you worked with Geronimo (or any Java EE 5
application server) you could inject ejbs and other managed resources
into your application client, but as I wrote I didn't try it out so I
can't comment on it much other than it should work. Please report a
issue report (in Geronimo's or OpenEJB's jira) if you think that such
an example should be available.

> 3) I did not find an example where the test class used DI to get the
> EJB. All of the tests got an EJB via context.lookup.

I'll look into it so one is available.

Jacel

-- 
Jacek Laskowski
http://www.JacekLaskowski.pl

Re: Problems getting EJB via annotation in test class.

Posted by Paul Spencer <pa...@mindspring.com>.
Jacek,
1) I am using jdk1.5.0_12

2) My source code, specifically the definition of CompanyAdminLocal, 
CompanyAdminReport, and CompanyAdminImpl match the injection example.

3) I did not find an example where the test class used DI to get the 
EJB. All of the tests got an EJB via context.lookup.

Paul Spencer



Jacek Laskowski wrote:
> On Nov 25, 2007 4:45 AM, Paul Spencer <pa...@mindspring.com> wrote:
>> I am trying to test an EJB3 using annotation.  The problem is the
>> injected value is always null.
> 
> Dependency Injection (DI) in Java EE 5 only works for managed objects
> like enterprise javabeans classes or interceptors (limiting it to ejb3
> only).
> 
>> ***
>> * Annotated test class
>> ***
>> class MyTestClass {
>>                 @EJB
>>                 CompanyAdminLocal localBean;
>>
>>                 @EJB(name="CompanyAdminImplRemote")
>>                 CompanyAdminRemote remoteBean;
>>
>>                 @EJB
>>                 CompanyAdminImpl defaultBean;
> 
>>>From EJB3's standpoint the class is not a managed object and cannot
> use DI. OpenEJB 3 doesn't even consider it as a target of DI. That's
> why the class returns null's from its getters. Make it a ejb (like
> @Stateless) with its business interface and it should work fine.
> 
> See examples in
> http://svn.apache.org/repos/asf/openejb/trunk/openejb3/examples for
> more ejb3 examples. Read about them in
> http://openejb.apache.org/examples.html. Let us know when there's no
> such an example you're after.
> 
> Jacek
> 


Re: Problems getting EJB via annotation in test class.

Posted by Jacek Laskowski <ja...@laskowski.net.pl>.
On Nov 25, 2007 4:45 AM, Paul Spencer <pa...@mindspring.com> wrote:
> I am trying to test an EJB3 using annotation.  The problem is the
> injected value is always null.

Dependency Injection (DI) in Java EE 5 only works for managed objects
like enterprise javabeans classes or interceptors (limiting it to ejb3
only).

> ***
> * Annotated test class
> ***
> class MyTestClass {
>                 @EJB
>                 CompanyAdminLocal localBean;
>
>                 @EJB(name="CompanyAdminImplRemote")
>                 CompanyAdminRemote remoteBean;
>
>                 @EJB
>                 CompanyAdminImpl defaultBean;

>From EJB3's standpoint the class is not a managed object and cannot
use DI. OpenEJB 3 doesn't even consider it as a target of DI. That's
why the class returns null's from its getters. Make it a ejb (like
@Stateless) with its business interface and it should work fine.

See examples in
http://svn.apache.org/repos/asf/openejb/trunk/openejb3/examples for
more ejb3 examples. Read about them in
http://openejb.apache.org/examples.html. Let us know when there's no
such an example you're after.

Jacek

-- 
Jacek Laskowski
http://www.JacekLaskowski.pl