Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for JavaMoney (JSR 354) with the MonetaryAmountType #450
- Loading branch information
1 parent
490a2dd
commit 94b8340
Showing
15 changed files
with
986 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
...nate-types-52/src/main/java/com/vladmihalcea/hibernate/type/money/MonetaryAmountType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package com.vladmihalcea.hibernate.type.money; | ||
|
||
import org.hibernate.HibernateException; | ||
import org.hibernate.engine.spi.SharedSessionContractImplementor; | ||
import org.hibernate.type.BigDecimalType; | ||
import org.hibernate.type.StringType; | ||
import org.hibernate.type.Type; | ||
import org.hibernate.usertype.CompositeUserType; | ||
import org.javamoney.moneta.Money; | ||
|
||
import javax.money.MonetaryAmount; | ||
import java.io.Serializable; | ||
import java.math.BigDecimal; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.Objects; | ||
|
||
import static java.sql.Types.DECIMAL; | ||
import static java.sql.Types.VARCHAR; | ||
|
||
/** | ||
* Maps a {@link MonetaryAmount} object type to composite columns (with amount and with currency). | ||
* | ||
* @author Piotr Olaszewski | ||
*/ | ||
public class MonetaryAmountType implements CompositeUserType { | ||
|
||
@Override | ||
public String[] getPropertyNames() { | ||
return new String[]{"amount", "currency"}; | ||
} | ||
|
||
@Override | ||
public Type[] getPropertyTypes() { | ||
return new Type[]{BigDecimalType.INSTANCE, StringType.INSTANCE}; | ||
} | ||
|
||
@Override | ||
public Object getPropertyValue(Object component, int property) throws HibernateException { | ||
MonetaryAmount monetaryAmount = (MonetaryAmount) component; | ||
if (property == 0) { | ||
return monetaryAmount.getNumber().numberValue(BigDecimal.class); | ||
} else if (property == 1) { | ||
return monetaryAmount.getCurrency(); | ||
} | ||
|
||
throw new IllegalArgumentException("Invalid property index " + property + " for class " + component.getClass()); | ||
} | ||
|
||
@Override | ||
public void setPropertyValue(Object component, int property, Object value) throws HibernateException { | ||
throw new HibernateException("Call setPropertyValue on immutable type " + component.getClass()); | ||
} | ||
|
||
@Override | ||
public Class returnedClass() { | ||
return MonetaryAmount.class; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object x, Object y) throws HibernateException { | ||
return Objects.equals(x, y); | ||
} | ||
|
||
@Override | ||
public int hashCode(Object x) throws HibernateException { | ||
return x.hashCode(); | ||
} | ||
|
||
@Override | ||
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { | ||
if (rs.wasNull()) { | ||
return null; | ||
} | ||
|
||
String amountColumnName = names[0]; | ||
String currencyColumnName = names[1]; | ||
|
||
BigDecimal amount = rs.getBigDecimal(amountColumnName); | ||
String currency = rs.getString(currencyColumnName); | ||
|
||
return Money.of(amount, currency); | ||
} | ||
|
||
@Override | ||
public void nullSafeSet(PreparedStatement st, Object value, int amountColumnIndex, SharedSessionContractImplementor session) throws HibernateException, SQLException { | ||
int currencyColumnIndex = amountColumnIndex + 1; | ||
|
||
if (value == null) { | ||
st.setNull(amountColumnIndex, DECIMAL); | ||
st.setNull(currencyColumnIndex, VARCHAR); | ||
} else { | ||
MonetaryAmount monetaryAmount = (MonetaryAmount) value; | ||
|
||
BigDecimal amount = monetaryAmount.getNumber().numberValue(BigDecimal.class); | ||
String currency = monetaryAmount.getCurrency().getCurrencyCode(); | ||
|
||
st.setBigDecimal(amountColumnIndex, amount); | ||
st.setString(currencyColumnIndex, currency); | ||
} | ||
} | ||
|
||
@Override | ||
public Object deepCopy(Object value) throws HibernateException { | ||
return value; | ||
} | ||
|
||
@Override | ||
public boolean isMutable() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public Serializable disassemble(Object value, SharedSessionContractImplementor session) throws HibernateException { | ||
return (Serializable) value; | ||
} | ||
|
||
@Override | ||
public Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException { | ||
return cached; | ||
} | ||
|
||
@Override | ||
public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner) throws HibernateException { | ||
return original; | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...s-52/src/test/java/com/vladmihalcea/hibernate/type/money/MySQLMonetaryAmountTypeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package com.vladmihalcea.hibernate.type.money; | ||
|
||
import com.vladmihalcea.hibernate.util.AbstractMySQLIntegrationTest; | ||
import org.hibernate.annotations.Columns; | ||
import org.hibernate.annotations.Type; | ||
import org.hibernate.annotations.TypeDef; | ||
import org.javamoney.moneta.Money; | ||
import org.junit.Test; | ||
|
||
import javax.money.MonetaryAmount; | ||
import javax.persistence.*; | ||
import java.math.BigDecimal; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
/** | ||
* @author Piotr Olaszewski | ||
*/ | ||
public class MySQLMonetaryAmountTypeTest extends AbstractMySQLIntegrationTest { | ||
@Override | ||
protected Class<?>[] entities() { | ||
return new Class[]{ | ||
Salary.class | ||
}; | ||
} | ||
|
||
@Test | ||
public void testPersistAndReadMoney() { | ||
Salary _salary = doInJPA(entityManager -> { | ||
Salary salary = new Salary(); | ||
salary.setSalary(Money.of(new BigDecimal("10.23"), "USD")); | ||
|
||
entityManager.persist(salary); | ||
|
||
return salary; | ||
}); | ||
|
||
doInJPA(entityManager -> { | ||
Salary salary = entityManager.find(Salary.class, _salary.getId()); | ||
|
||
assertEquals(salary.getSalary(), Money.of(new BigDecimal("10.23"), "USD")); | ||
}); | ||
} | ||
|
||
@Test | ||
public void testSearchByMoney() { | ||
doInJPA(entityManager -> { | ||
Salary salary1 = new Salary(); | ||
salary1.setSalary(Money.of(new BigDecimal("10.23"), "USD")); | ||
entityManager.persist(salary1); | ||
|
||
Salary salary2 = new Salary(); | ||
salary2.setSalary(Money.of(new BigDecimal("20.23"), "EUR")); | ||
entityManager.persist(salary2); | ||
}); | ||
|
||
doInJPA(entityManager -> { | ||
Money money = Money.of(new BigDecimal("10.23"), "USD"); | ||
Salary salary = entityManager.createQuery("select s from Salary s where salary = :salary", Salary.class) | ||
.setParameter("salary", money) | ||
.getSingleResult(); | ||
|
||
assertEquals(Long.valueOf(1), salary.getId()); | ||
}); | ||
} | ||
|
||
@Entity(name = "Salary") | ||
@Table(name = "salary") | ||
@TypeDef(name = "monetary-amount-currency", typeClass = MonetaryAmountType.class, defaultForType = MonetaryAmount.class) | ||
public static class Salary { | ||
@Id | ||
@GeneratedValue | ||
private Long id; | ||
|
||
@Columns(columns = { | ||
@Column(name = "salary_amount"), | ||
@Column(name = "salary_currency") | ||
}) | ||
@Type(type = "monetary-amount-currency") | ||
private MonetaryAmount salary; | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
|
||
public MonetaryAmount getSalary() { | ||
return salary; | ||
} | ||
|
||
public void setSalary(MonetaryAmount salary) { | ||
this.salary = salary; | ||
} | ||
} | ||
} |
Oops, something went wrong.