Hi, I've come accross a problem when trying to implements some UserTypes.
In my company, we MUST use a library which contains various reusable value objects like this:
Code:
// Typesafe enumeration
class BankAccountType {
public static final US_TYPE = new BankAccountType(1);
public static final FRENCH_TYPE = new BankAccountType(2);
public static final GERMAN_TYPE = new BankAccountType(3);
...
private final int type;
private BankAccountType(int type) { ... }
...
}
// Abstract value object
abstract class AbstractBankAccount {
private final BankAccountType type;
private final String account;
public AbstractBankAccount(BankAccountType type, String account) { ... }
...
}
// Some concrete implementations
class UsBankAccountType {
public UsBankAccountType(String account) { super(BankAccountType.US_TYPE, account); }
}
class FrBankAccountType {
public FrBankAccountType(String account) { super(BankAccountType.FRENCH_TYPE, account); }
}
Now, I'm trying to implement some CompositeUserType for my BankAccounts and that's where the problem is coming. My BankAccountType (typesafe enum) does not contain that much information (I have a dozen types), so I would like to map the accountType to a byte instead of an integer.
Code:
class BankAccountCompositeUserType implements CompositeUserType {
private static final String[] PROPERTY_NAMES = {"value", "type"};
private static final Type[] PROPERTY_TYPES = {Hibernate.STRING, Hibernate.BYTE};
...
}
A developper using the hibernate usertype is not aware that it's using a byte in the database whereas it is implemented as an integer in java.
So, when he tries to do the following:
Code:
session.createQuery("from Customer customer where customer.bankAccount.value = :value and customer.bankAccount.type = :type")
.setParameter("value", "00000012-69")
.setParameter("type", new Integer(BankAccountType.FRENCH_TYPE.getValue())) // INTEGER! NOT A BYTE!
.list();
he will receive a ClassCastException because in the ByteType, the object is casted to a Byte
Code:
class ByteType extends PrimitiveType {
...
public void set(PreparedStatement st, Object value, int index) throws SQLException {
st.setByte(index, ((Byte) value).byteValue());
}
}
A solution could be to replace the cast to a java.lang.Byte into a cast to java.lang.Number
Code:
class ByteType extends PrimitiveType {
...
public void set(PreparedStatement st, Object value, int index) throws SQLException {
st.setByte(index, ((Number) value).byteValue());
}
}
I do not see if there could be a side-effect to this, so I'm posting this message here before eventually insert an issue in JIRA.
Thougts are welcome!
Thanks,
Xavier