Posting JSON to Spring MVC Controller

Spring MVC can be setup to automatically bind incoming JSON string into a Java object. Firstly, ensure you have jackson-mapper-asl included on the classpath:

<dependency>
  <groupId>org.codehaus.jackson</groupId>
  <artifactId>jackson-mapper-asl</artifactId>
  <version>1.9.13</version>
</dependency>

Assuming the JSON string we want to bind represent a person object like this:

{
  name: "Gerry",
  age: 20,
  city: "Sydney"
}

Which will be bound into following Java class:

public class Person {
  private String name;
  private int age;
  private String city;
  // getters & setters ...
}

Declare the Spring MVC controller handler method like below. The handler method is mapped into path “addPerson” with method POST.

@RequestMapping(value = "/addPerson", method = RequestMethod.POST, headers = {"Content-type=application/json"})
public String addPerson(@RequestBody Person person) {
  logger.debug(person.toString());
  return "person";
}

Below is an example jQuery based javascript handler that posts into the above Spring MVC handler.

$.ajax({
  type: "POST",
  url: "addPerson",
  data: JSON.stringify({ name: "Gerry", age: 20, city: "Sydney" }),
  contentType: 'application/json',
  success: function(html) {
    alert(html);
  }
});
Advertisements

Spring MVC Executor Service Anomaly Due to Holding HttpServletRequest for too Long

Encountered a strange problem with Spring MVC running on Tomcat 7 today. I had a ThreadPoolTaskExecutor with 1 max thread capacity on my application which wasn’t working as it supposed to. My Runnable task look something like this:

public class LongRunningTask implements Runnable {

  private HttpServletRequest request;
  
  public LongRunningTask(HttpServletRequest request) {
    this.request = request;
  }
  
  @Override
  public void run() {
    // do something ..
  }

}

Notice I originally added a reference to HttpServletRequest with the intention of obtaining the remote host and address of the client. My controller class look something like this:

@Controller
public class HomeController {

  @Autowired private ThreadPoolTaskExecutor taskExecutor;

  @RequestMapping(...)
  public String schedule(HttpServletRequest req, ...) {
    taskExecutor.submit(new LongRunningTask(req));
  }
}

With the hope that user’s get their response immediately while the actual work is still queued on the background.

Turns out this caused all sorts of strange behavior. Sometime the task will run, most of the time it will just sit in the queue forever / won’t even queue at all.

After further research and trial and error, I figured out this was because my runnable is holding a reference to HttpServletRequest. When I refactored the code the task executor work as per normal again.

I’ve came into a conclusion that holding to a HttpServletRequest object for longer than necessary is not a good practice.

Using Spring Data MongoDB

Spring Data MongoDB provides a great third party support based on standard MongoDB Java Driver.

Dependencies

Following dependencies are required. Check for latest version via Nexus Central Repository:

  1. spring-data-mongodb
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-mongodb</artifactId>
      <version>1.2.1.RELEASE</version>
    </dependency>
    
  2. mongo-java-driver
    <dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongo-java-driver</artifactId>
      <version>2.11.1</version>
    </dependency>
    

Setup Mongo Connection, Template and Repository Scanning

This is similar idea with setting up db datasource. In this example the mongo database server is located at localhost:27017 (default). The MongoDB database name used is enrollment. The <mongo:repositories ...> tag specifies the base package to scan for repository classes

<?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:mongo="http://www.springframework.org/schema/data/mongo"
  xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.2.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <mongo:mongo host="localhost" port="27017" />

  <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongo" />
    <constructor-arg value="enrollment" />
  </bean>
  
  <mongo:repositories base-package="com.gerrydevstory.enrollment"/>
</beans>

Domain / Entity Class

Example on this post will be based on a simple Student entity class with only id and name field:

import org.springframework.data.annotation.Id;

public class Student {
  @Id private String id;
  private String name;
  // getters & setters..
}

Without explicit configuration this entity class will be mapped into MongoDB collection name student. To override this default behavior use @Document(collection = "...") annotation.

Repository Class

Simply add an interface extending Spring Data Repository interface. Below sample uses PagingAndSortingRepository, which extends CrudRepository which provides most basic operation. The type parameter specifies this repository operates over Student entity, with the ID type being String. Spring Data will automatically generate an implementation of this interface.

public interface StudentRepository extends PagingAndSortingRepository<Student, String> {

}

This repository can now be injected into controllers:

@Controller
@RequestMapping("/student")
public class StudentController {

  @Autowired private StudentRepository studentRepository;

  @RequestMapping(method = GET)
  public String get(Model model) {
    Iterable<Student> students = studentRepository.findAll();
    return "student";
  }

  @RequestMapping(value = "/new", method = POST)
  public String addNew(@ModelAttribute("student") Student student) {
    studentRepository.save(student);
  }

  ...
}

Read More

Learn more about Spring Data and MongoDB:

Cross Site Request Forgery (CSRF) Protection in Spring 3.1

Eyal Lupu has written an excellent article in his blog about mitigating Cross Site Request Forgery (CSRF) attack.

CSRF allows an attacker to create a fake form / link posting to a secured website. It exploits the fact you might have an active session from a secured website. For example, an attacker can create a fake form / link with all the data required to transfer money to his / her account without you realizing it.

This CSRF prevention techniques involes two components:

  1. Rendering a hidden form field with randomly generated token stored in session
  2. Ensuring the next post request came with matching token

The sample source code of this solution can be obtained from:

git clone https://github.com/eyal-lupu/eyallupu-blog.git

Session Scoped Beans in Spring

If your Spring application context is associated with a Java EE container (eg: created via DispatcherServlet), you can set your bean in a session scope. This means every user starting a new http session will obtain a different copy of your bean.

Let’s see this in action. Below I have a ShoppingCart bean

public class ShoppingCart implements Serializable {
  private int userId;
  private List<Product> products;
  // getters & setters ...
}

Configure this to be a session scoped bean in spring xml configuration file:

<bean class="com.gerrydevstory.ShoppingCart" scope="session">
  <aop:scoped-proxy/>
</bean>

The <aop:scoped-proxy/> tag will cause Spring to create a proxy class over the ShoppingCart bean. This is critical because we want to inject our ShoppingCart to a singleton class (eg: Service / Controller classes) yet each user’s http session should get its own copy of the data.

In order for proxying to take effect you also need to include cglib library into your classpath.

I can now inject the ShoppingCart into HomeController:

@Controller
@RequestMapping("/home")
public class HomeController {

  @Autowired private ShoppingCart shoppingCart;

  ...
}

One way to think about this is the proxy is actually a singleton mirror image of the ShoppingCart class, except each user coming from different HttpSession will see different data when they invoke the public methods. For each new HttpSession, on the first time user invokes one of the proxied method a new actual ShoppingCart bean instance is created behind the screen.

Entity Relationship On Hibernate JPA

This article is tested against Java EE 6, Hibernate 4.2.2.

One To Many Unidirectional Relationship

Unidirectional here means you can only obtain related entities from one side. For example supposed we have one to many Customer --> Account relationship, here’s what Customer entity look like

@Entity
public class Customer {

  @Id
  @GeneratedValue
  private long id;

  private String name;

  @OneToMany
  @JoinColumn(name = "customer_id")
  private Set<Account> accounts;

  // getters & setters..
}

Instead of Set, you can use List, however if you have more than one relationship in your entity class, you will get MultipleBagFetchException.

And This is what Account looks like. Notice there’s no reference to Customer object from Account.

@Entity
public class Account {

  @Id
  @GeneratedValue
  private long id;
  
  private double balance;

  // Getters & Setters ..
}

One To Many Bidirectional Relationship

Similar to unidirectional except you can obtain relation from both direction. This is what Customer and Account look like:

@Entity
public class Customer {

  @Id
  @GeneratedValue
  private long id;

  private String name;

  @OneToMany(mappedBy = "customer")
  private Set<Account> accounts;

  // getters & setters..
}

The “customer” on @OneToMany(mappedBy = "customer") refers to customer java property on Account entity.

@Entity
public class Account {

  @Id
  @GeneratedValue
  private long id;
  
  private double balance;

  @ManyToOne
  @JoinColumn(name = "customer_id")
  private Customer customer;

  // Getters & Setters ..
}

The @JoinColumn(name = "customer_id") annotation sets the database foreign key column name to be “customer_id”.

Lazy / Eager Loading

Lazy / Eager refers to when does entity relationship get populated. Eager means it will get populated as soon as the entity is obtained from database, where in Lazy it’s only populated when you request the relationship for the first time.

The default value for @OneToMany is LAZY, but for @ManyToOne it’s EAGER. It’s a good practice to explicitly configure it so your code is easier to understand

@Entity
public class Customer {
  ...
  @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY)
  private Set<Account> accounts;
  ...
}
@Entity
public class Account {
  ...
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "customer_id")
  private Customer customer;
  ...
}

LazyInitializationException: could not initialize proxy – no Session

Almost every Hibernate/JPA noobie struggle with this exception when they started learning (including myself). This is basically saying you’re tring to access unfetched data after transaction has been closed.

If you use Spring declarative transaction management, transaction start and finish mark are declared by simply annotating DAO method with @Transactional. Let’s see a common failure where LazyInitializationException can happen.

Here’s your CustomerDAO class:

@Repository
public class CustomerDAO {
  
  @PersistenceContext private EntityManager em;

  @Transactional
  public List<Customer> getAllCustomers() {
    List<Customer> customers = em.createQuery("select c from Customer", 
      Customer.class).getResultList();
    return customers;
  }

Then on your controller you populate your Model object with list of Customers, and on your view your JSP tried to access Accounts associated with each customer:

<h1>Customer Info</h1>
Id: ${customer.id}
Name: ${customer.name}
Accounts: <ul>
  <c:forEach var="acc" items="${customer.accounts}">
    <li>Acc Id: ${acc.id}, Balance: ${acc.balance}</li>
  </c:forEach>
</ul>

Since the transaction is already closed when CustomerDAO.getAllCustomers() method returns, this will throw LazyInitializationException.

My preferred strategy to overcome this problem is to prefetch the related entities on the DAO, so all the information we need is available on view level in detached state. Other strategy being opening a transaction / session while view is being generated (see: OpenSessionInViewFilter). To achieve this, change the getAllCustomers() DAO method to use JPQL left join fetch syntax like this:

@Repository
public class CustomerDAO {
  ...
  @Transactional
  public List<Customer> getAllCustomers() {
    List<Customer> customers = em.createQuery(
      "select distinct c from Customer " +
      "left join fetch c.accounts", 
      Customer.class).getResultList();
    return customers;
  }
  ...
}

Now you can iterate and access all related accounts entities without exceptions.

Unit Testing Spring Bean Service With Mockito

The main idea of unit testing is quick compile-time checking that your code (somewhat) fulfills the business requirement.

A good unit testing practice is to not depend on any external system / dependencies. One way to substitute this external dependency is by using mocking tehcniques. Here I’ll go through unit testing a Spring bean service using Mockito.

Assuming you have a BankingService class that comes with a method to transfer money from one account to another. The method finds the Account object by its id using AccountsDAO repository class:

@Service
public class BankingService {

  @Autowired private AccountsDAO accountsDAO;
  
  public void transfer(long fromAccountId, long toAccountId, double amount) throws Exception {
    Account fromAccount = accountsDAO.findById(fromAccountId);
    Account toAccount = accountsDAO.findById(toAccountId);
    
    fromAccount.setBalance(fromAccount.getBalance() - amount);
    toAccount.setBalance(toAccount.getBalance() + amount);
  }
}

AccountsDAO obtain the information from a persistent data store (most likely database), hence it is an external dependency. Here’s how to unit test this class:

  1. Ensure junit, spring-test and mockito dependencies are on the classpath
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>3.2.3.RELEASE</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>1.9.5</version>
      <scope>test</scope>
    </dependency>
    
  2. Setup BankingServiceTest.xml spring beans configuration file specific for our unit test. Note in here we created a mock AccountsDAO using Mockito. The order of mock creation here is important, if you place it at the bottom you will get autowiring error. I think this is because Spring couldn’t pre-determine the resulting type of the Mock object (it only looks as if it’s a org.mockito.Mockito bean type).
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="com.gerrydevstory.mycoolbank.AccountsDAO"/>
      </bean>
    
      <bean class="com.gerrydevstory.mycoolbank.BankingService"/>
    
    </beans>
    
  3. Setup the unit test class. Notice the BankingService to test and the mock AccountsDAO are autowired into the unit test class
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("/BankingServiceTest.xml")
    public class BankingServiceTest {
    
      @Autowired private BankingService bankingService;
      @Autowired private AccountsDAO mockAccountsDAO;
      
      @Test
      public void testTransfer() throws Exception {
        // Setup 2 accounts
        Account acc1 = new Account();
        acc1.setBalance(800.00);
        Account acc2 = new Account();
        acc2.setBalance(200.00);
        
        // Tell mock DAO to return above accounts when 1011 or 2041 is queried respectively
        when(mockAccountsDAO.findById(1011)).thenReturn(acc1);
        when(mockAccountsDAO.findById(2041)).thenReturn(acc2);
        
        // Invoke the method to test
        bankingService.transfer(1011, 2041, 500.00);
        
        // Verify the money has been transferred
        assertEquals(300.00, acc1.getBalance(), 0.001);
        assertEquals(700.00, acc2.getBalance(), 0.001);
      }
    }
    
  4. The when(..).thenReturn(..) syntax is where the magic happen. It will cause the mock object to return the Account we setup (as opposed of calling SQL to fetch it from database).

There are heaps more magic stuff you can do with Mockito. Checkout their site.

Source Code

Source code of this demo can be downloaded via git:

git clone https://gerrytan@bitbucket.org/gerrytan/mycoolbank.git