Search Results

Keyword: ‘DBUnit’

Formatting Timestamps in DBUnit

March 19th, 2005
Comments Off

Another recent problem I’ve had with DBUnit has been the mandated format for TIMESTAMP columns in the test data. You’re forced to define TIMESTAMPs as yyyy-MM-dd HH:mm:ss.fffffffff, which is great if you need that level of granularity. I don’t, and revisiting all of my test data was too cumbersome. So I set about changing the format for my TIMESTAMPs.

The DataType

Each data type is represented by an implementation of the DataType class. DBUnit’s existing TimestampDataType class is what enforces the verbose format. By creating a new implementation of that class, I was able to define multiple TIMESTAMP formats, using the SimpleDateFormat class.

public class CustomTimestampDataType extends AbstractDataType {

public CustomTimestampDataType() {
super(”TIMESTAMP”, Types.TIMESTAMP, Timestamp.class, false);
}
public Object typeCast(Object value) throws TypeCastException {
if (value == null || value == ITable.NO_VALUE) {
return null;
}
if (value instanceof java.sql.Timestamp) {
return value;
}
if (value instanceof java.util.Date) {
java.util.Date date = (java.util.Date) value;
return new java.sql.Timestamp(date.getTime());
}

if (value instanceof Long) {
Long date = (Long) value;
return new java.sql.Timestamp(date.longValue());
}
if (value instanceof String) {
String stringValue = (String) value;
// Probably a java.sql.Date, try it just in case!
if (stringValue.length() == 10) {
try {
long time = java.sql.Date.valueOf(stringValue).getTime();
return new java.sql.Timestamp(time);
}
catch (IllegalArgumentException e) {
// Was not a java.sql.Date, let Timestamp handle this value
}
}
try {
String formats[] =
{”yyyy-MM-dd HH:mm”,
“yyyy-MM-dd HH:mm a”,
“yyyy-MM-dd HH:mm:ss.fffffffff”};
Timestamp ts = null;
for (int i = 0; i < formats.length; i++) {
SimpleDateFormat sdf = new SimpleDateFormat(formats[i]);
try {
Date date = sdf.parse(stringValue);
ts = new Timestamp(date.getTime());
return ts;
}
catch (ParseException e) {
}
}
}
catch (IllegalArgumentException e) {
throw new TypeCastException(value, this, e);
}
}
throw new TypeCastException(value, this);
}
public boolean isDateTime() {
return true;
}
public Object getSqlValue(int column, ResultSet resultSet)
throws SQLException, TypeCastException {
Timestamp value = resultSet.getTimestamp(column);
if (value == null || resultSet.wasNull()) {
return null;
}
return value;
}
public void setSqlValue(Object value, int column, PreparedStatement statement)
throws SQLException, TypeCastException {
statement.setTimestamp(column, (java.sql.Timestamp) typeCast(value));
}
}

Unfortunately, DBUnit doesn’t allow me to simply register this new class. Instead, I have to go about creating a DataTypeFactory.

The DataTypeFactory

The DataTypeFactory is pretty simple since I just needed to override a small portion of the base class’s functionality.

public class CustomDataTypeFactory extends DefaultDataTypeFactory {

public DataType createDataType(int sqlType, String sqlTypeName)
throws DataTypeException {
if (sqlType == Types.TIMESTAMP) {
return new CustomTimestampDataType();
}
else {
return super.createDataType(sqlType, sqlTypeName);
}
}
}

Next, I had to tell DBUnit about the new factory. (You can register new factories but not individual data types.)

Registering the DataTypeFactory

This was the easiest part to figure out:

IDatabaseConnection conn = new DatabaseConnection(c);
conn.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
new CustomDataTypeFactory());

Hopefully this saves someone a good deal of aggravation.

nick Uncategorized

Workaround for DBUnit

March 8th, 2005
Comments Off

DBUnit has an odd requirement for tables used for testing: Each table must have a primary key defined. If you don’t have a primary key for a given table when you’re loading data, you’ll get an exception. To work around this exception, you have to create your own implementation of DBUnits IColumnFilter interface and register it. The following code listing has a trivial implementation of the interface:

public class MyColumnFilter implements IColumnFilter {
public boolean accept(String tableName, Column column) {
// since my seating_links table doesn’t have a primary key,
// just return true;
if (tableName != null && tableName.equals(”seating_links”)) {
return true;
}
else {
if (column.getName().equals(”id”)) {
return true;
}
else {
return false;
}
}
}
}

With the implementation done, we just need to tell DBUnit to use it:

IDatabaseConnection conn = new DatabaseConnection(jdbcConn);
conn.getConfig().setProperty(
“http://www.dbunit.org/properties/primaryKeyFilter”,
new MyColumnFilter());

This is a little long-winded for something that should be trivial. However, I have this code in my base test case class so I don’t need to duplicate it throughout the test code.

nick Uncategorized