클래스 구현하기

public class MonetaryAmountUserType implements UserType {

	public Object assemble(Serializable cached, Object owner)
			throws HibernateException {
		return cached;
	}

	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	public Serializable disassemble(Object value) throws HibernateException {
		return (Serializable) value;
	}

	public boolean equals(Object x, Object y) throws HibernateException {
		if (x == y)
			return true;
		if (x == null || y == null)
			return false;
		return x.equals(y);
	}

	public int hashCode(Object x) throws HibernateException {
		return x.hashCode();
	}

	public boolean isMutable() {
		return false;
	}

	public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
			throws HibernateException, SQLException {

		BigDecimal valueInUSD = resultSet.getBigDecimal(names[0]);
		if (resultSet.wasNull())
			return null;

		// DB에서 가져온 다음에 원하는 값으로 캐스팅 해서 반환.

		return null;
	}

	public void nullSafeSet(PreparedStatement statement, Object value, int index)
			throws HibernateException, SQLException {
		
		// SQL을 DB에 보내기 전에 statement의 특정 위치에 들어갈 값을 변경한다.

	}

	public Object replace(Object original, Object target, Object owner)
			throws HibernateException {
		return original;
	}

	public Class returnedClass() {
		return MonetaryAmount.class;
	}

	public int[] sqlTypes() {
		return new int[] { Hibernate.BIG_DECIMAL.sqlType() };
	}

}
  • sqlTypes() 메소드는 하이버네이트가 어떤 SQL 컬럼 타입으로 DDL 스키마를 생성할 지 알려준다.
  • returnClass() 메소드는 어떤 자바 타입을 맵핑할 것인지 알려준다.
  • deepCopy()는 스냅샷 객체을 전달해 준다. 따라서, immutable한 타입일 경우에는 그냥 넘기면 된다.
  • disassemble()은 MonetaryAmount를 하이버네이트 2차 캐쉬에 집어 넣을 때 호출된다. 이곳에서 직렬화된 상태로 데이터를 캐슁한다.
  • assemble()은 캐쉬된 상태의 데이터를 MonetaryAmount 객체로 변환한다.
  • replace()는 detached 상태의 객체를 merging할 때 사용한다.
  • equals()는 dirty checking 할 때 사용한다.
  • nullSafeGet()은 ResultSet에서 데이터를 가져올 때 사용한다.
  • nullSafeSet()은 PreparedStatement에 저장할 값을 설정할 때 사용한다.

맵핑하기

@org.hibernate.annotations.Type(
    type = " persistence.MonetaryAmountUserType"
)
@Column(name = "INITIAL_PRICE")
private MonetaryAmount initialPrice;

단점

  • 하이버네이트는 Monetary Amount의 속성을 모른다. 따라서 그 안에 있는 amount나 currency를 가져오는 쿼리를 작성할 수 없다.

해결책

  • CompositeUserType을 사용하면 된다.