I am using hibernate to persist my data. It's a financial application and I am having a hard time persisting the most fundamental entity of the application which is 'Money'. I was using JodaMoney but it's immutable so I am not able to find a good way to persist it. And without persisting my money to database, there is no point of making the application. What would I do with the immutability when I can't even store the state of my object? Then I started creating my own 'Money'(fields as BigDecimal amount and java.util.Currency for currency), I wanted to use 'Currency' of java.util . But, that doesn't have a public constructor so hibernate can not persist that. Please guide me on how to deal with this?
EDIT1: The code for most basic class:
@Entity
public class BasicMoney {
@Embedded
@Id
private BigDecimal amount;
@Embedded
private Currency currency;
//getters and setters, other methods
}
Now, when I make an object of this class and try to store it into database, it doesn't work. Hibernate throws:
org.hibernate.InstantiationException: No default constructor for entity: : java.util.Currency
So, this is the problem which I am facing.
1 Answer. Java has Currency class that represents the ISO 4217 currency codes. BigDecimal is the best type for representing currency decimal values.
An entity is a lightweight persistence domain object. Typically, an entity represents a table in a relational database, and each entity instance corresponds to a row in that table. The primary programming artifact of an entity is the entity class, although entities can use helper classes.
Instead of dealing with a currency string and an amount, teach Hibernate about your type instead. That way you would have:
private Money amount;
instead of
private BigDecimal amount;
private String currency;
so you don't need to convert all over the place.
Here's how I do it:
1) Instead of JodaMoney, use JavaMoney, the JSR-354 project that is expected to be included in Java 9. If you want to stick to JodaMoney, you don't need step #3 below.
2) Add this UserType library to your classpath
3) Create this simple class:
public class CustomPersistentMoneyAmountAndCurrency extends AbstractMultiColumnUserType<MonetaryAmount> {
private static final ColumnMapper<?, ?>[] COLUMN_MAPPERS = new ColumnMapper<?, ?>[] { new CustomStringColumnCurrencyUnitMapper(), new BigDecimalBigDecimalColumnMapper() };
private static final String[] PROPERTY_NAMES = new String[]{ "currency", "number" };
@Override
protected ColumnMapper<?, ?>[] getColumnMappers() {
return COLUMN_MAPPERS;
}
@Override
protected Money fromConvertedColumns(Object[] convertedColumns) {
CurrencyUnit currencyUnitPart = (CurrencyUnit) convertedColumns[0];
BigDecimal amountPart = (BigDecimal) convertedColumns[1];
return Money.of(amountPart, currencyUnitPart);
}
@Override
protected Object[] toConvertedColumns(MonetaryAmount value) {
return new Object[] { value.getCurrency(), value.getNumber().numberValue(BigDecimal.class) };
}
@Override
public String[] getPropertyNames() {
return PROPERTY_NAMES;
}
}
4) Now wherever you want to use this in your Entities you would do:
@TypeDefs(value = {
@TypeDef(name = "moneyAmountWithCurrencyType", typeClass = CustomPersistentMoneyAmountAndCurrency.class)
})
@Entity
@Table(name = "account_entry")
public class AccountEntry {
private Money referenceMoney;
...
@Basic( optional = false )
@Columns(columns = {
@Column( name = "reference_money_currency", nullable = false, length = 3 ),
@Column( name = "reference_money", nullable = false )
})
@Type(type = "moneyAmountWithCurrencyType")
public Money getReferenceMoney() {
return this.referenceMoney;
}
}
And that's it. You will get strong typing all throughout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With