Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to persist classes like java.util.Currency?

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.

like image 791
Anmol Gupta Avatar asked Apr 14 '15 05:04

Anmol Gupta


People also ask

What is best way to store Currency values in Java application?

1 Answer. Java has Currency class that represents the ISO 4217 currency codes. BigDecimal is the best type for representing currency decimal values.

What is@ entity in Java?

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.


1 Answers

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.

like image 186
wwadge Avatar answered Dec 08 '22 23:12

wwadge