Saturday 14 May 2011

How to call Jersey RESTful service from Sencha Touch application

Introduction

This article describes how to create RESTful service using Jersey library (JAX-RS reference implementation) and call this service from Sencha Touch-based application. Sencha can consume JSONP services, where Jersey returns JSON response by default (what is the difference?). To make this two frameworks work together, you must configure Jersey service properly.

Prerequisites
  • JDK 6, 
  • Eclipse IDE with m2eclipse plugin, 
  • Maven 2 (standalone or bundled with Eclipse Helios),
  • Chrome web browser.
    Table of contents
    1. Create Jersey project in Eclipse.
    2. Create JSONP RESTful service.
    3. Create Sencha Touch client application.
    4. Summary.
    Sources

      Create Jersey project in Eclipse

      First, we will create simple Jersey RESTful service.

      Let's generate Jersey application from Maven archetype. To do this, you have to download archetype catalog file. Catalog file will contain location of archetype we want to use (it will be jersey-quickstart-grizzly).

      Download the following file: http://download.java.net/maven/2/archetype-catalog.xml
      and save it in your .m2 directory (on my computer it is C:\Users\bzawadka\.m2\).

      Start your Eclipse IDE and create a new project. Click File > New > Project...
      Select Maven Project and click Next.


      Click Next again (do not skip archetype selection).
      In Catalog dropdown choose Default local. Choose jersey-quickstart-grizzly artifact. Click Next.



      Fill out all Artifact fields (Group Id, Artifact Id, Version, Name) and click Next.


      Now is the time to check whether the project is working properly.
      Hit Ctrl+Shift+X and M to run the project as Maven build.
      Enter clean compile exec:java in Goals textbox. After that, click Apply and Run.

      Our Jersey service should be now running:


      Open your web browser and go to this address: http://localhost:9998/myresource


      Congratulations, your Jersey service is working!
      Now stop the Grizzly server by pressing Enter in Eclipse Console.


      Create JSONP RESTful service

      Simple Jersey service is now running, let's create a new service, which will return JSONP data.
      Create new package - pl.bzawadka.poc.jsonp.dto with two classes - InvoiceDto and InvoiceListDto.


      InvoiceListDto class should look like this:
      package pl.bzawadka.poc.jsonp.dto;
      
      import java.net.URL;
      import java.util.Date;
      
      import javax.xml.bind.annotation.XmlRootElement;
      
      @XmlRootElement(name = "simpleInvoice")
      public class InvoiceDto {
       private int invoiceId;
       private String billNumber;
       private Date invoiceDate;
       private Double invoiceAmount;
       private URL downloadLink;
      
       public InvoiceDto() {
       }
      
       public InvoiceDto(int invoiceId, String billNumber, Date invoiceDate, double invoiceAmount) {
        this.invoiceId = invoiceId;
        this.billNumber = billNumber;
        this.invoiceDate = invoiceDate;
        this.invoiceAmount = invoiceAmount;
       }
      
       public int getInvoiceId() {
        return invoiceId;
       }
      
       public void setInvoiceId(int invoiceId) {
        this.invoiceId = invoiceId;
       }
      
       public String getBillNumber() {
        return billNumber;
       }
      
       public void setBillNumber(String billNumber) {
        this.billNumber = billNumber;
       }
      
       public Date getInvoiceDate() {
        return invoiceDate;
       }
      
       public void setInvoiceDate(Date invoiceDate) {
        this.invoiceDate = invoiceDate;
       }
      
       public Double getInvoiceAmount() {
        return invoiceAmount;
       }
      
       public void setInvoiceAmount(Double invoiceAmount) {
        this.invoiceAmount = invoiceAmount;
       }
      
       public URL getDownloadLink() {
        return downloadLink;
       }
      
       public void setDownloadLink(URL downloadLink) {
        this.downloadLink = downloadLink;
       }
      }
      

      ... where InvoiceListDto class should look like this:
      package pl.bzawadka.poc.jsonp.dto;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import javax.xml.bind.annotation.XmlElement;
      import javax.xml.bind.annotation.XmlRootElement;
      
      @XmlRootElement(name = "invoices")
      public class InvoiceListDto {
      
       private List<InvoiceDto> simpleInvoices = new ArrayList<InvoiceDto>();
      
       public InvoiceListDto() {
       }
      
       public InvoiceListDto(List<InvoiceDto> simpleInvoices) {
        this.simpleInvoices = simpleInvoices;
       }
      
       @XmlElement(name = "invoice")
       public List<InvoiceDto> getSimpleInvoices() {
        return simpleInvoices;
       }
      
       public void setSimpleInvoices(List<InvoiceDto> simpleInvoices) {
        this.simpleInvoices = simpleInvoices;
       }
      }
      

      Now it is high time to update MyResource class. First, we will create new service, which will return standard JSON response. Check out getInvoicesForCustomerJson method!
      App class should look like this:

      package pl.bzawadka.poc.jsonp;
      
      import java.util.ArrayList;
      import java.util.Date;
      import java.util.List;
      
      import javax.ws.rs.*;
      import javax.ws.rs.core.*;
      import pl.bzawadka.poc.jsonp.dto.*;
      
      @Path("/myresource")
      public class MyResource {
      
       @GET
       @Produces("text/plain")
       public String getIt() {
        return "Got it!";
       }
      
       @GET
       @Path("invoicejson/{accountId}")
       @Produces({ MediaType.APPLICATION_JSON })
       public Response getInvoicesForCustomerJson(
         @PathParam(value = "accountId") String accountId) {
      
        InvoiceListDto invoices = generateMockData();
      
        return Response.ok(invoices).build();
       }
      
       private InvoiceListDto generateMockData() {
        List<InvoiceDto> invoices = new ArrayList<InvoiceDto>();
        invoices.add(new InvoiceDto(1, "37897-001", new Date(), 58.92));
        invoices.add(new InvoiceDto(2, "37897-002", new Date(), 293.63));
        invoices.add(new InvoiceDto(3, "37897-003", new Date(), 173.3));
        invoices.add(new InvoiceDto(4, "37897-004", new Date(), 170.71));
        return new InvoiceListDto(invoices);
       }
      }
      

      After you run the build (Alt+Shift+X, M), go to web browser: http://localhost:9998/myresource/invoicejson/1234


      As you can see, this is a "normal" JSON. Unfortunately, this response will not be consumed by Sencha Touch.

      Let's create a new method, which will return JSONP. We have to use a new class - JSONWithPadding. Using this class, the result will be wrapped around a JavaScript callback function, whose name by default is "callback". We have to change media type to application/x-javascript as well.
      Add getInvoicesForCustomerJsonp method to MyResource class:

      @GET
       @Path("invoice/{accountId}")
       @Produces({ "application/x-javascript" })
       public JSONWithPadding getInvoicesForCustomerJsonp(
         @PathParam(value = "accountId") String accountId,
         @QueryParam("callback") String callback) {
      
        InvoiceListDto invoices = generateMockData();
      
        return new JSONWithPadding(invoices, callback);
       }

      Run the build and check new URL: http://localhost:9998/myresource/invoicejsonp/1234


      Now we have JSONP! You can see that JSON object is passed as an argument of callback method.


      Create Sencha Touch client application

      Create a html file and fill it with the following content:
      <!DOCTYPE html>
      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <title>Hello Jersey</title>
      
      <script src="lib/touch/sencha-touch.js" type="text/javascript"></script>
      <link href="lib/touch/resources/css/sencha-touch-debug.css" rel="stylesheet" type="text/css" />
      <script>
      
      new Ext.Application({
       launch : function() {
      
        var itemTpl = new Ext.XTemplate([
               '<table>',
                 '<tr><th>Date</th><th>Bill Number</th><th>Amount</th><th></th></tr>',
                '<tpl for=".">',
                 '<tr>',
                  '<td class="date">{invoiceDate}</td>',
                  '<td>{billNumber}</td>',
                  '<td>£{invoiceAmount}</td>',
                 '</tr>',
                '</tpl>',
               '</table>',
              ]);
      
        var makeJSONPRequest = function() {
         panel.update('');
         panel.setLoading(true, true);
      
         Ext.util.JSONP.request({
          url: 'http://localhost:9998/myresource/invoicejsonp/1234',
          callbackKey: 'callback',
          callback: onCallback 
         });
        };
      
        var onCallback = function(result) {
         var data = result.invoice;
         if (data) {
          panel.update(itemTpl.applyTemplate(data));   
          panel.scroller.scrollTo({x: 0, y: 0});                     
         } else {
          alert('There was an error during retrieving data.');
         }
         panel.setLoading(false);
        };
      
        panel = new Ext.Panel({
         fullscreen : true,
         scroll: 'vertical',
         cls: 'card',
         dockedItems: [
          {
           dock : 'top',
           xtype: 'toolbar',
           items: [
            {
             text: 'Load invoices',
             handler: makeJSONPRequest 
            }
           ]
          }
         ]
        });
       }
      });
      
      </script>
      
      </head>
      <body>
      </body>
      </html>
      

      Some comment about this application - in makeJSONPRequest method we are making request to the web service. When browser will receive a response, onCallback method will be invoked. itemTpl defines how invoices will be displayed. You need to download sencha-touch.js and sencha-touch-debug.css files and place them in proper directories.

      Save your html file somewhere on your disk and open this page with Chrome web browser.
      It must be Chrome - only this browser is capable of displaing Sencha Touch application properly (and mobile phones and tablets of course).



      Click on Load invoices button.



      VoilĂ ! Our REST service was invoked, and invoices are being displayed properly. If something went wrong, make sure that web service is running.
      If your page is not as pretty as mine, you can add the following style in the header

      <style type="text/css">
       table {
        border-collapse: collapse;
        font-family: Arial;
       }
       td, th {
        color: #666;
        padding: 5px;
       }
       th {
        color: black;
        font-weight: bold;
       }
      </style>


      Summary

      In this article you have learnt how to create Jersey RESTful service which will return JSONP response body. You were also given an example of Sencha Touch application, which consumes that service. If you are interested in Sencha Touch, which is great mobile framework, visit project page.

      Thursday 10 February 2011

      How to use Dozer for automatic Java Bean mapping - quickstart with Maven & Eclipse

      Introduction

      This step-to-step article describes how to create simple Dozer-enabled application. Dozer is very useful Java Bean to Java Bean mapper, which automatiacally (and recursively) copies fields' values from one object to another. For example, you can use it to automatiacally copy data from Entity object to Dto object. 

      Prerequisites
      • JDK 6, 
      • Eclipse IDE with m2eclipse plugin, 
      • Maven 2 (standalone or bundled with Eclipse Helios).
        Table of contents
        1. Create Eclipse project.
        2. How to use default Dozer mapping.
        3. How to configure Dozer mapping.
        4. Summary

          Create Eclipse project

          Start your Eclipse IDE and create a new project. Click File > New > Project...
          Select Maven Project and click Next.


          Select Create a simple project (skip archetype selection) checkbox, and click Next again.


          Fill out all Artifact fields (Group Id, Artifact Id, Version, Name) and click Next.


          On the next form, you need to add two dependencies to the project. First one will be Dozer library. Click Add button, and search for net.sf.dozer dependency. If found, select it on the list and click OK button.


          You will also need JUnit 4 and slf4j-api library. Click Add button again, search for JUnit, select it on the list and add to the project by clicking OK button. Search also for slf4j-api library and add it to the project. When you are done, click Finish.



          How to use default Dozer mapping

          Ok, we have the project, so now we try to use Dozer. What we want to do is to copy fields' values from one object to another. What is great - Dozer requires no configuration if these fields have the same names. Only constraint you should have in mind is that Dozer expects JavaBean class with setters, getters and public no-arg constructor. Let's see how it works!

          Select src/main/java directory and click New Java class button.


          Create App class. In this class we will use dozer for rewriting objects' fields. Fill out Package and Name fields, and click Finish button.


          Leave App class empty for now, and in the same pacakage create another class - SimilarObject1. Add two String fields to this class - firstName and lastName. To generate setters, getters and constructors, click somewhere in the SimilarObject1 editor, press Alt+Shift+S, choose Generate Constructors from Superclass and click OK.


          Press Alt+Shift+S again and choose Generate Constructor using Fiels. Select both fields and click OK.


          Press Alt+Shift+S for the last time and choose Generate Getters and Setters. Click Select All button and click OK.


          SimilarObject1 class should now look like this:
          package pl.bzawadka.poc.dozer;
          
          public class SimilarObject1 {
              private String firstName;
              private String lastName;
          
              public SimilarObject1() {
                  super();
              }
          
              public SimilarObject1(String firstName, String lastName) {
                  super();
                  this.firstName = firstName;
                  this.lastName = lastName;
              }
          
              public String getFirstName() {
                  return firstName;
              }
          
              public void setFirstName(String firstName) {
                  this.firstName = firstName;
              }
          
              public String getLastName() {
                  return lastName;
              }
          
              public void setLastName(String lastName) {
                  this.lastName = lastName;
              }
          }
          

          In the same package create second class. This class will contain the same fields as first one. 
          SimilarObject2 class should look like this:
          package pl.bzawadka.poc.dozer;
          
          public class SimilarObject2 {
              private String firstName;
              private String lastName;
          
              public SimilarObject2() {
                  super();
              }
          
              public SimilarObject2(String firstName, String lastName) {
                  super();
                  this.firstName = firstName;
                  this.lastName = lastName;
              }
          
              public String getFirstName() {
                  return firstName;
              }
          
              public void setFirstName(String firstName) {
                  this.firstName = firstName;
              }
          
              public String getLastName() {
                  return lastName;
              }
          
              public void setLastName(String lastName) {
                  this.lastName = lastName;
              }
          }
          

          Now it is high time to update App class. To use Dozer, you have to instantiate it's DozerBeanMapper class and invoke map method. And that is all you have to do! Fields in the destination object will be set with values from the source object.
          App class should look like this:

          package pl.bzawadka.poc.dozer;
          
          import org.dozer.DozerBeanMapper;
          import org.dozer.Mapper;
          
          /**
           * Dozer proof of concept
           * 
           */
          public class App {
          
              public static void rewriteSimilar(SimilarObject1 source, SimilarObject2 destination) {
                  Mapper mapper = new DozerBeanMapper();
                  mapper.map(source, destination);
              }
          
          }
          

          Now we will write a test to check whether rewriteSimilar method works. Create AppTest class in src/test/java directory.
          AppTest class should look like this:

          package pl.bzawadka.poc.dozer;
          
          import static org.junit.Assert.assertEquals;
          
          import org.junit.Test;
          
          /**
           * Unit test for simple App.
           */
          public class AppTest {
          
              @Test
              public void testRewriteSimilar() {
                  SimilarObject1 obj1 = new SimilarObject1("dafi", "duck");
                  SimilarObject2 obj2 = new SimilarObject2();
          
                  App.rewriteSimilar(obj1, obj2);
          
                  assertEquals(obj1.getFirstName(), obj2.getFirstName());
                  assertEquals(obj1.getLastName(), obj2.getLastName());
              }
          
          }
          
          Let's test our rewriteSimilar method. Click Run Configurations button...


          ... and create new Maven Build configuration. Double click Maven Build option. Fill out Name and choose our project by clicking Browse Workspace... button. Type clean test in Goals field. Click Apply and Run.


          Check Console output - BUILD SUCCESS means, that Dozer automatically filled out our destination object fields. It works!



          How to configure Dozer mapping

          Dozer requires no configuration if objects' fields have the same names. If fields have different names, you need to create xml configuration file.

          Let's create a new class, with slightly different fields (name instead of firstName and latestName instead of lastName).
           
          DifferentObject class should look like this:

          package pl.bzawadka.poc.dozer;
          
          public class DifferentObject {
              private String name;
              private String lastestName;
          
              public DifferentObject() {
              }
          
              public DifferentObject(String name, String lastestName) {
                  super();
                  this.name = name;
                  this.lastestName = lastestName;
              }
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getLastestName() {
                  return lastestName;
              }
          
              public void setLastestName(String lastestName) {
                  this.lastestName = lastestName;
              }
          }
          

          To create configuration file, right-click on the src/main/resources directory and select New > File.


          Type dozer-mapping.xml in File name field.


          Edit this file. <class-a> and <class-b> elements define which classes will be mapped. For each mapped class field, <field> element must exists. In our case, first <field> element defines that SimilarObject1.firstName will be mapped into DifferentObject.lastName.
          dozer-mapping.xml  class should look like this:
          <?xml version="1.0" encoding="UTF-8"?>
          <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
          
              <configuration>
                  <stop-on-errors>true</stop-on-errors>
              </configuration>
          
              <mapping>
                  <class-a>pl.bzawadka.poc.dozer.SimilarObject1</class-a>
                  <class-b>pl.bzawadka.poc.dozer.DifferentObject</class-b>
                  <field>
                      <a>firstName</a>
                      <b>name</b>
                  </field>
                  <field>
                      <a>lastName</a>
                      <b>lastestName</b>
                  </field>
              </mapping>
          
          </mappings>
          

          Let's add a new method do App class. This time DozerBeanMapper constructor will take List of configuration files as parameter. You will also need two new imports (java.util.ArrayList, java.util.List).

              public static void rewriteDifferent(SimilarObject1 source, DifferentObject destination) {
                  List<String> mappingFiles = new ArrayList<String>();
                  mappingFiles.add("dozer-mapping.xml");
                  Mapper mapper = new DozerBeanMapper(mappingFiles);
                  mapper.map(source, destination);
              }
          

          Add the following test to AppTest class:
              @Test
              public void testRewriteDifferent() {
                  SimilarObject1 obj1 = new SimilarObject1("dafi", "duck");
                  DifferentObject obj3 = new DifferentObject();
          
                  App.rewriteDifferent(obj1, obj3);
          
                  assertEquals(obj1.getFirstName(), obj3.getName());
                  assertEquals(obj1.getLastName(), obj3.getLastestName());
              }
          

          Run the build (Alt+Shift+X and press M). The result should be like the following:


          Dozer worked again!


          Summary

          In this article you have learnt how to use Dozer library for automatic Java Bean mapping. By default, Dozer requires no configuration. If you want to map objects' fields with different names, xml configuration file is required. For more information, visit project page.