@Produces
The @Produces annotation can be applied to a (private or other) field or a method. That means that you can inject not only beans, but also collections etc. Using the @Produce annotation you may also fine the criteria when you combine it with qualifiers.
Here’s an example from the official JSR 299 document. My sample application also utilizes the annotation but in a simpler manner.
public class Shop { @Produces @All public List<Product> getAllProducts() { ... } @Produces @WishList public List<Product> getWishList() { ... } }
You can read more about alternatives in Section 3.3.2 of JSR.
@Alternative
You may have a few possibilities for a dependency injection. You can either use qualifiers (see Part 1) or the @Alternative annotation (you have to pick either approach or your CDI implementation will complain).
If you decide to use alternatives, you choose one default bean and annotate the rest with the @Alternative annotation. Then, you can change the one to be injected using your beans.xml file.
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>me.m1key.jsf.dao.DogsDaoMockImpl</class> </alternatives> </beans>
Remember that for this to work, the two beans (the one without the @Alternative annotation and the alternative one) must be on the same level of priority, i.e. have no or the same qualifiers etc.
Testing
No modern framework or toolkit can be considered mature without making it possible to run tests in isolation, without a server. What does testing look like with CDI?
I based my research on a post by Jacek Laskowski (the text is Polish, but the source code isn’t).
You need to provide your own implementation of CDI. We are going to use Arquillian and Weld.
Here’s the relevant pom.xml part:
<dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-core-bom</artifactId> <version>1.0.1-Final</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>1.0-SP1</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-junit</artifactId> <version>1.0.0.Alpha2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-weld-embedded</artifactId> <version>1.0.0.Alpha2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-core</artifactId> <version>1.0.1-Final</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-api</artifactId> <version>1.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.10</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>2.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet</artifactId> <version>1.0.1-Final</version> <scope>test</scope> </dependency> </dependencies> <repositories> <repository> <id>JBoss.org</id> <name>JBoss Repository</name> <url>http://repository.jboss.com/maven2</url> </repository> <repository> <id>jboss-public-repository-group</id> <name>JBoss Public Maven Repository Group</name> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories>
And now the test itself.
package me.m1key.jsf; import static org.junit.Assert.assertNotNull; import java.io.File; import java.io.IOException; import javax.inject.Inject; // .. import org.jboss.arquillian.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ArchivePaths; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(Arquillian.class) public class DogsDaoTest { @Deployment public static JavaArchive createTestArchive() throws IllegalArgumentException, IOException { return ShrinkWrap.create("test.jar", JavaArchive.class) .addManifestResource(new File("src/test/resources/beans.xml"), ArchivePaths.create("beans.xml")).addClasses( DogsDaoImpl.class, DogsDaoMockImpl.class); } @Inject private DogsDao dogsDao; @Test public void testInjectedDaoNotNull() { assertNotNull(dogsDao); System.out.println(dogsDao.getClass().getCanonicalName()); } }
It’s a Maven project - and our test resources folder will contain another beans.xml. In this beans.xml we will specify alternative dependencies to inject (mock DAOs).
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>me.m1key.jsf.dao.DogsDaoMockImpl</class> </alternatives> </beans>
- @RunWith(Arquillian.class) - we need this for Arquillian to be activated for the tests
- @Deployment - it is an Arquillian’s requirement for one method with this annotation to be present. It builds an archive which contains all our tests need to run. You must manually specify which classes it should use. We are also loading the other beans.xml with alternative beans specified
- @Inject - here a bean will be injected by our combination of Arquillian and Weld (namely, DogsDaoMockImpl)
- The test method only checks if anything was injected
Summary
I showed you how to use the @Produce and @Alternative annotations. You can check out the source code to see it working. NOTE: I removed qualifiers so that @Alternative can work.
We also looked at testing possibilities from JUnit .
Download sample source code for this article
Thanks! Your sample was rery usefull :)
ReplyDeleteReckless Driving In New Jersey
ReplyDeleteI think this blog post is very informative and provides valuable insight into the current state of the economy. It does a great job of highlighting the various challenges we face and provides solutions for how to tackle them.