spring3

Ext JS 4: A File Browser with Spring 3 Server-side

I recently needed to create a file browser to access log files for my application. I don’t have access to the machines where the log files reside, so by creating a file browsing application I could ensure access controls and still get to the logs. From within my file browser I can open the log file in another browser tab/window or download the file. This was also my first time working with trees…

Here is what it looks like:
FileBrowser
(more…)

Spring 3 @Autowired Unit Tests with Mockito

I’ve been wanting to enhance the unit tests I have in my application for awhile. I’m using Spring 3 testing facilities, but most of my tests are “integration” tests. I finally carved out a bit of time to enable better unit tests in my application. This is an example of a unit test of a simple service class using Spring 3 annotations. I am using Mockito to mock the dependencies.

First my service class. Like I said, simple. Just two methods and straightforward logic.

package my.app.service;

import java.util.List;

import my.app.dao.SupervisorDAO;
import my.app.model.Supervisor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SupervisorService {

	@Autowired private SupervisorDAO supervisorDao;

	@Transactional(readOnly=true)
	public List getSupervisors() {
		return supervisorDao.getSupervisors();
	}

	/**
	 * Determine if the supervisor is responsible for any users for the
	 * specified department
	 * @param dbId The dbId of the supervisor
	 * @param department The department to look for
	 * @return true if there are users assigned to the superivsor for the department
	 */
	public boolean isSupervisorResponsibleForUser(int dbId, String department) {
		if (dbId == 0) {
			throw new IllegalArgumentException("A dbId is required");
		}
		if (department == null) {
			throw new IllegalArgumentException("department is required");
		}
		boolean hasUsers = false;
		int numAssignedUsers = supervisorDao.getUserCountForSupervisor(dbId, department);
		if (numAssignedUsers > 0) {
			hasUsers = true;
		}
		return hasUsers;
	}
}

The unit test. I need to mock the dao object to create a repeatable unit test of the service class. Here’s the code:

package my.app.service;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import my.app.dao.SupervisorDAO;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class SupervisorServiceUnitTest {

	@Mock private SupervisorDAO mockSupervisorDao;
	@InjectMocks private SupervisorService supervisorService;

	@Before
	public void init() {
		when(mockSupervisorDao.getUserCountForSupervisor(1, "Department1"))
			.thenReturn(2);
		when(mockSupervisorDao.getUserCountForSupervisor(1, "Department2"))
			.thenReturn(0);
	}

	@Test
	public void testIsSupervisorResponsibleForUserTrue() {
		boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department1");
		assertTrue(isSupervisor);
	}

	@Test
	public void testIsSupervisorResponsibleForUserFalse() {
		boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department2");
		assertFalse(isSupervisor);
	}

	@Test(expected=IllegalArgumentException.class)
	public void testIsSupervisorResponsibleRequiredDbId() {
		supervisorService.isSupervisorResponsibleForUser(0, "Department3");
	}

	@Test(expected=IllegalArgumentException.class)
	public void testIsSupervisorResponsibleRequiredDivision() {
		supervisorService.isSupervisorResponsibleForUser(1, null);
	}
}

The key things that I learned along the way:

  • Use @RunWith(MockitoJUnitRunner.class) to run this test
  • Use the @Mock annotation for the classes that need to be mocked within the class you are testing. Use the @InjectMocks annotation on the class you are testing. The @Mock classes are injected into the @InjectMocks class. I guess this should have been obvious, but it wasn’t to me.

It’s a simple class and a simple unit test, but it’s a start. It gets me over the hump of having the correct jars and knowing how to get a test up and running. I am new to the behavior driven style of Mockito, but this works well for me in this unit test. I think it is clean and easy to read.

Some links that were helpful to me (disclaimer, some of these are for older versions of Mockito)

Version Info:

  • Spring 3.0.5
  • Mockito 1.9.0

Spring 3 One Approach to Exception Handling for MVC when using JSON

Whenever an exception (such as a binding exception) came up in my Spring 3 MVC app, Spring would return and HTML page with the stack trace. I don’t want this. Besides not exposing the stack trace, I need well formatted JSON in my response, not an HTML page. I haven’t quite got a grip on exception handling in Spring. I’ve read a ton of entries in stack overflow and I get that @Exception works per controller, but for this case, I wanted to handle the exceptions that occur before you even get to the controller. I finally found one model that is working for me. There are probably other ways to do this and I hope to discover and understand them at some point, but this was actually fairly simple.

Thanks to Google App Engine + JAVA + Spring + REST + Mapping Exceptions to Errors for JSON for providing me with a solution. The entry at Wet Feet is very well written. I’m just copying my version here.

1. Create your own class that implements the HandlerExceptionResolver. I used my own view, but the Wet Feet blog entry uses MappingJacksonJsonView. The WebUtil call in the code is my own code to build the JSON.

package com.ahlearns.mystuff;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

public class JsonExceptionResolver implements HandlerExceptionResolver {
	
	protected final Logger log = LogManager.getLogger(getClass());
	
	@Override
	public ModelAndView resolveException(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex) {
		log.error("Error occurred for handler [" + handler + "]", ex);
		ModelAndView mav = new ModelAndView();
        	mav.setViewName("error");
        	mav.addObject("jsonMsg", WebUtil.getJsonSuccessMsg(false, "An unexpected error occurred."));
        	return mav;
	}
}

2. Add the following bean definition to your spring config. Spring will detect it and route exceptions to the resolver.

<bean id="exceptionResolver" class="com.ahlearns.mystuff.JsonExceptionResolver" />

Adding an Interceptor to Spring 3 Controller

Very simple case, I want to log some information for requests made into a specific controller.

I created an interceptor class like this

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class MyInterceptor extends HandlerInterceptorAdapter {

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		//my code here
		return super.preHandle(request, response, handler);
	}
}

And then I configured it in my Spring config file

	<!-- Configures Handler Interceptors -->	
	<mvc:interceptors>
		<!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
		<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
		<mvc:interceptor>
			<mvc:mapping path="/*" />
			<bean class="xxx.xxx.MyInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>

This caught all the entry points into my application which was what I needed.

Spring 3 MVC @RequestBody Deserialization of custom List objects

A few things to make sure Spring and Jackson can correctly deserialize a list of custom objects:

  1. Besides having annotations turned on, you must use @RequestBody in the controller method to indicate you are reading the JSON in the POST request
  2. Make sure your AJAX request has a content-type of “application/json”.  Using Ext JS 4, this is done by sending jsonData instead of params in the Ext.Ajax.request.
  3. Jackson needs the property type to know how deserialize, but Spring doesn’t pass that along in the message converters and might not ever do that,  so you need a wrapper class
  4. If Jackson cannot deserialize your class, then Spring’s MappingJacksonHttpMessageConverter.canRead<?> fails and you get the HttpMediaTypeNotSupportedException (even if the request header has content-type of application/json).  In my case, this was two setters for one property.

I had a few of these things mixed together, so it was a little tricky to unwind, but here’s some code that will deserialize a list of “Users”.  So, that JSON looks something like (w/o the proper quotes):

[{userId: 1, name: John}, {userId: 2, name: Sally}]


// The wrapper class, so that type info (of User) is passed thru the message converters to Jackson
public class Users extends ArrayList<User> {
	private static final long serialVersionUID = 1L;

	public Users() { super(); }
}

// Example method from the controller:
	@RequestMapping(value="/status", method = RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> status(@RequestBody Users users) {
		// handle the request here
	}

Helpful links:

Using Application Properties with Spring 3

I’m new to Spring and it can be a lot to take in. I was confused by properties and Spring. Not Spring configuration properties, but properties that are used in the application. I just wanted global access to my application properties. I might run into issues further down, like if I want to dynamically update properties, but so far, this is what I have.

1. In my app-config.xml Spring config file:

    
    <bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" value="classpath:application.properties" />
    </bean>

2. In the components that I wanted to use properties (some are annotated with @Service and others with @Component) I used the @Value notation. In addition, there were a few where I wanted to set a default in case the property was missing. In this situation the property is really there just in case something needs to be changed w/o redeploying.

@Component
public class RestClient {
	@Value("#{appProperties['property.webservice.rest.timeout.seconds']}")
	private Integer timeout = 360;
	
	@Value("#{appProperties['property.webservice.rest.filecontenttype']}")
	private String fileContentType = HTTP.DEFAULT_CONTENT_TYPE;

	public void doSomething() {
		//...
	}
}

The above worked to read in the property and the assignment was used if the property is missing.

Ext JS – Serialize Date using Jackson and Spring 3

From bottom to top:

  1. In the database (MS SQLServer): column is a datetime (aka, a timestamp)
  2. In domain object, need the @Temporal(TemporalType.TIMESTAMP) annotation (using Hibernate 3x). Note, I also added @JsonProperty for Jackson b/c I wanted a shorter name in the JSON.
    	@Temporal(TemporalType.TIMESTAMP)
    	@Column(name="REGISTRATION_DATE")
    	private Date registrationDate;
    	@JsonProperty("regDate")
    	public Date getRegistrationDate() { return registrationDate; }
    	public void setRegistrationDate(Date registrationDate) { this.registrationDate = registrationDate; }
    
  3. Configured Jackson object mapper to use ISO-8601 format
    objectMapper.configure(SerializationConfig.WRITE_DATES_AS_TIMESTAMPS, false);
    
  4. Define field in Ext JS 4 model as a Date type, using the ‘c’ date format.
    Ext.define('User', {
    	extend: 'Ext.data.Model',
    	fields: [
    		{name: 'regDate', type: 'date', dateFormat: 'c'}
    	]
    });
    
  5. Show the date in a user friendly format in the grid. Ext JS 4, column config:
    {text: 'Registration Date', dataIndex: 'regDate', sortable: true, xtype: 'datecolumn', format:'m-d-Y'}
    

Helpful Links

The Journey for Handling Hibernate Lazy Loading using Spring 3 MVC Annotations and Jackson for JSON

I’m not even sure where to start with this one. Let’s see…

The Setup

Here’s the big picture.  A new project, new everything, lots of annotations… And I should add, I’m new to Hibernate and Spring…

  • Ext JS 4
  • Spring 3.0.4
  • Hibernate 3.6.2
  • Jackson 1.7.6

In my db, I have a User table.  Each user may have a Supervisor, which is just a user_id.  The User entity ends up looking like this:

@JsonAutoDetect
@Entity
@Table(name="PR_USER")
public class User {

	@Id
	@Column(name="USER_ID")
	private int userId;
	public int getUserId() { return userId; }
	public void setUserId(int userId) { this.userId = userId; }

	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="SUPERVISOR_ID")
	private User supervisor;
	public User getSupervisor() { return supervisor; }
	public void setSupervisor(User supervisor) { this.supervisor= supervisor; }
}

Helpful link: How to create relationship to the same entity with JPA (Hibernate)?

Issue 1 – Eagerly Load One Supervisor

Once I got it straight how to create the relationship to the same entity, everything was working well except for one thing… I only needed to eagerly load the user’s supervisor. But I didn’t need the supervisor’s supervisor and their supervisor and so on. After a lot of searching around (and I seem to have lost the link that helped me finally understand, but it might have just been the Hibernate documentation), I determined that in order to only load one “level” of supervisor I needed the “fetch=FetchType.LAZY” property on the @ManyToOne annotation for the supervisor column. Then my query needed to be built with HQL (previously I was using Criterias) so that I could specify to fetch the one supervisor eagerly. The HQL ended up looking something like this:

from User as user
left outer join fetch user.supervisor as supervisor
where user.fname like

I have a few different user queries, by first name, last name, supervisor, etc.

Great! It worked! Now my supervisor chain doesn’t go on and on. Now on to the next issue.

Issue 2 – Jackson mapping of Lazy Loaded objects

All ready to test and then bam! This error from the Jackson mapper:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[46]->....User_$$_javassist_2["handler"])
    at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:268)
    at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:146)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:118)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:236)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:189)
    at org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:111)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:296)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:224)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:925)
    at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)

So, it turns out that Jackson does not know what to do with a Hibernate Lazy Loaded object. A lot of research and these helpful links led me to the following conclusion:

  1. There is a new, very new, completed untested Jackson-hibernate module out there to handle lazy loading, named jackson-module-hibernate.  https://github.com/FasterXML/jackson-module-hibernate.
  2. The example setup in jackson-module-hibernate has a configuration for AnnotationMethodHandlerAdapter.  Close reading of the comments in the “Serializing Hibernate entities into JSON using Jackson framwork” extremely helpful blog entry, says the AnnotationMethodHandlerAdpater configs are for REST only.  Currently, my setup is to use @ResponseBody to write the JSON the response, which uses AnnotationMethodHandlerAdapter.  So, it seems there are now two options.
    • No longer use @ResponseBody and instead create a “jsonView” and return that as the ModelAndView, as suggested in the comments of the post.
    • Make AnnotationMethodHandlerAdapter work.  This lead me to the incredibly helpful post: http://scottfrederick.blogspot.com/2011/03/customizing-spring-3-mvcannotation.html.  Which clearly explains the problem with AnnotationMethodHandlerAdapter and mvc annotations and a workaround for it, unless you can hang around for Spring 3.1.

I should also mention that I had to make changes to jackson-module-hibernate.  The key piece of code was commented out and the parameters were wrong.  So, after changing


public class HibernateSerializers implements Serializers
{
    ....
   public JsonSerializer<?> findSerializer(
        SerializationConfig config, JavaType type,
        BeanDescription beanDesc, BeanProperty beanProperty )
   {
       ....
       if (HibernateProxy.class.isAssignableFrom(raw)) {
        //  return new HibernateProxySerializer(type, config);
        //  return new PersistentCollectionSerializer(type, isEnabled(Feature.FORCE_LAZY_LOADING));
       }
      ....
   }
}

to

public class HibernateSerializers implements Serializers
{
    ....
    public JsonSerializer<?> findSerializer(
         SerializationConfig config, JavaType type,
         BeanDescription beanDesc, BeanProperty beanProperty )
    {
        ....
        if (HibernateProxy.class.isAssignableFrom(raw)) {
            return new HibernateProxySerializer( isEnabled(Feature.FORCE_LAZY_LOADING));
         // return new PersistentCollectionSerializer(type, isEnabled(Feature.FORCE_LAZY_LOADING));
        }
        ....
     }
}

With the above change to jackson-module-hibernate and also implementing Scott Frederick’s AnnotationMethodHandlerAdapterConfigurer, amazingly, it worked.  Hibernate only loaded the supervisor one level deep and Jackson handled the lazy loaded object and mapped the JSON as I expected and Ext JS showed the user data in my grid.

It was a journey…