Recently, one of my good friends asked me to make a simple web application for them. Since I’ve been wanting to learn Spring for quite some time now, I decided to take on his request because I’m such a good person. Just kidding, I really just wanted to have an excuse to learn Spring.
After a few minutes of Google searching, I came across the official tutorial for Spring MVC. I noticed that the tutorial was a bit outdated and had a few errors, but I still managed to finish the tutorial in spite of that.
Now that I already did all the necessary stuff to make a simple web application in Spring, I decided to add a bit more to get started with the project that my friend asked me to do. The first thing that I tried to do was learn how to do CRUD operations in Spring. I started by making a Java bean called company:
I’m not sure if I’ve overridden hashCode() and equals() right, but that’s not really the issue here. Since the tutorial was all about TDD, I decided to make a unit test for the bean that I just created:
Of course, a test as simple as this would most likely pass. Just kidding. To be honest, I’m not really sure about the tests on hashCode and equals, but again, that’s not the issue here. After making the bean, I made an interface to do handle the bean services:
package gpspeedometer.service;import java.util.ArrayList;import java.util.List;import gpspeedometer.domain.Company;import gpspeedometer.repository.CompanyDao;import gpspeedometer.repository.InMemoryCompanyDao;import junit.framework.TestCase;publicclassSimpleCompanyManagerTestsextends TestCase {private SimpleCompanyManager companyManager;private List<Company> companies;privatestaticint COMPANY_COUNT = 2;privatestatic String COMPANY_ONE ="Bus Company #1";privatestatic String COMPANY_TWO ="Bus Company #2";protectedvoidsetUp()throws Exception {
companyManager =new SimpleCompanyManager();
companies =new ArrayList<Company>();
Company company =new Company();
company.setName("Bus Company #1");
companies.add(company);
company =new Company();
company.setName("Bus Company #2");
companies.add(company);
CompanyDao companyDao =new InMemoryCompanyDao(companies);
companyManager.setCompanyDao(companyDao);}publicvoidtestGetCompaniesWithNoCompanies(){
companyManager =new SimpleCompanyManager();
companyManager.setCompanyDao(new InMemoryCompanyDao(null));
assertNull(companyManager.getCompanies());}publicvoidtestGetCompanies(){
List<Company> companies = companyManager.getCompanies();
assertNotNull(companies);
assertEquals(COMPANY_COUNT, companyManager.getCompanies().size());
Company company = companies.get(0);
assertEquals(COMPANY_ONE, company.getName());
company = companies.get(1);
assertEquals(COMPANY_TWO, company.getName());}}
Well, hey, the tests passed again. Lucky me. At this point, I’m pretty sure you’re already bored reading this entry. I wouldn’t be surprised if you skipped over what I said over here. I’m feeling sad about this, so bear with me for a while. Anyway, let’s move on to the database part of the program. Again, I made another interface to handle the DAO of Company:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package gpspeedometer.repository;import java.util.List;import gpspeedometer.domain.Company;publicinterfaceCompanyDao{public List<Company>getCompanyList();public Company getCompany(int id);publicvoidaddCompany(Company company);publicvoideditCompany(Company company);}
I was on a roll until this happened. I made the implementation class for CompanyDao:
package gpspeedometer.repository;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;import org.springframework.jdbc.core.simple.ParameterizedRowMapper;import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;import gpspeedometer.domain.Company;publicclassJdbcCompanyDaoextends SimpleJdbcDaoSupport implements CompanyDao {protectedfinal Log logger = LogFactory.getLog(getClass());public List<Company>getCompanyList(){
logger.info("Getting companies.");
List<Company> companies = getSimpleJdbcTemplate().query("SELECT id, name FROM companies",new CompanyMapper());return companies;}public Company getCompany(int id){
logger.info("Getting company with id = "+ id);
Company company = getSimpleJdbcTemplate().queryForObject("SELECT id, name FROM companies WHERE id = ?",new CompanyMapper(), id);return company;}publicvoidaddCompany(Company company){
logger.info("Inserting company: "+ company.getName());int count = getSimpleJdbcTemplate().update("INSERT INTO companies (name) VALUES (:name)",new MapSqlParameterSource().addValue("name", company.getName()));
logger.info("Rows affected: "+ count);}publicvoideditCompany(Company company){
logger.info("Editing company: "+ company.getName());int count = getSimpleJdbcTemplate().update("UPDATE companies SET name = :name WHERE id = :id",new MapSqlParameterSource().addValue("name", company.getName()).addValue("id", company.getId()));
logger.info("Rows affected: "+ count);}privatestaticclassCompanyMapperimplements ParameterizedRowMapper<Company>{public Company mapRow(ResultSet rs,int rowNum)throws SQLException {
Company company =new Company();
company.setId(rs.getInt("id"));
company.setName(rs.getString("name"));return company;}}}
If you look at the code at first glance, you wouldn’t see anything wrong with it. Unfortunately, that wasn’t the case. I learned that from the unit test that I made for the previous class:
package gpspeedometer.repository;import java.util.List;import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;import gpspeedometer.domain.Company;publicclassJdbcCompanyDaoTestsextends AbstractTransactionalDataSourceSpringContextTests {private CompanyDao companyDao;publicvoidsetCompanyDao(CompanyDao companyDao){this.companyDao= companyDao;}@Overrideprotected String[]getConfigLocations(){returnnew String[]{"classpath:test-context.xml"};}@OverrideprotectedvoidonSetUpInTransaction()throws Exception {super.deleteFromTables(new String[]{"companies"});super.executeSqlScript("file:db/load_data.sql",true);}publicvoidtestGetCompanyList(){
List<Company> companies = companyDao.getCompanyList();
assertEquals("Wrong number of companies?", 3, companies.size());}publicvoidtestGetCompany(){
Company company = companyDao.getCompany(1);
assertEquals("Benjo", company.getName());}publicvoidtestAddCompany(){
Company company =new Company();
company.setName("Ponce Inc.");
companyDao.addCompany(company);
company = companyDao.getCompany(4);
assertEquals("Wrong name of company?","Ponce Inc.", company.getName());}publicvoidtestEditCompany(){
List<Company> companies = companyDao.getCompanyList();for(Company company : companies){
company.setName("Lasam Inc.");
companyDao.editCompany(company);}
List<Company> updatedCompanies = companyDao.getCompanyList();for(Company company : updatedCompanies){
assertEquals("Wrong name of company?","Lasam Inc.", company.getName());}}}
This test, testGetCompany is failing. Here’s the error that I got from JUnit in Ant:
1
2
3
4
5
6
7
8
9
10
11
12
[junit] Testcase: testAddCompany(gpspeedometer.repository.JdbcCompanyDaoTests): Caused an ERROR
[junit] Incorrect result size: expected 1, actual 0[junit] org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0[junit] at org.springframework.dao.support.DataAccessUtils.requiredSingleResult(DataAccessUtils.java:71)[junit] at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:722)[junit] at org.springframework.jdbc.core.simple.SimpleJdbcTemplate.queryForObject(SimpleJdbcTemplate.java:169)[junit] at gpspeedometer.repository.JdbcCompanyDao.getCompany(JdbcCompanyDao.java:29)[junit] at gpspeedometer.repository.JdbcCompanyDaoTests.testAddCompany(JdbcCompanyDaoTests.java:44)[junit] at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)[junit][junit][junit] Test gpspeedometer.repository.JdbcCompanyDaoTests FAILED
For some reason, the query returns nothing, which results in an empty result set. The development came to a screeching halt the moment this error appeared. The reason why this sucked is because I’m still working my way around Spring and how it works. I haven’t got a clue as to how this happened since I don’t really know what’s happening behind the scenes with my code. Let’s take a look at the faulty methods here:
1
2
3
4
5
6
7
public Company getCompany(int id){
logger.info("Getting company with id = "+ id);
Company company = getSimpleJdbcTemplate().queryForObject("SELECT id, name FROM companies WHERE id = ?",new CompanyMapper(), id);return company;}
1
2
3
4
5
publicvoidtestGetCompany(){
Company company = companyDao.getCompany(1);
assertEquals("Benjo", company.getName());}
On my database, there’s a table called company that has “Benjo” as its name on the first row, so I checked if the test data really made it into the database:
If this is the case, the method, getCompany(), should be able to retrieve a row from the database, but unfortunately, that didn’t happen. It always returned an empty result set.
Since I couldn’t handle the problem by myself anymore, I turned to StackOverflow for answers. My problem is still vague for me, so I decided to ask a very generic question about my problem. My question didn’t receive any good feedback. All I got was a guy asking me why I was still using Spring 2.5 instead of 3.0, which was out of the question. Honestly, I don’t even know how that is relevant to my problem. I’m pretty sure migrating to 3.0 won’t solve my problem since I’ll most likely be writing the same code if that happens.
Anyway, since I still haven’t received any help from anyone, and I’m still clueless as to how Spring works, I decided to blog about it right now. This really made me sad because I can’t even do simple CRUD operations. What more if I needed to do something more complex? Hopefully, someone will be patient enough to read this and help me with my problem.