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:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class DogsBean {
// ...

NOTE: I am using JBoss 6 M3.

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.


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

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.



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
And these are entity lifecycle events. See Section 3.6 of JSR 317 for more details.

JSF calls validation upon:
  • the process validation phase
See Section 2.5.7 of JSR 314 for more details.


Next article


In the next article I will show you how to define custom constraints and more.

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.


@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.

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...

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 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?


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

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...


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

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 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

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...


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

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 - 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/1
The 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.