RESOLVED - issue BATCH-281: Null fields cause problems in Oracle and Derby
http://jira.springframework.org/browse/BATCH-281
This commit is contained in:
@@ -20,7 +20,6 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -33,13 +32,10 @@ import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.core.domain.JobInstance;
|
||||
import org.springframework.batch.core.domain.JobInstanceProperties;
|
||||
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
|
||||
import org.springframework.batch.core.repository.NoSuchBatchDomainObjectException;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -142,7 +138,7 @@ public class JdbcJobDao implements JobDao, InitializingBean {
|
||||
private String createJobKey(JobInstanceProperties jobInstanceProperties){
|
||||
|
||||
Map props = jobInstanceProperties.getParameters();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
StringBuilder stringBuilder = new StringBuilder("params:");
|
||||
for(Iterator it = props.entrySet().iterator();it.hasNext();){
|
||||
Entry entry = (Entry)it.next();
|
||||
stringBuilder.append(entry.toString() + ";");
|
||||
@@ -492,49 +488,7 @@ public class JdbcJobDao implements JobDao, InitializingBean {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Private inner class for mapping values from the JOB_PARAMETERS table into the java
|
||||
* JobParameters class. TODO: is this going to be used? If not can we delete it?
|
||||
*/
|
||||
private static class JobParameterCallbackHandler implements RowCallbackHandler{
|
||||
|
||||
private JobInstancePropertiesBuilder parametersBuilder;
|
||||
|
||||
public JobParameterCallbackHandler() {
|
||||
parametersBuilder = new JobInstancePropertiesBuilder();
|
||||
}
|
||||
|
||||
public void processRow(ResultSet rs) throws SQLException {
|
||||
|
||||
ParameterType parameterType = ParameterType.getType(rs.getString("TYPE_CD"));
|
||||
|
||||
String key = rs.getString("KEY");
|
||||
|
||||
if(parameterType == ParameterType.STRING){
|
||||
parametersBuilder.addString(key, rs.getString("STRING_VAL"));
|
||||
}
|
||||
else if(parameterType == ParameterType.LONG){
|
||||
parametersBuilder.addLong(key, new Long(rs.getLong("LONG_VAL")));
|
||||
}
|
||||
else if(parameterType == ParameterType.DATE){
|
||||
//I debated about just passing the Timestamp in, however, I didn't want there to be any equality
|
||||
//issues when comparing a java.util.Date to a timestamp.
|
||||
Timestamp ts = rs.getTimestamp("DATE_VAL");
|
||||
parametersBuilder.addDate(key, new Date(ts.getTime()));
|
||||
}
|
||||
else{
|
||||
//invalid type code, error out.
|
||||
throw new DataRetrievalFailureException("Invalid JobParameter type");
|
||||
}
|
||||
}
|
||||
|
||||
public JobInstanceProperties getJobParmeters(){
|
||||
return parametersBuilder.toJobParameters();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ParameterType {
|
||||
|
||||
private final String type;
|
||||
|
||||
@@ -21,33 +21,57 @@ import java.util.Date;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
|
||||
|
||||
/**
|
||||
* Convenient {@link JobIdentifier} implementation that identifies itself by a
|
||||
* {@link Date} as well as an optional String key. The time portion of the
|
||||
* schedule date is significant, and clients are responsible for truncating it
|
||||
* if it represents a date rather than a timestamp.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ScheduledJobIdentifier extends DefaultJobIdentifier implements JobIdentifier {
|
||||
|
||||
|
||||
public static final String SCHEDULE_DATE = "schedule.date";
|
||||
|
||||
|
||||
ScheduledJobIdentifier() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
|
||||
public ScheduledJobIdentifier(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param key
|
||||
* Convenience constructor that leaves the schedule date null.
|
||||
*
|
||||
* @param name the name of the job
|
||||
* @param key a unique key for this execution
|
||||
*/
|
||||
public ScheduledJobIdentifier(String name, String key) {
|
||||
super(name, key);
|
||||
}
|
||||
|
||||
public ScheduledJobIdentifier(String name, Date scheduleDate){
|
||||
|
||||
/**
|
||||
* Convenience constructor that leaves the key null.
|
||||
*
|
||||
* @param name the name of the job
|
||||
* @param scheduleDate a timestamp
|
||||
*/
|
||||
public ScheduledJobIdentifier(String name, Date scheduleDate) {
|
||||
super(name, new JobInstancePropertiesBuilder().addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
|
||||
}
|
||||
|
||||
public ScheduledJobIdentifier(String name, String jobKey, Date scheduleDate){
|
||||
super(name, new JobInstancePropertiesBuilder().addString(ScheduledJobIdentifier.JOB_KEY, jobKey).
|
||||
addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
|
||||
|
||||
/**
|
||||
* Convenience constructor with all properties.
|
||||
*
|
||||
* @param name the name of the job
|
||||
* @param key a unique key for this execution
|
||||
* @param scheduleDate a timestamp
|
||||
*/
|
||||
public ScheduledJobIdentifier(String name, String key, Date scheduleDate) {
|
||||
super(name, new JobInstancePropertiesBuilder().addString(ScheduledJobIdentifier.JOB_KEY, key).addDate(
|
||||
SCHEDULE_DATE, scheduleDate).toJobParameters());
|
||||
}
|
||||
|
||||
public Date getScheduleDate() {
|
||||
|
||||
@@ -272,6 +272,39 @@ public abstract class AbstractJobDaoTests extends
|
||||
|
||||
}
|
||||
|
||||
public void testJobWithScheduledJobIdentifier() throws Exception {
|
||||
Date date = new Date();
|
||||
ScheduledJobIdentifier jobIdentifier = new ScheduledJobIdentifier("Job1", "testKey", date);
|
||||
|
||||
// Create job.
|
||||
job = jobDao.createJob(jobIdentifier);
|
||||
|
||||
List jobs = jobDao.findJobs(jobIdentifier);
|
||||
|
||||
assertEquals(1, jobs.size());
|
||||
assertEquals(job.getName(), ((JobInstance) jobs.get(0)).getName());
|
||||
assertEquals(jobIdentifier.getJobKey(), ((JobInstance) jobs.get(0)).
|
||||
getIdentifier().getJobInstanceProperties().getString(DefaultJobIdentifier.JOB_KEY));
|
||||
|
||||
}
|
||||
|
||||
public void testJobWithScheduledJobIdentifierAndDifferentTime() throws Exception {
|
||||
Date date = new Date();
|
||||
ScheduledJobIdentifier jobIdentifier = new ScheduledJobIdentifier("Job1", "testKey", date);
|
||||
|
||||
// Create job.
|
||||
job = jobDao.createJob(jobIdentifier);
|
||||
|
||||
Date later = new Date(date.getTime()+3600000);
|
||||
ScheduledJobIdentifier laterIdentifier = new ScheduledJobIdentifier("Job1", "testKey", later);
|
||||
|
||||
List jobs = jobDao.findJobs(laterIdentifier);
|
||||
|
||||
// Different timestamp is different identifier...
|
||||
assertEquals(0, jobs.size());
|
||||
|
||||
}
|
||||
|
||||
public void testFindJobExecutions(){
|
||||
|
||||
List results = jobDao.findJobExecutions(job);
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.springframework.batch.execution.repository.dao;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.batch.core.runtime.SimpleJobIdentifier;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
public class JdbcJobDaoTests extends AbstractJobDaoTests {
|
||||
@@ -16,16 +17,21 @@ public class JdbcJobDaoTests extends AbstractJobDaoTests {
|
||||
public void testUpdateJobExecutionWithLongExitCode() {
|
||||
|
||||
assertTrue(LONG_STRING.length() > 250);
|
||||
jobExecution.setExitStatus(ExitStatus.FINISHED
|
||||
.addExitDescription(LONG_STRING));
|
||||
jobExecution.setExitStatus(ExitStatus.FINISHED.addExitDescription(LONG_STRING));
|
||||
jobDao.update(jobExecution);
|
||||
|
||||
List executions = jdbcTemplate.queryForList(
|
||||
"SELECT * FROM BATCH_JOB_EXECUTION where JOB_ID=?",
|
||||
List executions = jdbcTemplate.queryForList("SELECT * FROM BATCH_JOB_EXECUTION where JOB_ID=?",
|
||||
new Object[] { job.getId() });
|
||||
assertEquals(1, executions.size());
|
||||
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0))
|
||||
.get("EXIT_MESSAGE"));
|
||||
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0)).get("EXIT_MESSAGE"));
|
||||
}
|
||||
|
||||
public void testJobInstanceParametersNotNullOrEmptyWithSimpleJobIdentifier() {
|
||||
job = jobDao.createJob(new SimpleJobIdentifier("foo"));
|
||||
Map map = jdbcTemplate.queryForMap("SELECT * FROM BATCH_JOB_INSTANCE where ID=?",
|
||||
new Object[] { job.getId() });
|
||||
String key = (String) map.get("JOB_KEY");
|
||||
assertTrue("Key should be non-zero length (otherwise Oracle will treat as null)", key.length()>0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user