Hi there, I recently read the post by Ed Yong on the evolution of our language measured using Google Books. Google Books apparently has 12% of everything that has ever been published! A group of scientists prepared a tool to analyze this enormous amount of data and you can try it yourself!
What it does is it shows you how often certain words (specified by you) have been used in print in history. I found some interesting examples.
devil vs. god
life vs. death
sex vs. drugs vs. rock and roll
Classic from Ed’s blog: burnt vs. burned
terrorism
2010-12-28
2010-11-30
2010-11-22
Getters called multiple times in JSF
In JSF, getters of your beans might be called multiple times per request - it’s a fact. Therefore making a data source call from the getter will have a negative impact on your performance.
Suppose you have a page with a form on it. The user fills and submits the form. There are two scenarios possible - submit success or failure. The expensive call could be acquiring a list of options to choose from on the form.
For these two scenarios putting the expensive database call in the constructor or getter will not work. You will either get too many calls or too few.
And here is the solution.
This part does the trick:
Interested in how to inject FacesContext?
You can download sample code (a Maven app) that works on JBoss 6 M5.
Suppose you have a page with a form on it. The user fills and submits the form. There are two scenarios possible - submit success or failure. The expensive call could be acquiring a list of options to choose from on the form.
- The user opens the page.
- Make just one expensive database call. I.e. don’t make the same call twice.
- The user fills and submits the form.
- Display the success page, do not make the expensive database call.
- The user opens the page.
- Make just one expensive database call. I.e. don’t make the same call twice.
- The user fills and submits the form.
- Validation error occurs. Return to the form page and make the expensive call (to reload the list of options, for instance).
For these two scenarios putting the expensive database call in the constructor or getter will not work. You will either get too many calls or too few.
Solution
And here is the solution.
package me.m1key.sample.singlecall; import javax.enterprise.context.RequestScoped; import javax.faces.context.FacesContext; import javax.inject.Inject; import javax.inject.Named; // ... @Named @RequestScoped public class UserBean { @Inject private FacesContext facesContext; public List<String> getUsernames() { if (facesContext.getRenderResponse()) { System.out.println("Expensive call..."); } List<String> usernames = new ArrayList<String>(); usernames.add("Michal"); usernames.add("Ilinka"); return usernames; }
This part does the trick:
if (facesContext.getRenderResponse()) { // Expensive stuff }
Interested in how to inject FacesContext?
You can download sample code (a Maven app) that works on JBoss 6 M5.
Labels:
Java,
JSF,
Programming
2010-11-20
JSF: Inject FacesContext
In JSF, the standard way of accessing FacesContext is through a static call:
Static calls defy the purpose of OO programming, make unit testing hard, and you have to create a local variable.
Now, with the dawn of JEE6 and dependency injection you would like to do just that:
But it doesn’t work. Here is some explanation why.
The solution is to use Seam Faces. Seam Faces allow you to access FacesContext, ExternalContext and NavigationHandler without having to make static calls.
Here’s how you can add it to your project:
And it just works! Of course your server must support CDI.
Obviously, the tests require a bit of clumsy boilerplate. If you find it confusing, you can read more about unit testing with Arquillian.
You can download sample code (a Maven app) that works on JBoss 6 M5.
FacesContext context = FacesContext.getCurrentInstance();
Static calls defy the purpose of OO programming, make unit testing hard, and you have to create a local variable.
Now, with the dawn of JEE6 and dependency injection you would like to do just that:
@Inject private FacesContext facesContext;
But it doesn’t work. Here is some explanation why.
The solution
The solution is to use Seam Faces. Seam Faces allow you to access FacesContext, ExternalContext and NavigationHandler without having to make static calls.
Here’s how you can add it to your project:
<dependency> <groupId>org.jboss.seam.faces</groupId> <artifactId>seam-faces</artifactId> <version>3.0.0.Alpha3</version> </dependency>
And it just works! Of course your server must support CDI.
Unit testing
Obviously, the tests require a bit of clumsy boilerplate. If you find it confusing, you can read more about unit testing with Arquillian.
package me.m1key.sample.singlecall; import static org.junit.Assert.assertEquals; 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.jboss.shrinkwrap.impl.base.asset.ByteArrayAsset; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(Arquillian.class) public class UserBeanTest { @Deployment public static JavaArchive createTestArchive() throws IllegalArgumentException, IOException { return ShrinkWrap.create("test.jar", JavaArchive.class) .addManifestResource(new ByteArrayAsset(new byte[0]), ArchivePaths.create("beans.xml")).addClasses( UserBean.class, MockFacesContext.class); } @Inject private UserBean userBean; @Test public void thereShouldBeTwoUserNames() { assertEquals(2, userBean.getUsernames().size()); } }
Sample
You can download sample code (a Maven app) that works on JBoss 6 M5.
2010-11-18
Mercurial server on Windows with Apache
In this tutorial I will show you how to set up a Mercurial 1.7.1 server on Windows using the Apache server, version 2.2.17. I successfully verified this configuration on Windows 7 and Windows XP.
It should be fairly similar for Unix based system, but I haven’t tried that. You can obviously use a different server too.
Thanks goes to my friend Jeroen who helped me out with this.
Obviously, you need Mercurial. It’s up to you how you want to install it, but make sure that the hg command is available from command line. Use the MSI installation and it will do it for you.
I will assume you installed it to C:\Program Files\Mercurial.
The second step is to obtain and install the Apache server. You may want to install it as a service. There is a nice and simple ApacheMonitor application that will put itself in your system tray and you can control your Apache from there.
I will assume you installed it to C:\Program Files\Apache Software Foundation\Apache2.2.
For the Mercurial server to work, you need to have Python installed. The Python version must correspond to the Mercurial version. For Mercurial 1.7.1 you should get Python 2.6.
Please not that you do NOT need to set a system variable called PYTHONPATH as some tutorials suggest.
I will assume you installed your Python to C:\Python26.
Download Mercurial source for your Mercurial version and unpack it. If you are lazy, you don’t have to do it - all the necessary files are available on my website (see links below).
You need to create a project where Mercurial will store your projects. I will assume it’s C:\Projects\hg.
In the Apache htdocs folder put this file - hgweb.cgi. Get it from the Mercurial source. In another folder (I will assume it’s the Mercurial installation folder) put hgweb.config - just create it.
Please note those two files are also available for download from my website (see links below).
So if you got this file from the source, you need to make it look more or less like this one.
C:\Projects\hg is, again, where Mercurial will contain your projects. It allows anyone to push. It uses the monoblue style. Provide your email in the contact field. The last line makes SSL not compulsory to be able to push.
I didn't have to do this, but user Good reported he did and he found it on the editrocket.com site.
Search the httpd.conf file for the line
Thanks Good!
Now, for each project you will have to manually create a repository in the C:\Projects\hg folder.
Go to console, go to this folder and type hg init projectName. This will create the repository.
Launch the server and go to http://localhost/hgweb.cgi. You should now see your project listed there under projectName.
You can push and pull to http://localhost/hgweb.cgi/projectName/.
Sample hgweb.cgi (I changed the extension to .txt so that the server wouldn’t treat it as a script)
Sample hgweb.config
It should be fairly similar for Unix based system, but I haven’t tried that. You can obviously use a different server too.
Thanks goes to my friend Jeroen who helped me out with this.
Installing Mercurial
Obviously, you need Mercurial. It’s up to you how you want to install it, but make sure that the hg command is available from command line. Use the MSI installation and it will do it for you.
I will assume you installed it to C:\Program Files\Mercurial.
Installing Apache
The second step is to obtain and install the Apache server. You may want to install it as a service. There is a nice and simple ApacheMonitor application that will put itself in your system tray and you can control your Apache from there.
I will assume you installed it to C:\Program Files\Apache Software Foundation\Apache2.2.
Installing Python
For the Mercurial server to work, you need to have Python installed. The Python version must correspond to the Mercurial version. For Mercurial 1.7.1 you should get Python 2.6.
Please not that you do NOT need to set a system variable called PYTHONPATH as some tutorials suggest.
I will assume you installed your Python to C:\Python26.
Downloading Mercurial source
Download Mercurial source for your Mercurial version and unpack it. If you are lazy, you don’t have to do it - all the necessary files are available on my website (see links below).
Configuring Mercurial
- Go to your Mercurial installation directory.
- Unpack the library.zip file contents into a folder called lib. You will have to create it yoruself. In this folder the contents of the library.zip file should reside direcly, i.e. the path to for instance zipfile.pyc should be C:\Program Files\Mercurial\lib\zipfile.pyc.
- Move the C:\Program Files\Mercurial\templates folder into the new lib folder.
Creating a projects folder
You need to create a project where Mercurial will store your projects. I will assume it’s C:\Projects\hg.
Configuring Apache
In the Apache htdocs folder put this file - hgweb.cgi. Get it from the Mercurial source. In another folder (I will assume it’s the Mercurial installation folder) put hgweb.config - just create it.
Please note those two files are also available for download from my website (see links below).
hgweb.cgi
#!c:/Python26/python.exe -u # # An example hgweb CGI script, edit as necessary # See also http://mercurial.selenic.com/wiki/PublishingRepositories # Path to repo or hgweb config to serve (see 'hg help hgweb') config = "C:/Program Files/Mercurial/hgweb.config" # Uncomment and adjust if Mercurial is not installed system-wide: import sys; sys.path.insert(0, "C:/Program Files/Mercurial/lib") # Uncomment to send python tracebacks to the browser if an error occurs: import cgitb; cgitb.enable() from mercurial import demandimport; demandimport.enable() from mercurial.hgweb import hgweb, wsgicgi application = hgweb(config) wsgicgi.launch(application)
So if you got this file from the source, you need to make it look more or less like this one.
hgweb.config
[collections] C:\Projects\hg = C:\Projects\hg [web] allow_push = * style = monoblue contact = you@localhost.com push_ssl = false
C:\Projects\hg is, again, where Mercurial will contain your projects. It allows anyone to push. It uses the monoblue style. Provide your email in the contact field. The last line makes SSL not compulsory to be able to push.
httpd.conf
I didn't have to do this, but user Good reported he did and he found it on the editrocket.com site.
Search the httpd.conf file for the line
Options Indexes FollowSymLinksAdd ExecCGI to this line. The line should now look similar to the following (NOTE: there may be more options listed):
Options Indexes FollowSymLinks ExecCGINext, search for the following:
#AddHandler cgi-script .cgiUncomment this line by removing the # in front of the line, and add a .py to the end of the line. The new line should look like this:
AddHandler cgi-script .cgi .py
Thanks Good!
Creating a sample project
Now, for each project you will have to manually create a repository in the C:\Projects\hg folder.
Go to console, go to this folder and type hg init projectName. This will create the repository.
Verifying
Launch the server and go to http://localhost/hgweb.cgi. You should now see your project listed there under projectName.
You can push and pull to http://localhost/hgweb.cgi/projectName/.
Sample hgweb.cgi (I changed the extension to .txt so that the server wouldn’t treat it as a script)
Sample hgweb.config
2010-10-13
2010-10-03
2010-09-27
Photos from New York, Chicago & Washington DC
Dear everyone, please check out my photos from New York & Washington DC (that's the first gallery) and from Chicago (the second gallery).
2010-07-22
@Named vs. @ManagedBean in JSF 2.0
A lot of people seem to suggest that you should use @Named instead of @ManagedBean in JSF 2.0 (e.g. see @ManagedBean dead on arrival? or this JavaRanch discussion).
However, what I discovered in a painful process is that you must use @ManagedBean when the scope is @ViewScoped, apparently because CDI doesn’t declare a view scope. Thus this is correct:
NOTE: I am using JBoss 6 M3.
However, what I discovered in a painful process is that you must use @ManagedBean when the scope is @ViewScoped, apparently because CDI doesn’t declare a view scope. Thus this is correct:
import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; @ManagedBean @ViewScoped public class DogsBean { // ...
NOTE: I am using JBoss 6 M3.
Labels:
CDI,
Java,
JSF,
Programming
2010-07-21
Custom validation with Bean Validation (JSR-303)
In my previous post on Bean Validation I explained how to use built-in constrains. When the standard constraints aren’t enough, you can develop your own.
Let’s create a custom constraint and have it checked that the first character is an uppercase one.
Now, we need the validator.
Nothing special here. Finally, the usage...
It’s identical as any other constraint.
I showed you how to write custom constraints and gave a hint about existence and purpose of groups and payloads.
Download source code for this article
Custom constraint
Let’s create a custom constraint and have it checked that the first character is an uppercase one.
package me.m1key.jsf.constraints; import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Documented @Constraint(validatedBy = FirstUpperValidator.class) @Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface FirstUpper { String message() default "{me.m1key.jsf.constraints.FirstUpper.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
- message - the error message. You can omit curly braces and just hard code it
- groups - this is for grouping validations (if one group fails - other groups are not checked; here we use the default group)
- payload - additional type-safe information might be carried here
Now, we need the validator.
Custom validator
package me.m1key.jsf.constraints; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class FirstUpperValidator implements ConstraintValidator<FirstUpper, String> { @Override public void initialize(FirstUpper firstUpper) { // See JSR 303 Section 2.4.1 for sample implementation. } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null || value.length() == 0) { return true; } return value.substring(0, 1) .equals(value.substring(0, 1).toUpperCase()); } }
Nothing special here. Finally, the usage...
The usage
It’s identical as any other constraint.
@NotNull @Size(min = 3) @FirstUpper public String getName() { return name; }
Summary
I showed you how to write custom constraints and gave a hint about existence and purpose of groups and payloads.
Download source code for this article
Read on
- Great posts on Bean Validation by Gunnar Morling.
- JSR 303
- Getting started with Bean Validation (my post)
2010-07-20
Bean Validation with JEE 6 (JSR-303)
In this article I will show you some basic Bean Validation examples. You may want to (you should) read the official JSR 303 document to learn more. First, a quote from that document.
Validating data is a common task that occurs throughout an application, from the presentation layer to the persistence layer. Often the same validation logic is implemented in each layer, proving to be time consuming and errorprone. To avoid duplication of these validations in each layer, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code that is, in fact, metadata about the class itself.
This JSR defines a metadata model and API for JavaBean validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors.
To use built-in constraints your project must import the javax.validation dependency. Maven:
Here are some built-in annotations:
Usage:
Here’s an example of unit testing constraints. You must add a Bean Validation implementation:
And the code itself:
Error messages are customizable. They can be modified if you provide a ResourceBundle called ValidationMessages (so, you can create a ValidationMessages .properties file and make if available in the classpath root).
Very good question! The specification doesn’t explicitly say when; instead it provides a clue in form of Appendices D, E and F.
Different JEE technologies launch Bean Validation. But when?
JPA calls validation upon:
JSF calls validation upon:
In the next article I will show you how to define custom constraints and more.
Validating data is a common task that occurs throughout an application, from the presentation layer to the persistence layer. Often the same validation logic is implemented in each layer, proving to be time consuming and errorprone. To avoid duplication of these validations in each layer, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code that is, in fact, metadata about the class itself.
This JSR defines a metadata model and API for JavaBean validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors.
Built-in constraints
To use built-in constraints your project must import the javax.validation dependency. Maven:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> <type>jar</type> <scope>test</scope> </dependency>
Here are some built-in annotations:
- @Null
- @NotNull
- @AssertTrue
- @AssertFalse
- @Min
- @Max
- @DecimalMin
- @DecimalMax
- @Size - covers min and max
- @Digits
- @Past - must be a date in the past
- @Future - must be a date in the future
- @Pattern
Usage:
import javax.validation.constraints.Size; import javax.validation.constraints.NotNull; // ... @NotNull @Size(min = 3) public String getName() { return name; }UPDATE: @Min is for numbers only, my bad. This code now uses @Size.
Testing the validation
Here’s an example of unit testing constraints. You must add a Bean Validation implementation:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.0.2.GA</version> <type>jar</type> <scope>test</scope> </dependency>
And the code itself:
package me.m1key.jsf; import static org.junit.Assert.assertEquals; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import org.junit.BeforeClass; import org.junit.Test; public class DogsBeanTest { private static Validator validator; @BeforeClass public static void setUp() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } @Test public void test() { DogsBean bean = new DogsBean(); Set<ConstraintViolation<DogsBean>> constraintViolations = validator .validate(bean); assertEquals(1, constraintViolations.size()); } }It could be a lot better, because I only check the size of the violations set here. You might check the actual error message (still not so elegant...).
Error messages
Error messages are customizable. They can be modified if you provide a ResourceBundle called ValidationMessages (so, you can create a ValidationMessages .properties file and make if available in the classpath root).
When does validation occur?
Very good question! The specification doesn’t explicitly say when; instead it provides a clue in form of Appendices D, E and F.
Different JEE technologies launch Bean Validation. But when?
JPA calls validation upon:
- pre-persist
- pre-update
- pre-remove
JSF calls validation upon:
- the process validation phase
Next article
In the next article I will show you how to define custom constraints and more.
Labels:
Java,
JPA,
JSF,
Maven,
Programming
2010-07-13
CDI + JSF 2.0. Part 2
In my previous posts I showed a sample JSF 2.0 + Maven configuration and basic features of CDI with JSF 2.0. In this article I will show you the @Produces annotation and Alternatives, as well as unit testing of CDI.
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.
You can read more about alternatives in Section 3.3.2 of JSR.
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.
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.
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:
And now the test itself.
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).
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
@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
2010-07-12
StackOverflowError when using CDI
It seems that the current Weld implementation has an error - when no faces-config.xml is present in the deployment, but beans.xml is - you may get a StackOverflowError. At least I did with JBoss 6 RC3.
I filed the bug.
I filed the bug.
Labels:
CDI,
Java,
JBoss,
JSF,
Programming
2010-07-11
CDI + JSF 2.0. Part 1
In my previous post I complained about the standard JSF dependency injection mechanism. Therefore I decided it was the right time to look at...
It might be a good idea to read the JSR 299 document (the evaluation version is for you; the other one is for JSR implementers like Guice or Spring) if you haven’t yet.
CDI (formerly known as Web Beans) differs from DI in that it introduces the concept of Context. So you can inject dependencies according to the context too. What contexts are there?
That allows you to have a very flexible dependency injection mechanism where a new object is created by the container and injected whenever it does not exist in your context (or in broader context).
That’s right. This is how your JSF managed bean will look like now:
In fact, we wouldn’t have to use the @Named annotation to make it a managed bean, because according to the specification (consult JSR) most Java classes are managed beans (i.e. you can use dependency injection in them or inject them). We need @Named, however, to reference that bean from JSF. You can specify another name (the default one is dogsBean in this case).
It’s simple.
Let’s take a look at...
Let’s create a DAO.
Great! This bean is Application scoped, so there is going to be one instance of it per application. Note: the constructor will be called twice, actually. One for the actual object, one for the proxy. Read more about this behavior or consult JSR 299, Section 5.4.
Now, let’s inject it.
That’s it. You ask for an interface injection. The container sees there is only one implementation, and injects it. But what if you want to have two implementations of DogsDao?
With the current configuration, you’d get an exception - the container would not be able to decide which one to instantiate for you. How can you further specify which implementation you need? You should use...
Qualifiers are a CDI concept that allows you to have more sophisticated criteria for selecting the implementation. Let’s create two qualifiers.
Qualifiers must be annotated with @Qualifier.
Now, let’s annotate the classes.
Now, when we inject, we must specify which implementation we want, with the same qualifier.
And now it works.
I explained how to use basic CDI which is a new feature of JEE6. Remember that this is a JSF example, so I assumed you run it on an application server. However, CDI itself can be run without a server, so long as you provide an implementation for it (like Weld; the situation is similar to JPA).
Download source code for this article
In the next article I will explain why and how you can use the @Produces annotation and how to use alternatives (alternatives in the CDI sense).
CDI - Contexts and Dependency Injection (JSR 299)
It might be a good idea to read the JSR 299 document (the evaluation version is for you; the other one is for JSR implementers like Guice or Spring) if you haven’t yet.
CDI (formerly known as Web Beans) differs from DI in that it introduces the concept of Context. So you can inject dependencies according to the context too. What contexts are there?
- Application
- Request
- Session
- Conversation
- custom
That allows you to have a very flexible dependency injection mechanism where a new object is created by the container and injected whenever it does not exist in your context (or in broader context).
No more @ManagedBean
That’s right. This is how your JSF managed bean will look like now:
package me.m1key.jsf; import javax.enterprise.context.RequestScoped; import javax.inject.Named; // ... @Named @RequestScoped public class DogsBean {
In fact, we wouldn’t have to use the @Named annotation to make it a managed bean, because according to the specification (consult JSR) most Java classes are managed beans (i.e. you can use dependency injection in them or inject them). We need @Named, however, to reference that bean from JSF. You can specify another name (the default one is dogsBean in this case).
Accessing a managed bean from JSF
It’s simple.
<h:form> <h:inputText value="#{dogsBean.name}" /> <h:commandButton value="Send" action="#{dogsBean.send}" /> </h:form>And that’s it. Our bean is request scoped (CAUTION: make sure you import @RequestScoped from the correct package! That is javax.enterprise.context and not javax.faces.bean) so there will be a new instance of it per request.
Let’s take a look at...
Dependency injection
Let’s create a DAO.
package me.m1key.jsf.dao; // ... public interface DogsDao { public List<Dog> retrieveAllDogs(); }
package me.m1key.jsf.dao; import javax.enterprise.context.ApplicationScoped; // ... @ApplicationScoped public class DogsDaoImpl implements DogsDao { public DogsDaoImpl() { System.out.println(" DogsDaoImpl created: " + this); } public List<Dog> retrieveAllDogs() { List<Dog> dogs = new ArrayList<Dog>(); Dog dog1 = new Dog(); dog1.setId(1L); dog1.setName("Sega"); dogs.add(dog1); Dog dog2 = new Dog(); dog2.setId(2L); dog2.setName("Fluffy"); dogs.add(dog2); return dogs; } }
Great! This bean is Application scoped, so there is going to be one instance of it per application. Note: the constructor will be called twice, actually. One for the actual object, one for the proxy. Read more about this behavior or consult JSR 299, Section 5.4.
Now, let’s inject it.
@Inject private DogsDao dogsDao;
That’s it. You ask for an interface injection. The container sees there is only one implementation, and injects it. But what if you want to have two implementations of DogsDao?
package me.m1key.jsf.dao; import javax.enterprise.context.ApplicationScoped; // ... @ApplicationScoped public class DogsDaoMockImpl implements DogsDao {
With the current configuration, you’d get an exception - the container would not be able to decide which one to instantiate for you. How can you further specify which implementation you need? You should use...
Qualifiers
Qualifiers are a CDI concept that allows you to have more sophisticated criteria for selecting the implementation. Let’s create two qualifiers.
package me.m1key.jsf.qualifiers; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE }) public @interface Actual {}
package me.m1key.jsf.qualifiers; // ... @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE }) public @interface Mock {}
Qualifiers must be annotated with @Qualifier.
Now, let’s annotate the classes.
// ... import me.m1key.jsf.qualifiers.Actual; @Actual @ApplicationScoped public class DogsDaoImpl implements DogsDao {
// ... import me.m1key.jsf.qualifiers.Mock; @Mock @ApplicationScoped public class DogsDaoMockImpl implements DogsDao {
Now, when we inject, we must specify which implementation we want, with the same qualifier.
@Inject @Actual private DogsDao dogsDao;
And now it works.
Summary
I explained how to use basic CDI which is a new feature of JEE6. Remember that this is a JSF example, so I assumed you run it on an application server. However, CDI itself can be run without a server, so long as you provide an implementation for it (like Weld; the situation is similar to JPA).
Download source code for this article
Next article
In the next article I will explain why and how you can use the @Produces annotation and how to use alternatives (alternatives in the CDI sense).
2010-07-08
JSF 2.0 + Maven
In this article I will show you how to create a basic JSF 2.0 application with Maven, for JBoss 6.0.0-RC3.
JSF is a framework for building web applications using reusable components, and it’s focused on UI components. This allows you to write less HTML, which is a good thing.
What’s new compared to JSF 1.x?
I will present basic configuration of a JSF 2.0 project with Maven. Nothing fancy.
Why those versions of JSF? Well, that’s exactly what JBoss 6.0.0-RC3 uses.
No faces-config.xml - we don’t need it!
Because we are using the @ManagedBean annotation, we don’t need to declare the bean anywhere else. You can override this configuration with faces-config.xml, if you need to.
The send() method returns a String “hello". Automatically, .xhtml is going to be appended to it and a view hello.xhtml will be resolved. No need to declare the rule. Convention over configuration.
The default scope of this bean is request. You can modify the default scope.
Because it’s a managed bean, you can use JEE goodies (such as @EJB etc.) if you run your application on a JEE server .
Read more about managed beans validation and dependency injection using annotations.
I think that the JSF way of doing dependency injection is somewhat cumbersome. If you’re on JEE 6, you may want to use the new CDI mechanism. Jacek Laskowski wrote an article on using CDI with Java SEE (so without a JEE6 server). The article is in Polish, but the source code isn’t.
Note the PROJECT_STAGE property. It’s new to JSF 2.0. You can read more about PROJECT_STAGE on Ryan Lubke’s blog.
The view with a form:
The result view:
We created a simple JSF 2.0 application that uses a single managed bean and has 2 views. On that I will build another example, perhaps something using CDI.
Download source code for this article
JSF 2.0
JSF is a framework for building web applications using reusable components, and it’s focused on UI components. This allows you to write less HTML, which is a good thing.
What’s new compared to JSF 1.x?
- Annotations - faces-config.xml has less content or does not exist at all
- Support for Groovy
- A bit of convention over configuration (that also limits faces-config.xml content)
- Support for Ajax
- ... and more!
In this article
I will present basic configuration of a JSF 2.0 project with Maven. Nothing fancy.
Maven pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>me.m1key.jsf</groupId> <artifactId>sample</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <build> <finalName>sample</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.0.2-FCS</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.0.2-FCS</version> <scope>provided</scope> </dependency> </dependencies> <repositories> <repository> <id>JBoss.org</id> <name>JBoss Repository</name> <url>http://repository.jboss.com/maven2</url> </repository> </repositories> </project>
Why those versions of JSF? Well, that’s exactly what JBoss 6.0.0-RC3 uses.
faces-config.xml
No faces-config.xml - we don’t need it!
Managed bean
package me.m1key.jsf; import javax.faces.bean.ManagedBean; @ManagedBean public class UserBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String send() { return "hello"; } }
Because we are using the @ManagedBean annotation, we don’t need to declare the bean anywhere else. You can override this configuration with faces-config.xml, if you need to.
The send() method returns a String “hello". Automatically, .xhtml is going to be appended to it and a view hello.xhtml will be resolved. No need to declare the rule. Convention over configuration.
The default scope of this bean is request. You can modify the default scope.
// ... // import javax.faces.bean.RequestScoped; import javax.faces.bean.SessionScoped; @ManagedBean // @RequestScoped @SessionScoped public class UserBean { // ...
- @RequestScoped
- @SessionScoped
- @ApplicationScoped - one bean for all
- @ViewScoped - the same bean is used as long as the user stays on the page (this is for AJAX)
- @CustomScoped - stores the bean in a map; developer controls it
- @NoneScoped - not in scope. Normally referenced by other beans that are in scope
Because it’s a managed bean, you can use JEE goodies (such as @EJB etc.) if you run your application on a JEE server .
Read more about managed beans validation and dependency injection using annotations.
I think that the JSF way of doing dependency injection is somewhat cumbersome. If you’re on JEE 6, you may want to use the new CDI mechanism. Jacek Laskowski wrote an article on using CDI with Java SEE (so without a JEE6 server). The article is in Polish, but the source code isn’t.
web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Web Application</display-name> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> </web-app>
Note the PROJECT_STAGE property. It’s new to JSF 2.0. You can read more about PROJECT_STAGE on Ryan Lubke’s blog.
The views
The view with a form:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title>Index</title> </h:head> <h:body> <h:form> <h:inputText value="#{userBean.name}" /> <h:commandButton value="Send" action="#{userBean.send}" /> </h:form> </h:body> </html>
The result view:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title>Hello</title> </h:head> <h:body> <h1>Hello #{userBean.name}</h1> </h:body> </html>
Summary
We created a simple JSF 2.0 application that uses a single managed bean and has 2 views. On that I will build another example, perhaps something using CDI.
Download source code for this article
Labels:
Java,
JBoss,
JSF,
Maven,
Programming
2010-07-05
REST with Scala's Lift framework. Part 4 - DELETE
In my previous posts I described how to handle REST with Lift: GET, POST and PUT. Now it’s time for...
Delete is probably the most simple case. It only requires the object’s ID and it returns nothing (except for the HTTP code).
(I already did that with Spring 3.)
We are going to use DeleteRequest. For a more detailed description of this code, see the first post.
This would normally be some sort of business logic...
We return a Lift’s object - OkResponse.
It is no different (actually simpler) from the previous examples.
This completes the series! As said before, Spring 3 support is a lot better at this point, but we should wait to see what Lift 2.0 has to offer in this respect.
Download sample source code
REST with Lift: DELETE
Delete is probably the most simple case. It only requires the object’s ID and it returns nothing (except for the HTTP code).
(I already did that with Spring 3.)
Retrieve the request
We are going to use DeleteRequest. For a more detailed description of this code, see the first post.
class Boot { def boot { // where to search snippet LiftRules.addToPackages("me.m1key") LiftRules.statelessDispatchTable.append { // ... case Req(List("rest", "dogs", dogId), _, DeleteRequest) => () => DogsRestService.deleteDog(dogId) } } }
Processing the request
This would normally be some sort of business logic...
def deleteDog(dogId: String): Box[LiftResponse] = dogId match { case "1" => { Log.info("Deleting dog with ID: " + dogId) Full(OkResponse()) } case _ => return Empty }
We return a Lift’s object - OkResponse.
Summary
It is no different (actually simpler) from the previous examples.
This completes the series! As said before, Spring 3 support is a lot better at this point, but we should wait to see what Lift 2.0 has to offer in this respect.
Download sample source code
Labels:
Lift,
Maven,
Programming,
REST,
Scala
2010-07-03
REST with Scala's Lift framework. Part 3 - PUT
In the previous posts I explained how to handle GET and POST requests in Scala's Lift framework in a RESTful manner. Now it's time to look into...
PUT is for updating objects. It's not really different from POST from developer's point of view. It's just that you get an identifier of the object from request.
(I already did that for Spring 3, you may want to take a look: REST with Spring 3: PUT.)
It's very similar to POST, so you can check out the POST post (really cunning game play here, folks!) for more details.
Processing the request is very similar to the PUT case.
Similarly to the POST case, handling RESTful PUT requests in Lift 1.0 is not as comfortable as it is with Spring 3. I'm looking forward to seeing Lift 2.0 improvements in that matter.
Download source code for this article
PUT requests
PUT is for updating objects. It's not really different from POST from developer's point of view. It's just that you get an identifier of the object from request.
(I already did that for Spring 3, you may want to take a look: REST with Spring 3: PUT.)
Retrieve the request
package bootstrap.liftweb import me.m1key.rest.DogsRestService import net.liftweb.http._ class Boot { def boot { // where to search snippet LiftRules.addToPackages("me.m1key") LiftRules.statelessDispatchTable.append { // ... case request @ Req(List("rest", "dogs"), _, PutRequest) => () => DogsRestService.updateDog(request) } } }
It's very similar to POST, so you can check out the POST post (really cunning game play here, folks!) for more details.
Processing the request
Processing the request is very similar to the PUT case.
def updateDog(request: Req): Box[LiftResponse] = { var dogId = "" var dogName = "" request.xml match { case Full(<dog>{parameters @ _*}</dog>) => { for(parameter <- parameters){ parameter match { case <name>{name}</name> => dogName = name.text case <id>{id}</id> => dogId = id.text case _ => } } val dog = new Dog(dogId, dogName) Log.info("Updating a dog with id: " + dog.id) return Full(InMemoryResponse(dog.toXml.toString.getBytes("UTF-8"), List("Content-Type" -> "text/xml"), Nil, 200)) } case _ => Log.error("Invalid request"); Log.error("Request: " + request); Log.error("Request.xml: " + request.xml);Full(BadResponse()) } }
Summary
Similarly to the POST case, handling RESTful PUT requests in Lift 1.0 is not as comfortable as it is with Spring 3. I'm looking forward to seeing Lift 2.0 improvements in that matter.
Download source code for this article
Labels:
Lift,
Maven,
Programming,
REST,
Scala
2010-07-02
REST with Scala's Lift framework. Part 2 - POST
In my previous post I explained how to handle GET requests with Scala’s Lift framework in a RESTful way.
In this post I will show you how to...
Which is a bit different than handling GET, because you expect an actual object to be coming your way along with the request!
I am going to work with the same project as in Part 1. If you haven’t read it yet, you might want to do it now to make things clear.
(I already did that for Spring 3, you may want to take a look: REST with Spring 3: POST.)
It looks a bit different, because you assign the request to a value named also request (of type Req) and then you pass it to the service. You also narrow it down to POST requests with PostRequest.
This is how you process the request. It’s not quite neat.
If the request is correct, then we acquire the dog’s name and we create a new dog using that name. We then return it with HTTP code 200 (OK).
If the request is incorrect (for instance, no XML with a dog in it), then we use Lift’s BadResponse and pack it in a Full. That gives the user HTTP code 400.
Handling RESTful POST requests in Lift 1.0 is not as comfortable as it is with Spring 3. I’m looking forward to seeing Lift 2.0 improvements in that matter.
Download source code for this article
In this post I will show you how to...
Handle POST in Lift using REST
Which is a bit different than handling GET, because you expect an actual object to be coming your way along with the request!
I am going to work with the same project as in Part 1. If you haven’t read it yet, you might want to do it now to make things clear.
(I already did that for Spring 3, you may want to take a look: REST with Spring 3: POST.)
Retrieve the request
package bootstrap.liftweb import me.m1key.rest.DogsRestService import net.liftweb.http._ class Boot { def boot { // ... LiftRules.statelessDispatchTable.append { // ... case request @ Req(List("rest", "dogs"), _, PostRequest) => () => DogsRestService.addDog(request) } } }
It looks a bit different, because you assign the request to a value named also request (of type Req) and then you pass it to the service. You also narrow it down to POST requests with PostRequest.
Processing the request
This is how you process the request. It’s not quite neat.
def addDog(request: Req): Box[LiftResponse] = { var dogName = "" request.xml match { case Full(<dog>{parameters @ _*}</dog>) => { for(parameter <- parameters){ parameter match { case <name>{name}</name> => dogName = name.text case _ => } } val dog = new Dog("2", dogName) // Normally you'd assign a unique ID Log.info("Creating a dog with name: " + dog.name) return Full(InMemoryResponse(dog.toXml.toString.getBytes("UTF-8"), List("Content-Type" -> "text/xml"), Nil, 200)) } case _ => Log.error("Invalid request"); Log.error("Request: " + request); Log.error("Request.xml: " + request.xml);Full(BadResponse()) } }
If the request is correct, then we acquire the dog’s name and we create a new dog using that name. We then return it with HTTP code 200 (OK).
If the request is incorrect (for instance, no XML with a dog in it), then we use Lift’s BadResponse and pack it in a Full. That gives the user HTTP code 400.
Summary
Handling RESTful POST requests in Lift 1.0 is not as comfortable as it is with Spring 3. I’m looking forward to seeing Lift 2.0 improvements in that matter.
Download source code for this article
Labels:
Lift,
Maven,
Programming,
REST,
Scala
REST with Scala's Lift framework. Part 1 - GET
[See also: POST, PUT, DELETE]
A while ago I wrote a series of posts on REST protocol handling with Spring 3. Now it's time to look at handling REST with Lift - the web framework for Scala.
I have just started my adventure with Lift, so bear with me if something is not optimal (although I did my best to make sure it is) - and please point it out.
In this article I will show you how to handle GET requests using Lift. You can look at the corresponding Spring 3 post. For REST newbies I should recommend those two articles:
Normally I code in Eclipse, but this time I decided to use IntelliJ IDEA since it has a free community edition now and in my opinion it handles Scala better than the plugin available for Eclipse. You can download IntelliJ IDEA (I got version 9.0.2), but if you want to stick to Eclipse (or Notepad), it's fine.
Should you choose IntelliJ IDEA, you're going to have to (well, not really, but since you are using an IDE...) get the Scala plugin (which you should do through File -> Settings -> Plugins -> Available).
What you require is Maven.
Also, I'm going to use Scala version 2.7.3 and Lift 1.0.
I leave this step up to you - how you want to use Maven is really up to you (via IntelliJ IDEA, Eclipse, command line?). The archetype you should use is:
You should check your pom.xml file. If you got Scala version 2.7.1 (or any other than 2.7.3), you should update it to 2.7.3.
You should make sure your lift-webkit version is 1.0:
Another problem you might get is the DTD location in your web.xml file.
Wrong:
Correct:
When you build this project (call a Maven target jetty:run), you might get an error:
That's a problem with your Boot.scala file. It can be easily fixed by replacing "/" with
Or delete the whole SiteMap thing altogether, we won't need it in this project.
This is not really that important - in your real life application you will replace this code with something that actually does something useful. Anyway, please take a look:
It is a Scala object so that we don't need an instance of it. It defines one method, getDog by ID, and has a very dummy implementation. The interesting part is this line:
Lift defines Full/Empty concept. This is similar to Scala's native Option: Some/None concept (it's about avoiding nulls). If your rest handling method returns Empty, then the client gets a 404 error. Otherwise, you must return a Full containing InMemoryResponse.
InMemoryResponse takes four parameters:
Perhaps you noticed this call in the previous code sample:
Scala has pretty cool XML support. Here's the actual Dog class.
The toXml method returns a scala.xml.Elem. Note the Expression Language-like usage of the id and name properties.
Let's see how we can test it.
Why JUnit 3? Well, that's what the archetype gives you out of the box. If you don't like it, you can use specs. Here's my article on how to use the Specs library in Eclipse.
See how I am using the Scala way of accessing data in an XML document (line 25.)?
Now let's see how our DogRestService.getDog method can be called.
You put proper code in the Boot.scala file (it's the bootstrap code that is called on application start up).
Let's analyze it line by line.
You must tell Lift where (in which packages) to look for views and templates and snippets etc.:
This is how you would add a new rewriting rule if you wanted to have access to the S object as well ass LiftSession:
Next, you must add a new URL rewriting rule:
Create a new rule:
The second parameter (left blank) is the suffix, and the third one specifies that we only want to handle GET requests.
The declaration of this looks a bit confusing (it did to me), so it helps to realize that it is a partial function.
And that's all you need!
Now just run it (jetty:run) in the browser (http://localhost:8080/rest/dogs/1) and see for yourself.
In this article I showed you how to handle GET requests with the Lift framework, how to do a bit of unit testing and how to use redirection rules.
At this moment I don't know whether we can simulate the requests (like it is possible with Spring) from integration tests.
Download source code for this article
Lift 2.0 has just been released. They claim that it has better REST support. As soon as more is available on this topic, I will write an article on it as well.
A while ago I wrote a series of posts on REST protocol handling with Spring 3. Now it's time to look at handling REST with Lift - the web framework for Scala.
I have just started my adventure with Lift, so bear with me if something is not optimal (although I did my best to make sure it is) - and please point it out.
In this article - handle GET requests
In this article I will show you how to handle GET requests using Lift. You can look at the corresponding Spring 3 post. For REST newbies I should recommend those two articles:
The means
Normally I code in Eclipse, but this time I decided to use IntelliJ IDEA since it has a free community edition now and in my opinion it handles Scala better than the plugin available for Eclipse. You can download IntelliJ IDEA (I got version 9.0.2), but if you want to stick to Eclipse (or Notepad), it's fine.
Should you choose IntelliJ IDEA, you're going to have to (well, not really, but since you are using an IDE...) get the Scala plugin (which you should do through File -> Settings -> Plugins -> Available).
What you require is Maven.
Also, I'm going to use Scala version 2.7.3 and Lift 1.0.
Create a project from archetype
I leave this step up to you - how you want to use Maven is really up to you (via IntelliJ IDEA, Eclipse, command line?). The archetype you should use is:
net.liftweb:lift-archetype-blank:RELEASE
You should check your pom.xml file. If you got Scala version 2.7.1 (or any other than 2.7.3), you should update it to 2.7.3.
<properties> <scala.version>2.7.3</scala.version> </properties>
You should make sure your lift-webkit version is 1.0:
<dependency> <groupId>net.liftweb</groupId> <artifactId>lift-webkit</artifactId> <version>1.0</version> </dependency>
Another problem you might get is the DTD location in your web.xml file.
Wrong:
http://java.sun.com/j2ee/dtds/web-app_2_3.dtd
Correct:
http://java.sun.com/dtd/web-app_2_3.dtd
When you build this project (call a Maven target jetty:run), you might get an error:
[WARNING] found : java.lang.String("/") [WARNING] required: net.liftweb.sitemap.Loc.Link[net.liftweb.sitemap.NullLocParams] [WARNING] (Menu(Loc("Home", "/", "Home"))
That's a problem with your Boot.scala file. It can be easily fixed by replacing "/" with
List("/")
Or delete the whole SiteMap thing altogether, we won't need it in this project.
Business logic
This is not really that important - in your real life application you will replace this code with something that actually does something useful. Anyway, please take a look:
package me.m1key.rest import me.m1key.model.Dog import net.liftweb.util.{Full, Empty, Box} import net.liftweb.http.{InMemoryResponse, LiftResponse} object DogsRestService { def getDog(dogId: String): Box[LiftResponse] = dogId match { case "1" => { val dog: Dog = new Dog("1", "Sega") return Full(InMemoryResponse(dog.toXml.toString.getBytes("UTF-8"), List("Content-Type" -> "text/xml"), Nil, 200)) } case _ => return Empty } }
It is a Scala object so that we don't need an instance of it. It defines one method, getDog by ID, and has a very dummy implementation. The interesting part is this line:
return Full(InMemoryResponse(dog.toXml.toString.getBytes("UTF-8"), List("Content-Type" -> "text/xml"), Nil, 200))
Lift defines Full/Empty concept. This is similar to Scala's native Option: Some/None concept (it's about avoiding nulls). If your rest handling method returns Empty, then the client gets a 404 error. Otherwise, you must return a Full containing InMemoryResponse.
InMemoryResponse takes four parameters:
- The actual content of the response
- Headers
- Cookies
- HTTP code to return to the client
Scala XML herding
Perhaps you noticed this call in the previous code sample:
dog.toXml
Scala has pretty cool XML support. Here's the actual Dog class.
package me.m1key.model class Dog(id: String, name: String) { def toXml = <dog> <id>{id}</id> <name>{name}</name> </dog> }
The toXml method returns a scala.xml.Elem. Note the Expression Language-like usage of the id and name properties.
Let's see how we can test it.
Test it with JUnit 3
Why JUnit 3? Well, that's what the archetype gives you out of the box. If you don't like it, you can use specs. Here's my article on how to use the Specs library in Eclipse.
package me.m1key.model import junit.framework.{TestCase, TestSuite, Test} import junit.framework.Assert._ object DogTest { def suite: Test = { val suite = new TestSuite(classOf[DogTest]); suite } def main(args : Array[String]) { junit.textui.TestRunner.run(suite); } } /** * Unit test. */ class DogTest extends TestCase("dog") { val dog: Dog = new Dog("1", "Sega") def testDogToXmlCorrectName = { assertEquals("Sega", (dog.toXml \ "name").text) } }
See how I am using the Scala way of accessing data in an XML document (line 25.)?
Handling REST requests
Now let's see how our DogRestService.getDog method can be called.
You put proper code in the Boot.scala file (it's the bootstrap code that is called on application start up).
package bootstrap.liftweb import me.m1key.rest.DogsRestService import net.liftweb.http.{GetRequest, RequestType, Req, LiftRules} /** * A class that's instantiated early and run. It allows the application * to modify lift's environment */ class Boot { def boot { // where to search snippet LiftRules.addToPackages("me.m1key") // LiftRules.dispatch.append LiftRules.statelessDispatchTable.append { case Req(List("rest", "dogs", dogId), _, GetRequest) => () => DogsRestService.getDog(dogId) } } }
Let's analyze it line by line.
You must tell Lift where (in which packages) to look for views and templates and snippets etc.:
LiftRules.addToPackages("me.m1key")
This is how you would add a new rewriting rule if you wanted to have access to the S object as well ass LiftSession:
// LiftRules.dispatch.append {
Next, you must add a new URL rewriting rule:
LiftRules.statelessDispatchTable.append {
Create a new rule:
case Req(List("rest", "dogs", dogId), _, GetRequest) =>The List("rest", "dogs", dogId) part means that we expect a URL in this form:
/rest/dogs/1The 1 will be assigned to dogId variable (see Scala Pattern Matching).
The second parameter (left blank) is the suffix, and the third one specifies that we only want to handle GET requests.
The declaration of this looks a bit confusing (it did to me), so it helps to realize that it is a partial function.
() => DogsRestService.getDog(dogId)
And that's all you need!
Now just run it (jetty:run) in the browser (http://localhost:8080/rest/dogs/1) and see for yourself.
<dog> <id>1</id> <name>Sega</name> </dog>
Summary
In this article I showed you how to handle GET requests with the Lift framework, how to do a bit of unit testing and how to use redirection rules.
At this moment I don't know whether we can simulate the requests (like it is possible with Spring) from integration tests.
Download source code for this article
Note
Lift 2.0 has just been released. They claim that it has better REST support. As soon as more is available on this topic, I will write an article on it as well.
Labels:
Lift,
Maven,
Programming,
REST,
Scala
2010-06-30
Integration testing your Spring 3 & JPA 2.0 application
In my previous posts, I explained the following:
Now, one thing that is missing in this picture is...
There is a presentation by Rod Johnson of Spring on testing with Spring that explains you what unit testing and what integration testing is, what mock objects are and some of the best practices. The presentation itself is from 2007 and while the general ideas haven't changed, the implementation techniques have.
Therefore in this article I will show you how to integration test your DAO classes. I am going to use a JPA project for this, but the same test code will work for Hibernate as well.
Integration testing is another level of tests; while unit tests test pieces of code in separation, integration tests test the bigger picture. Unit tests don't go to data sources, they are fast and simple. Integration tests hit the data sources and test multiple modules together.
So, you should have a database set up, in a well known state. This should not be the production database! But it should be identical (or as close as possible).
On this database you perform the tests. This is better than mock objects, because although you can simulate certain behaviors with mock objects, it's nothing compared to using a real database, with its triggers, views, stored procedures etc.
Integration testing that involves a data source, whether you use Spring or, say, DBUnit, often works according to the same schema.
You mess around with the database, add, update, remove. Then all the changes are reverted.
With Spring, they are rolled back.
Prior to Spring 3 the recommended way of testing JPA was to use AbstractJpaTests - but not anymore; now it's deprecated. The official documentation suggests you use (extend) AbstractJUnit38SpringContextTests. You would rather use AbstractJUnit4SpringContextTests if you use JUnit 4. But both strategies require extending and Java allows for inheritance only (which is good), so I will show you an alternative way of doing it.
Alright! Let's explain these annotations, one by one.
NOTE: Some configurations also use this annotation:
And now a test method.
In the previous posts I screwed up dependencies - yes. I imported spring-dao, version 2.0.8 - WRONG. Here's the correct dependency set for the whole project:
Previously I was getting this:
Apart from JUnit traditional annotations, such as @Before and @BeforeClass, you can also use:
In this article I showed you how to integration test DAO classes with Spring 3.
Download source code for this article
- How to create a Spring 3, JPA 2.0, Maven project
- How to manage transactions in Spring
- and how to refactor your DAO classes to use entity managers from JEE (even if you are on Java SE)
Now, one thing that is missing in this picture is...
Testing DAO classes
There is a presentation by Rod Johnson of Spring on testing with Spring that explains you what unit testing and what integration testing is, what mock objects are and some of the best practices. The presentation itself is from 2007 and while the general ideas haven't changed, the implementation techniques have.
Therefore in this article I will show you how to integration test your DAO classes. I am going to use a JPA project for this, but the same test code will work for Hibernate as well.
Integration Testing principles
Integration testing is another level of tests; while unit tests test pieces of code in separation, integration tests test the bigger picture. Unit tests don't go to data sources, they are fast and simple. Integration tests hit the data sources and test multiple modules together.
So, you should have a database set up, in a well known state. This should not be the production database! But it should be identical (or as close as possible).
On this database you perform the tests. This is better than mock objects, because although you can simulate certain behaviors with mock objects, it's nothing compared to using a real database, with its triggers, views, stored procedures etc.
How does it, uhm, how does it work?
Integration testing that involves a data source, whether you use Spring or, say, DBUnit, often works according to the same schema.
You mess around with the database, add, update, remove. Then all the changes are reverted.
With Spring, they are rolled back.
Integration testing with Spring 3
Prior to Spring 3 the recommended way of testing JPA was to use AbstractJpaTests - but not anymore; now it's deprecated. The official documentation suggests you use (extend) AbstractJUnit38SpringContextTests. You would rather use AbstractJUnit4SpringContextTests if you use JUnit 4. But both strategies require extending and Java allows for inheritance only (which is good), so I will show you an alternative way of doing it.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "file:src/test/resources/applicationContext-test.xml" }) @TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true) @Transactional public class DogsDaoImplTest { // ...
Alright! Let's explain these annotations, one by one.
- @RunWith(SpringJUnit4ClassRunner.class) - this means that JUnit will enable the functionality of the Spring TextContext Framework. That makes it possible for you to use Spring goodies (annotations like @Autowired etc.) in the tests
- @ContextConfiguration - tells Spring where the beans files are. Note the format. This way it works within Eclipse, within Ant, within Maven, from Hudson etc.
- @TransactionConfiguration - here we configure the transaction. We specify the manager to use and if rollback should be the default thing to do when a transaction ends (a bit explicit - the default is true anyhow)
- @Transactional - all methods must run in transactions so that their effects can be rolled back
NOTE: Some configurations also use this annotation:
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class })But the code works without it... I don't see why it should be used. Perhaps someone can clarify on that.
And now a test method.
@Autowired private DogsDao dogsDaoImpl; @Test public void testPersistDog() { long dogsBefore = dogsDaoImpl.retrieveNumberOfDogs(); Dog dog = new Dog(); dog.setName("Fluffy"); dogsDaoImpl.persistDog(dog); long dogsAfter = dogsDaoImpl.retrieveNumberOfDogs(); assertEquals(dogsBefore + 1, dogsAfter); }
Dependencies
In the previous posts I screwed up dependencies - yes. I imported spring-dao, version 2.0.8 - WRONG. Here's the correct dependency set for the whole project:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>me.m1key</groupId> <artifactId>springtx</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.5.3-Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.5.3-Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.5.3-Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.0-api</artifactId> <version>1.0.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.5.3-Final</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.5.8</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.8</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> </dependencies> <repositories> <repository> <id>r.j.o-groups-public</id> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> </project>
Previously I was getting this:
java.lang.NoSuchMethodError: org.springframework.transaction.interceptor. TransactionAttribute.getQualifier()Ljava/lang/String;Now it's fixed.
Other possibilities
Apart from JUnit traditional annotations, such as @Before and @BeforeClass, you can also use:
- @BeforeTransaction (org.springframework.test.context.transaction.BeforeTransaction)
- @AfterTransaction (org.springframework.test.context.transaction.AfterTransaction)
Summary
In this article I showed you how to integration test DAO classes with Spring 3.
Download source code for this article
Labels:
Java,
JPA,
Maven,
Programming,
Spring
2010-06-28
Spring transaction management: org.hibernate.SessionException: Session is closed!
If you got this exception:
... and you are using Spring transaction management, then the reason might be that your DAO method (the method that threw it and that uses persistence context) is not transactional and it should be:
See my article on correct setup of Spring 3 & JPA 2.0.
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.SessionException: Session is closed!
... and you are using Spring transaction management, then the reason might be that your DAO method (the method that threw it and that uses persistence context) is not transactional and it should be:
import org.springframework.transaction.annotation.Transactional; //... @Transactional(readOnly = true) public List<Dog> retrieveAllDogs() { return em.createQuery("from Dog").getResultList(); } //...
See my article on correct setup of Spring 3 & JPA 2.0.
Labels:
Hibernate,
Java,
JPA,
Programming,
Spring
2010-06-27
Removing JpaTemplate in favor of injected @PersistenceContext
In the previous two articles (Spring, JPA 2.0 & Maven and Spring transaction management) I showed you how to create a project that utilizes Spring 3, JPA 2.0 and Maven, that does not require a server and that offers transaction handling.
However, I used Spring's JpaTemplate which got some attention from Tomek Nurkiewicz who pointed out that this is not really a recommended way of doing it.
The recommended way of handling JPA in your DAO classes is to use an EntityManager injected with JEE's @PersistenceContext annotation.
Let's see what the configuration looks like.
Here's the whole file:
We removed an additional thin layer of JpaTemplate.
Many sites (e.g. the official Hibernate site) will tell you you cannot use @PersistenceContext in Java SE applications - well we just did, thanks to Spring (thanks to PersistenceAnnotationBeanPostProcessor).
I got some of the information from the blog by Łukasz.
Download source code for this article
However, I used Spring's JpaTemplate which got some attention from Tomek Nurkiewicz who pointed out that this is not really a recommended way of doing it.
The recommended way of handling JPA in your DAO classes is to use an EntityManager injected with JEE's @PersistenceContext annotation.
Let's see what the configuration looks like.
Your Spring beans file
- Remove the jpaTemplate bean declaration.
- Remove the jpaTemplate bean references.
- Add PersistenceAnnotationBeanPostProcessor.
Here's the whole file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="Dogs" /> </bean> <bean id="dogsDao" class="me.m1key.springtx.dao.DogsDaoImpl" /> <bean id="dogsBean" class="me.m1key.springtx.beans.DogsBean" scope="singleton"> <property name="dogsDao" ref="dogsDao" /> </bean> <tx:annotation-driven transaction-manager="myTransactionManager" /> <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> </beans>
Your DAO class
- Remove extending JpaDaoSupport.
- Add @PersistenceContext injected EntityManager.
- Replace getJpaTemplate() with the EntityManager (that's not always a non-brainer).
- Make each DAO method @Transactional (you can set its readOnly attribute to true if the method only reads data).
package me.m1key.springtx.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.transaction.annotation.Transactional; import me.m1key.springtx.entities.Dog; public class DogsDaoImpl implements DogsDao { @PersistenceContext private EntityManager em; @SuppressWarnings("unchecked") @Transactional(readOnly = true) public List<Dog> retrieveAllDogs() { return em.createQuery("from Dog").getResultList(); } @Transactional(readOnly = true) public Long retrieveNumberOfDogs() { System.out.println(em); return (Long) em.createQuery( "select count(d) from Dog d") .getSingleResult(); } @Transactional(readOnly = false) public void persistDog(Dog dog) { em.persist(dog); } }
Summary
We removed an additional thin layer of JpaTemplate.
Many sites (e.g. the official Hibernate site) will tell you you cannot use @PersistenceContext in Java SE applications - well we just did, thanks to Spring (thanks to PersistenceAnnotationBeanPostProcessor).
I got some of the information from the blog by Łukasz.
Download source code for this article
Labels:
Java,
JPA,
Programming,
Spring
Spring 3 transaction management
In this article I will show you how to handle transaction management with Spring.
Great! Let's begin with some basic information you may want to skip if you already know about transactions.
Transactions ensure that the data in your application (in the data source) stays consistent. You should also be familiar with the ACID concept.
Now, in Java you can handle transactions with plain SQL, with plain JDBC (a bit higher level), using Hibernate (or any other ORM library), or on an even higher level - with EJB or, finally, Spring!
EJBs require an application server, but our application presented here - doesn't.
Spring offers two ways of handling transactions: programmatic and declarative. If you are familiar with EJB transaction handling, this corresponds to bean-managed and container-managed transaction management.
Programmatic means you have transaction management code surrounding your business code. That gives you extreme flexibility, but is difficult to maintain and, well, boilerplate.
Declarative means you separate transaction management from the business code. You only use annotations or XML based configuration.
We say that:
We will focus on declarative management.
OK, a small description of what we want to achieve and how.
The goals:
The means:
We are going to build on the project I used in my previous post on Spring & JPA 2.0.
We must first specify that we want to use annotation driven transaction management.
And, of course, the transaction manager itself:
What we are using here is the JpaTransactionManager. There are more managers available:
It references a bean called entityManagerFactory. Here it is:
@Transactional is the annotation you can use on any method of any bean and on the bean itself.
If you apply the annotation on the bean (i.e. on the class level), every public method will be transactional.
Note: Remember that it affects only Spring managed data sources (in our example whatever comes from the entity manager factory). If you get your data source outside of Spring, the @Transactional annotation will have no effect.
You should put this annotation on your business logic methods (service methods), not on DAO methods (unless you know what you're doing) - that's a rule of thumb. Normally a business method will call many DAO methods and those calls make only sense when made together, every single one or none (atomicity).
Whenever a transactional method is called, a decision is made - what to do with the transaction. Create a new one? Use an existing one if it exists, otherwise create a new one? Use an existing one only if it exists, otherwise fail?
To make it possible for you to specify this, propagation behaviors exist.
See the behaviors:
It is up to you to decide which behavior is best for each method. REQUIRED is the default one.
Note: If you are using the XML setup for transactions, you can also configure these behaviors there instead of Java code.
Concurrent transactions cause problems that might be difficult to investigate.
Now, the perfect solution to these problems is maximum isolation, but in reality this would cost too much resources and could lead to deadlocks. So, instead, you will set one of five isolation levels (where the fifth one is actually the maximum isolation level):
The default choice is DEFAULT.
HSQLDB 2.0 supports READ_COMMITTED and SERIALIZABLE levels (HSQLDB FAQ).
With Spring transaction management the default behavior for automatic rollback is this: Only unchecked exceptions cause a rollback. Unchecked exceptions are RuntimeExceptions and Errors.
That's the default behavior. However, you may want to change it for certain cases:
Note: If you are using the XML setup for transactions, you can also configure these rules there instead of Java code.
You've seen it before.
That's all!
You have to use the classic AOP approach. org.springframework.transaction.interceptor.TransactionProxyFactoryBean might be your starting point.
You may want to go for something like this:
That's it! Although the transactions themselves are by no means a trivial topic, Spring makes at least handling them easy.
I got my knowledge mostly from this book:
Spring Recipes: A Problem-Solution Approach
It helps me run this website if you buy this book through this link, thanks!
A brief intro to HSQLDB and how to use it in this app (Note that the project in that article is NOT a Maven project, but an Eclipse JPA one, so the project creating part doesn't matter)?
Read on: Remove JpaTemplate in favor of @PersistenceContext.
Download the source code for this article
Benefits of Spring Transaction Management
- Very easy to use, does not require any underlying transaction API knowledge
- Your transaction management code will be independent of the transaction technology
- Both annotation- and XML-based configuration
- It does not require to run on a server - no server needed
Great! Let's begin with some basic information you may want to skip if you already know about transactions.
Overview
Transactions ensure that the data in your application (in the data source) stays consistent. You should also be familiar with the ACID concept.
Now, in Java you can handle transactions with plain SQL, with plain JDBC (a bit higher level), using Hibernate (or any other ORM library), or on an even higher level - with EJB or, finally, Spring!
EJBs require an application server, but our application presented here - doesn't.
Programmatic vs. Declarative
Spring offers two ways of handling transactions: programmatic and declarative. If you are familiar with EJB transaction handling, this corresponds to bean-managed and container-managed transaction management.
Programmatic means you have transaction management code surrounding your business code. That gives you extreme flexibility, but is difficult to maintain and, well, boilerplate.
Declarative means you separate transaction management from the business code. You only use annotations or XML based configuration.
We say that:
- programmatic management is more flexible during development time but less flexible during application life
- declarative management is less flexible during development time but more flexible during application life
In this article...
We will focus on declarative management.
OK, a small description of what we want to achieve and how.
The goals:
- A desktop application (i.e. it doesn't need a server)
- Declarative transaction management with minimum XML
The means:
- A Maven project created in Eclipse and making use of SpringIDE
- Spring transaction management
- Java with annotations enabled (I'm going to use Java 6)
- JPA 2.0
We are going to build on the project I used in my previous post on Spring & JPA 2.0.
Transaction Manager
We must first specify that we want to use annotation driven transaction management.
<tx:annotation-driven transaction-manager="myTransactionManager" />
And, of course, the transaction manager itself:
<bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
What we are using here is the JpaTransactionManager. There are more managers available:
- DataSourceTransactionManager - for single data source and JDBC
- JtaTransactionManager - for JTA
- HibernateTransactionManager - for Hibernate
It references a bean called entityManagerFactory. Here it is:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="Dogs" /> </bean>
Annotation based
@Transactional is the annotation you can use on any method of any bean and on the bean itself.
import org.springframework.transaction.annotation.Transactional; // ... @Transactional public void doSomething(... // ...
If you apply the annotation on the bean (i.e. on the class level), every public method will be transactional.
Note: Remember that it affects only Spring managed data sources (in our example whatever comes from the entity manager factory). If you get your data source outside of Spring, the @Transactional annotation will have no effect.
Where to put @Transactional
You should put this annotation on your business logic methods (service methods), not on DAO methods (unless you know what you're doing) - that's a rule of thumb. Normally a business method will call many DAO methods and those calls make only sense when made together, every single one or none (atomicity).
Transaction Propagation
Whenever a transactional method is called, a decision is made - what to do with the transaction. Create a new one? Use an existing one if it exists, otherwise create a new one? Use an existing one only if it exists, otherwise fail?
To make it possible for you to specify this, propagation behaviors exist.
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; // ... @Transactional(propagation = Propagation.REQUIRED) public void doSomething(... // ...
See the behaviors:
- REQUIRED - uses the existing transaction. If it doesn't exist, creates a new one
- REQUIRES_NEW - must start a new transaction. If there's an existing one, it should be suspended
- SUPPORTS - if there is a transaction, runs in it. If there isn't, it just runs outside transaction context
- NOT_SUPPORTED - must not run in a transaction. If there's an existing one, it should be suspended
- MANDATORY - must run in a transaction. If there isn't one, it throws an exception
- NEVER - must not run in a transaction. If there's an existing one, an exception will be thrown
- NESTED - if there is a transaction, it runs withing the nested transaction of it. Otherwise it runs in its own
It is up to you to decide which behavior is best for each method. REQUIRED is the default one.
Note: If you are using the XML setup for transactions, you can also configure these behaviors there instead of Java code.
Transaction Isolation
Concurrent transactions cause problems that might be difficult to investigate.
- Lost update - two transactions both update a row, the second transaction aborts, both changes are lost
- Dirty read - reading changes that are not yet committed
- Unrepeatable read - a transactions read twice the same row, getting different data each time
- Phantom read - similar to the previous one, except that the number of rows changed
Now, the perfect solution to these problems is maximum isolation, but in reality this would cost too much resources and could lead to deadlocks. So, instead, you will set one of five isolation levels (where the fifth one is actually the maximum isolation level):
- DEFAULT - uses the default database isolation level
- READ_UNCOMMITTED - dirty read, unrepeatable read, phantom read problems may occur, but not lost update
- READ_COMMITTED - unrepeatable read, phantom read problems my occur
- REPEATABLE_READ - phantom read problems my occur
- SERIALIZABLE - all problems avoided! But performance is low
The default choice is DEFAULT.
HSQLDB 2.0 supports READ_COMMITTED and SERIALIZABLE levels (HSQLDB FAQ).
... and roll...back! Transaction Rollback
With Spring transaction management the default behavior for automatic rollback is this: Only unchecked exceptions cause a rollback. Unchecked exceptions are RuntimeExceptions and Errors.
import org.springframework.transaction.annotation.Transactional; // ... @Transactional public void doSomething(... // ...Think about it for a second! Are you sure you understand what it does?
- If the doSomething method terminates its execution naturally, with no exceptions, the transaction is committed
- If the doSomething method or any other method it calls throws any kind of exception that is caught within doSomething or this other method and not rethrown, the transaction is committed
- If the doSomething method or any other method it calls throws any kind of checked exception that is not caught or is caught and rethrown, the transaction is committed (so everything up to the moment of the exception being thrown is persisted)
- If the doSomething method or any other method it calls throws any kind of unchecked exception that is not caught, the transaction is rolled back (so nothing saved in this transaction is persisted)
That's the default behavior. However, you may want to change it for certain cases:
@Transactional(rollbackFor = IOException.class, noRollbackFor = RuntimeException.class) public void doSomething(...Here I asked the transaction manager to rollback for IOExceptions and not to rollback for RuntimeExceptions.
Note: If you are using the XML setup for transactions, you can also configure these rules there instead of Java code.
Our sample application
Spring beans file
You've seen it before.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> ... <tx:annotation-driven transaction-manager="myTransactionManager" /> <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="Dogs" /> </bean> ...
Using transactions
import org.springframework.transaction.annotation.Transactional; // ... @Transactional public void doSomething(... // ...
That's all!
What if you...
What if you are using Spring 1.x?
You have to use the classic AOP approach. org.springframework.transaction.interceptor.TransactionProxyFactoryBean might be your starting point.
What if you want to declare transactions in XML and not in the code?
You may want to go for something like this:
<tx:advice id="dogsTxAdvice" transaction-manager="myTransactionManager"> <tx:attributes> <tx:method name="persistDog" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="dogsOperation" expression="execution(* me.m1key.springtx.beans.DogsBean.*(..))" /> <aop:advisor advice-ref="dogsTxAdvice" pointcut-ref="dogsOperation" /> </aop:config>
Summary
That's it! Although the transactions themselves are by no means a trivial topic, Spring makes at least handling them easy.
I got my knowledge mostly from this book:
Spring Recipes: A Problem-Solution Approach
It helps me run this website if you buy this book through this link, thanks!
A brief intro to HSQLDB and how to use it in this app (Note that the project in that article is NOT a Maven project, but an Eclipse JPA one, so the project creating part doesn't matter)?
Read on: Remove JpaTemplate in favor of @PersistenceContext.
Download the source code for this article
Subscribe to:
Posts (Atom)