클래스 구현하기

public class MonetaryAmountCompositeUserType implements CompositeUserType {

	public String[] getPropertyNames() {
		return new String[] { "amount", "currency" };
	}

	public Type[] getPropertyTypes() {
		return new Type[] { Hibernate.BIG_DECIMAL, Hibernate.CURRENCY };
	}

	public Object getPropertyValue(Object component, int property)
			throws HibernateException {
		MonetaryAmount monetaryAmount = (MonetaryAmount) component;
		if (property == 0)
			return monetaryAmount.getAmount();
		else
			return monetaryAmount.getCurrency();
	}

	public Object nullSafeGet(ResultSet resultSet, String[] names,
			SessionImplementor session, Object owner)
			throws HibernateException, SQLException {
		BigDecimal value = resultSet.getBigDecimal(names[0]);
		if (resultSet.wasNull())
			return null;
		Currency currency = Currency.getInstance(resultSet.getString(names[1]));
		return new MonetaryAmount(value, currency);
	}

	public void nullSafeSet(PreparedStatement statement, Object value,
			int index, SessionImplementor arg3) throws HibernateException,
			SQLException {
		if (value == null) {
			statement.setNull(index, Hibernate.BIG_DECIMAL.sqlType());
			statement.setNull(index + 1, Hibernate.CURRENCY.sqlType());
		} else {
			MonetaryAmount amount = (MonetaryAmount) value;
			String currencyCode = amount.getCurrency().getCurrencyCode();
			statement.setBigDecimal(index, amount.getAmount());
			statement.setString(index + 1, currencyCode);
		}
	}

	public void setPropertyValue(Object arg0, int arg1, Object arg2)
			throws HibernateException {
		throw new UnsupportedOperationException("Immutable MonetaryAmount!");
	}

}
  • CompositeUserType 인터페이스를 구현한다.
  • nullSafeSet()은 ResultSet에 담겨있는 두 개의 값을 Monetary 객체의 속성값으로 변환하면 된다.
  • nullSafeSet()은 객체가 가진 두 개의 값을 DB에 저장하도록 statement를 수정한다.
  • getPropertyNames()를 사용해서 Value Type의 속성들을 알려준다.
  • getPropertyValue()를 사용해서 Value Type의 각각의 속성이 가진 값을 알려준다.
  • setPropertyValue()를 사용해서 Value Type의 속성에 값을 설정한다.

맵핑하기

@org.hibernate.annotations.Type(
    type = "persistence.MonetaryAmountUserType"
)
@org.hibernate.annotations.Columns(columns = {
    @Column(name="INITIAL_PRICE"),
    @Column(name="INITIAL_PRICE_CURRENCY", length = 2)
})
private MonetaryAmount initialPrice;
  • 다음과 같이 쿼리를 작성할 수 있다.
from Item i
where i.initialPrice.amount > 100.0
  and i.initialPrice.currency = 'AUD'