Spring’s RestTemplate, Jackson’s JSON deserializing and inner classes

In trying to use Spring 3’s RestTemplate that every article about says is braindead easy, I hit upon a limitation that’s taken me a few hours to iron out.

JSON I am trying to consume:

{"results":[{"id":"1","details":{"title":"First Instructions","alternateTitle":"","location":"3","beginDate":"2002-12-03 15:04:00","endDate":"2003-02-27 03:00:00","frequency":"0","teacher":"1","program":"1","description":"","fees":"","status":"0"}}]}

Hastily written service method:

public CourseResult getCourseResult(Integer id) {
	String uriTemplate = apiUrl + "?id={id}";
	RestTemplate template = new RestTemplate();
	
	List> messageConverters = template.getMessageConverters();
	List> converters = new ArrayList>(messageConverters);
		
	MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
	converters.add(jsonConverter);	
	template.setMessageConverters(converters);
	    
	TclApiResponse response = template.getForObject(uriTemplate, TclApiResponse.class, String.valueOf(id));
	return response.getCourseResults()[0];
}

Domain Object:

public class TclApiResponse {
	
	private CourseResult[] courseResults;

	public CourseResult[] getCourseResults() {
		// TODO Auto-generated method stub
		return courseResults;
	}	
	
	public void setCourseResults(CourseResult[] courseResults) {
		this.courseResults = courseResults;
	}
	
	public class CourseResult {		
		Integer id;
		Details details; 
		
		[getters and setters]...
	}

	public class Details {

	...

	}
}

I was following along with the process described in http://dlinsin.blogspot.com/2009/11/playing-with-spring-resttemplate.html, with the “real” target domain object encased in a wrapper object (in this case TclApiResponse), and kept getting the consistent error:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [org.tcl.service.TclApiResponse] and content type [application/json]
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:77)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
	at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:199)
...

After much trial and error, I finally tried separating out the domain class into distinct, non-inner classes and it started working. With a 20/20 hindsight Google search, I found 1 blog that mentions this:

http://mangayaa.blogspot.com/2009/08/jackson-json-processor.html

Hopefully this saves someone some time.

Spring Roo, and mixing xml and annotated dependency injection of a Property

I used Spring Roo (with Spring 3.0) to create a simple project with a few domain objects and controllers. I wanted to experiment with using the @Component annotation and autowiring, but was having severe problems trying to autowire a String value (the url of a service) into my @Component managed bean, the string being contained in the xml of the application context. After searching several blogs, this is what I found:

  1. it is not possible to autowire a primitive value using annotations
  2. it WAS not possible before Spring 3, now you can do it with Spring Expression Language (spEL)

Here was my next to last attempt:

webmvc-config.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
				
	<!-- The controllers are autodetected POJOs labeled with the @Controller annotation. 
	<context:component-scan base-package="org.tcl" use-default-filters="false">
		<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
	</context:component-scan> -->

	<!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
	<context:component-scan base-package="org.tcl" />
	<context:annotation-config/>
	
	<!-- Turns on support for mapping requests to Spring MVC @Controller methods
	     Also registers default Formatters and Validators for use across all @Controllers -->
	<mvc:annotation-driven/>

        <util:properties id="appProperties" location="classpath:/app.properties"/> 
...

TclApiService.java:

package org.tcl.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class TclApiService implements ApiService {

	@Value("#{appProperties['tclApiUrl']}") String apiUrl;
	
	@Override
	public ApiResponse call() {
		return null; //breakpoint here, just to check out the value of the apiUrl property 
	}

	public void setApiUrl(String apiUrl) {
		this.apiUrl = apiUrl;
	}

}

app.properties:

tclApiUrl=http://www.mydomain.org/api/courses

No matter WHAT I tried, the tc server startup would fail with errors such as:

No matching bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}


or, in the case of my final spEL attempt:

Field or property 'appProperties' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'

Turns out, this is what is happening:
Since the <context:component-scan> tag occurs before the “appProperties” bean definition in webmvc-config.xml, the bean definition is not available when the @Component-ized class is being constructed. The fix is simple, just move the “appProperties” bean definition above any <context:component-scan> tag. In Roo, keep in mind, at least in my case, that there were actually 2 <context:component-scan> tags, one in applicationContext.xml and one in webmvc-config.xml. Putting my properties bean definition above the one in applicationContext.xml solved the problem. Tc Server now started successfully and the property was populated in my @Component class.

Nowhere in official spring documentation could I find the stipulation that it actually matters where the <context:component-scan> tag is placed. Initially I thought that spring might maintain a map of unresolved dependencies which are satisfied in a round robin fashion, but nope, the xml dependencies are resolved first, then the annotated ones – at least in this simple case.

oracle.sql.TIMESTAMP ClassCastException with SqlRowSet

After 2.5 days of smashing my head against Oracle hell (mixed metaphors?), I finally found a workaround for this strange ClassCastException I was having. I only found 2 or 3 Google results with this odd ClassCastException, so decided that my experience was significant enough to share!

ORIGINAL GOAL:
We had some code resembling the following:

String sqlString = “{some SQL statement that contains an ORDER BY clause}”;
Item item = itemDao.read(itemId);
getJdbcTemplate().query(sqlString,
    new Object[]{itemId},
    new RowCallbackHandler() {
        public void processRow(ResultSet rs) throws SQLException {
            ItemActivity itemActivity = new ItemActivity();
            populateItemActivity(itemActivity, rs, item);
        }
});
 

And populateItemActivity just does some stuff to the ItemActivity instance passed in, like:

public void populateItemActivity(ItemActivity itemActivity, ResultSet rs, Item item) throws SQLException{         
    itemActivity.setFileName(item.getName());
    itemActivity.setDate(rs.getTimestamp("LAST_MODIFIED_TIME"));
    itemActivity.setSize(item.getFileSize());      
    itemActivity.setAuditName(rs.getString("AUDIT_NAME"));
}

We discovered that the “AUDIT_NAME” field value was not populated for all returned rows, and in that case, the ItemActivity object should be populated with the “AUDIT_NAME” value in the record just before it, ordered by itemId and date. My fear was that the processRow(ResultSet rs) callback method was not guaranteed to process rows in the same order that they appeared in the resultset, so my attempt to copy back from the immediate prior record to copy its “AUDIT_NAME” value would be foiled and possibly incorrect.

Looking for a method that I could manipulate the entire ResultSet at one time, and so control the iteration and set a variable that I could copy between row processing, I found the JdbcTemplate.queryForRowSet(String sql, Object[] args) method, which returns a SqlRowSet I thought I could use to iterate explicitly.

We happen to be using Oracle, and a Timestamp value is one of the values in the returned SqlRowSet. This code was throwing the ClassCastException:

public void populateItemActivity(ItemActivity itemActivity, SqlRowSet rs, Item item) throws SQLException{                  
    itemActivity.setFileName(item.getName());
    oracle.sql.TIMESTAMP timestamp = (oracle.sql.TIMESTAMP) rs.getObject("LAST_MODIFIED_TIME ");  <--ClassCastException
    Date date =  (timestamp == null) ? null : new Date(timestamp.dateValue().getTime());   
    itemActivity.setDate(date);
    itemActivity.setSize(item.getFileSize());
    itemActivity.setAuditName(rs.getString("AUDIT_NAME"));
}

NOTE: the code at line 3 and 4 above I got from http://jira.springframework.org/browse/SPR-4886, who appeared to be having the same issue with SqlRowSet returning an oracle.sql.TIMESTAMP instead of a java.sql.Date with a call to rs.getObject.

No matter what I tried, I could not resolve the ClassCastException. Debugging in Eclipse showed that the Object returned from rs.getObject() was a oracle.sql.TIMESTAMP, but casting it to that same class resulted in the ClassCastException. Infuriating! Even gathering other developers, we could not figure this out.

So, NEW GOAL:
So I changed tack and found this other JdbcTemplate.query method with a different signature using a ResultSetExtractor, which allowed me to deal with the entire recordset (it's a ResultSet now instead of a SqlRowSet with the other attempt) at once (instead of a callback method for each row), letting me handle the row iteration explicitly:

getJdbcTemplate().query(sql,
        new Object[]{vaultItem.getVaultItemId()},
        new ResultSetExtractor() {                                             
          public Object extractData(ResultSet rs) throws SQLException,
            org.springframework.dao.DataAccessException {
                 String auditNameBuffer = null;
                 while (rs.next()){
                      ItemActivity itemActivity = new ItemActivity();                                                        
                      String auditName = rs.getString("AUDIT_NAME");
                      if ((null != auditName) ){
                          auditNameBuffer = auditName;
                      }                                                               
                      itemActivity.setAuditName(auditName);
                 }
                 return null;
            }      
     }
);

Project completed, but still don’t know what caused the ClassCastException.

Java Spring, Transactions and MySQL

I spent about 4 hours yesterday trying to figure out why transactions were not rolling back inserts into my mySQL database yesterday, and it turned out to be a problem in somewhere I least expected. 

There are a couple of really good and concise tutorials on how to set up transactions in Spring:

What is supposed to happen is if any exception is thrown in your base class, the transaction-wrapped proxy (TransactionProxyFactoryBean) that Spring is using will roll back your object state, which with Hibernate involved, should cancel any db operations that would have normally taken place. I turned on DEBUG logging, and the transaction was noted as being rolled back but the db was still merrily taking inserts from the frontend, even with the exceptions being thrown.

I finally found this forum that mentioned transactions with mySQL specifically:
"1. if you are using MySQL make sure you have InnoDB tables (not MyISAM or something else)."
Indeed, “show table status like 'testTable'\G;” displayed MyISAM, so a simple “alter table testTable TYPE = InnoDB2;” solved my problem. Craziness. I’m not intimately familiar with MySQL, but there are many debates going on about what engine to use, just google “mysql myisam innodb”. 

MyISAM = speed but does not support transactional rollback
InnoDB = reliability and supports transactions

The best advice I found if I were architecting a mySQL enterprise solution would be to use InnoDB on the master machines, where you might need rollback capability in case of error, and then MyISAM on any slaves, since at the point or replication from the master you should have clean data and the speed of replication would be increased by the usage of MyISAM.  

Anyway, hopefully this saves 4 hours of time from someone else who might be mystified by non-rolling back database rows in spring hibernate transactions like I was.

Google Tasks

Harkening back to my previous post on Task Reminder Services, I was watching DL.tv on TiVo recently and they showed briefly the new Tasks feature in GMail. It’s a new pane that when enabled in Google Labs preferences, allows you to store tasks and subtasks, check them off, and even convert emails to tasks. It also allows you to set a due date for that task, and I was getting excited as I searched for a “Mail me a reminder” feature.. but no such luck. I did go to their forums and request the feature though. Gmail +Tasks (should equal) Reminder Emails.

Bye Bye Sandy

For the last year or so, I’ve been subscribed to a free service called I Want Sandy. Sandy is like a virtual calendar assistant, in that it allocates me a personal email address, which I can send a specially formatted email to. That email could be something like “remind me to pick up my dry cleaning next Wednesday at 6:45pm”, in the subject line or body of the email. At that time, I get an email back from Sandy with a reminder about my dry cleaning.  I certainly am not a power user, using it maybe once or twice a week, but enough to make it convenient for those occasional reminders.

Well, I just got a notice from them that they are shutting their virtual doors on Dec 19. Looks like Twitter has bought their technology, and their CEO is also joining Twitter.  Now, on to look for alternatives:

http://twitter.com/timer – Pros: backed by Twitter’s solid foundation Cons: Limited by Twitter’s access methods – text or browser, no email
http://gopingme.com/ – Pros: They seem to be ready for Sandy’s abandoned users, as they have a tutorial for ex-Sandy users on their home page. Just like Sandy, you can postpone event reminders (reply to reminder email with “remind me about this in 1 day”) type of thing.
http://www.rememberthemilk.com – Pros: Has email-task and receive-email-reminder functionality, but they seems to be 2 distinct operations. Cons: seems to be a full fledged task management system, which I already use Omnifocus for. I really need something just to replace Sandy with- a simple email/get-reminder-later system.

Looks like I will try http://gopingme.com, even with the cheesy service name.