-
-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FastMoney or Money CompositeUserType mapping for Hibernate - ideas? #185
Comments
Which mapping did you try, Jadira? |
First of all, SQL has a CAST operator which can be used to convert varchar to number so you’ll be able to use agregated function SUM, MIN etc. |
Not sure, how you came to SourceForge with Jadira, maybe it still uses that for downloads, but the Issue tracker is https://github.com/JadiraOrg/jadira/issues. Would someone consider filing an issue there? |
This is not an issue. It looks like uded wanted to use hibernate’s composition mapping which needs for setters. Jadira will help you. |
Jadira is a good solution. public class PersistentMoneyAmountAndCurrency implements CompositeUserType { public String[] getPropertyNames() { // ORDER IS IMPORTANT! it must match the order the columns are defined in the property mapping return new String[]{"currency", "amount"}; } public Type[] getPropertyTypes() { return new Type[]{StringType.INSTANCE, BigDecimalType.INSTANCE}; } @Override public Class returnedClass() { return Money.class; } public Object getPropertyValue(Object component, int propertyIndex) { if (component == null) { return null; } final Money money = (Money) component; switch (propertyIndex) { case 0: return money.getCurrency().getCurrencyCode(); case 1: return money.getNumber().numberValue(BigDecimal.class); default: throw new HibernateException("Invalid property index [" + propertyIndex + "]"); } } public void setPropertyValue(Object component, int propertyIndex, Object value) { if (component == null) { return; } throw new HibernateException("Called setPropertyValue on an immutable type {" + component.getClass() + "}"); } @Override public Object nullSafeGet(ResultSet resultSet, String[] names, SharedSessionContractImplementor session, Object object) throws SQLException { assert names.length == 2; //owner here is of type TestUser or the actual owning Object Money money = null; final String currency = resultSet.getString(names[0]); //Deferred check after first read if (!resultSet.wasNull()) { final BigDecimal amount = resultSet.getBigDecimal(names[1]); money = (Money) MoneyUtils.amount(amount, currency); } return money; } @Override public void nullSafeSet(PreparedStatement preparedStatement, Object value, int property, SharedSessionContractImplementor session) throws SQLException { if (null == value) { preparedStatement.setNull(property, StringType.INSTANCE.sqlType()); preparedStatement.setNull(property + 1, BigDecimalType.INSTANCE.sqlType()); } else { final Money amount = (Money) value; preparedStatement.setString(property, amount.getCurrency().getCurrencyCode()); preparedStatement.setBigDecimal(property + 1, amount.getNumber().numberValue(BigDecimal.class)); } } /** * Used while dirty checking - control passed on to the {@link MonetaryAmount} */ @Override public boolean equals(final Object o1, final Object o2) { return Objects.equals(o1, o2); } @Override public int hashCode(final Object value) { return value.hashCode(); } /** * Helps hibernate apply certain optimizations for immutable objects */ @Override public boolean isMutable() { return false; } /** * Used to create Snapshots of the object */ @Override public Object deepCopy(final Object value) { return value; //if object was immutable we could return the object as its is } /** * method called when Hibernate puts the data in a second level cache. The data is stored * in a serializable form */ @Override public Serializable disassemble(final Object value, final SharedSessionContractImplementor paramSessionImplementor) { //Thus the data Types must implement serializable return (Serializable) value; } /** * Returns the object from the 2 level cache */ @Override public Object assemble(final Serializable cached, final SharedSessionContractImplementor sessionImplementor, final Object owner) { //would work as the class is Serializable, and stored in cache as it is - see disassemble return cached; } /** * Method is called when merging two objects. */ @Override public Object replace(final Object original, final Object target, final SharedSessionContractImplementor paramSessionImplementor, final Object owner) { return original; // if immutable use this } } Then use it like this in your entity @TypeDef(name = "persistentMoneyAmountAndCurrency", typeClass = PersistentMoneyAmountAndCurrency.class)
|
In orousseil's comment. Does anyone know what an equivalent to this statement is
javamoney.moneta.spi.MoneyUtils does not seem to have an amount method? Edit: Of course this should be:
Kindly, |
@rollenwiese Would this new method in MoneyUtils help with Hibernate? |
On the code I posted, I was using my own |
It would be such a great if there will be official Hibernate Custom type implementation in this package. 🙏 |
At least hibernate-validator already supports validation of |
The Hibernate Types project is OSS. Anyone can provide new Types. The same with Hibernate. If you wait for the core maintainers to implement all possible features, you will have to wait a very very long time. |
Same goes for the core maintainers of the Money JSR which is effectively in Maintenance mode ;-) |
OK, I went through the API as much as I could and as I do fully understand why it is created the way it is - it causes a problem for JPA/Hibernate mapping.
The easiest and, possibly, the safest way is to use
toString
/Parse
to represent the amount and currency in the DB. But this is far from perfect if one would like, well I do not know... like operate with SQL on this representation?sum
,min
,max
... none will work onVARCHAR
the way I would like to. But I do not see alternatives as I do not have setters to operate by property index on the object. Meaning either I have all data or I won't create an object that I can pass on by reference... or maybe I am missing something.Any bits of advice? Thoughts on this? I would love to store FastMoney as two separate columns, but I do not see a reasonable option for this...
The text was updated successfully, but these errors were encountered: