Type Converters
Volt uses type converters to translate between Java types and database types. Converters handle both writing values to prepared statements and reading values from result sets.
Built-in Converters
Volt includes converters for common types out of the box:
| Java Type | SQL Type |
|---|---|
String | VARCHAR |
Long / long | BIGINT |
Integer / int | INTEGER |
Double / double | DOUBLE |
BigDecimal | DECIMAL |
Boolean / boolean | BOOLEAN |
UUID | UUID |
Instant | TIMESTAMP |
LocalDate | DATE |
LocalDateTime | TIMESTAMP |
Custom Converters
For types not covered by built-in converters, implement BidirectionalTypeConverter<T>:
java
import me.oskarscot.volt.converter.BidirectionalTypeConverter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class MoneyConverter implements BidirectionalTypeConverter<Money> {
@Override
public void write(PreparedStatement stmt, int index, Money value) throws SQLException {
if (value == null) {
stmt.setNull(index, Types.BIGINT);
} else {
// Store as cents
stmt.setLong(index, value.toCents());
}
}
@Override
public Money read(ResultSet rs, String column) throws SQLException {
long cents = rs.getLong(column);
if (rs.wasNull()) {
return null;
}
return Money.fromCents(cents);
}
}Registering Custom Converters
Register your converter with the Volt instance:
java
volt.registerConverter(Money.class, new MoneyConverter());Register converters before registering entities that use them.
Example: Enum Converter
Store enums as strings in the database:
java
public class OrderStatusConverter implements BidirectionalTypeConverter<OrderStatus> {
@Override
public void write(PreparedStatement stmt, int index, OrderStatus value) throws SQLException {
if (value == null) {
stmt.setNull(index, Types.VARCHAR);
} else {
stmt.setString(index, value.name());
}
}
@Override
public OrderStatus read(ResultSet rs, String column) throws SQLException {
String value = rs.getString(column);
return value != null ? OrderStatus.valueOf(value) : null;
}
}Usage:
java
volt.registerConverter(OrderStatus.class, new OrderStatusConverter());
volt.registerEntity(Order.class);Example: JSON Converter
Store objects as JSON using a library like Gson:
java
public class JsonConverter<T> implements BidirectionalTypeConverter<T> {
private final Gson gson = new Gson();
private final Class<T> type;
public JsonConverter(Class<T> type) {
this.type = type;
}
@Override
public void write(PreparedStatement stmt, int index, T value) throws SQLException {
if (value == null) {
stmt.setNull(index, Types.VARCHAR);
} else {
stmt.setString(index, gson.toJson(value));
}
}
@Override
public T read(ResultSet rs, String column) throws SQLException {
String json = rs.getString(column);
return json != null ? gson.fromJson(json, type) : null;
}
}Handling Nulls
Always handle null values in your converters:
- Writing nulls: Use
stmt.setNull(index, sqlType)with the appropriate SQL type - Reading nulls: Check
rs.wasNull()after reading primitive types, or check for null directly with object types
java
@Override
public Double read(ResultSet rs, String column) throws SQLException {
double value = rs.getDouble(column);
return rs.wasNull() ? null : value; // getDouble returns 0 for NULL
}