1. 테스트 코드

[#M_ more.. | less.. |

package chapter5.customType.example;

 

import java.util.List;

 

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import org.springframework.test.context.transaction.TransactionConfiguration;

import org.springframework.transaction.annotation.Transactional;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration

@Transactional

@TransactionConfiguration(defaultRollback=true)

public class MemberTest {

 

       @Autowired

       private SessionFactory sessionFactory;

      

       @Test

       public void save() throws Exception {

             Member member = new Member();

             member.setMemberType(MemberType.ADMIN);

             member.setName("기선");

            

             Session session = sessionFactory.openSession();

             session.save(member);

 

             List<Member> memberList = session.createQuery("from Member m where m.memberType = chapter5.customType.example.MemberType.ADMIN").list();

             Member member2 = memberList.get(0);

            

             System.out.println(member);

             assertEquals(MemberType.ADMIN, member2.getMemberType());

            

             session.flush();

             session.close();

       }

}

 

_M#]
* 그냥 하나를 저장하고 그걸 다시 꺼내 봅니다. 꺼낼 때 get을 사용해도 되지만, 쿼리를 어떻게 작성해야 하는지 보기 위해서 HQL로 작성했습니다.

* 그냥 문자열일 뿐인데, 저걸 읽어서 Enum 타입을 알아내고 그것의 name()을 호출한 값으로 대체 해주는 하이버... 정말 똑똑하지 않나요. 대단합니다.

* 위 클래스에 있는 애노테이션들을 붙이면 Spring 2.5 전에 사용하던 AbstractTransactionalDataSource어쩌구저쩌구를 상속받은 클래스와 같은 녀석이 됩니다.(엄밀히 따지면 같지는 않습니다. applicationContext를 가지고 있지 않아서, 명시적으로 getBean() 할 수가 없습니다.)

2. Member 클래스와 MemberType 클래스
[#M_ more.. | less.. |

package chapter5.customType.example;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.EnumType;

import javax.persistence.Enumerated;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

 

import org.hibernate.annotations.Parameter;

import org.hibernate.annotations.Type;

import org.hibernate.annotations.TypeDef;

 

//@TypeDef(name="memberType", typeClass=chapter5.customType.example.StringEnumMemberType.class, parameters={@Parameter(name = "enumClassname", value = "chapter5.customType.example.MemberType")})

@Entity

public class Member {

 

       @Id

       @GeneratedValue(strategy=GenerationType.AUTO)

       private Long id;

 

       @Enumerated(EnumType.STRING)

       @Column(nullable=false, name="TYPE")

//     @Type(type="memberType")

       private MemberType memberType;

 

       private String name;

 

       public Long getId() {

             return id;

       }

 

       public void setId(Long id) {

             this.id = id;

       }

 

       public MemberType getMemberType() {

             return memberType;

       }

 

       public void setMemberType(MemberType memberType) {

             this.memberType = memberType;

       }

 

       public String getName() {

             return name;

       }

 

       public void setName(String name) {

             this.name = name;

       }

 

       @Override

       public String toString() {

             return "id: " + id + " name: " + name + " type: " + memberType;

       }

}

package chapter5.customType.example;

 

public enum MemberType {

      

       ADMIN, USER

 

}

 

_M#]
* 별거 없습니다. id, membeType, name.

* MemberType은 매우 단순한 enum입니다.

* 주목해야 할 것은 MemberType 속성 위에 붙인 @Enumerated 애노테이션 입니다. 이녀석이 굉장한 일을해줍니다.

3. XML 설정
[#M_ more.. | less.. |

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:context="http://www.springframework.org/schema/context"

       xmlns:jee="http://www.springframework.org/schema/jee"

       xmlns:lang="http://www.springframework.org/schema/lang"

       xmlns:p="http://www.springframework.org/schema/p"

       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:util="http://www.springframework.org/schema/util"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd

             http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd

             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

             http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

 

       <context:component-scan base-package="chapter4.identity" />

 

       <tx:annotation-driven transaction-manager="transactionManager" />

 

       <bean id="sessionFactory"

              class="org.springframework.orm.hibernate3.annotation.
AnnotationSessionFactoryBean"
>

             <property name="dataSource" ref="dataSource" />

             <property name="hibernateProperties">

                    <props>

                           <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>

                           <prop key="hibernate.show_sql">true</prop>

                           <prop key="hibernate.hbm2ddl.auto">update</prop>

                           <prop key="hibernate.connection.autocommit">false</prop>

                    </props>

             </property>

             <property name="annotatedClasses" ref="annotatedClasses" />

       </bean>

 

       <util:list id="annotatedClasses">

             <value>chapter5.customType.example.Member</value>

       </util:list>

 

       <bean id="dataSource"

             class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

             <property name="driverClassName" value="org.hsqldb.jdbcDriver" />

             <property name="url" value="jdbc:hsqldb:mem:test" />

             <property name="username" value="sa" />

             <property name="password" value="" />

       </bean>

 

       <bean id="transactionManager"

             class="org.springframework.orm.hibernate3.HibernateTransactionManager"

             p:dataSource-ref="dataSource" p:sessionFactory-ref="sessionFactory" />

 

</beans>

_M#]
* 역시나 뭐 별거 없습니다. 그냥 스프링+하이버 SessionFactory, TransactionManager, DataSource입니다.

4. 결과

Hibernate: insert into Member (id, TYPE, name) values (null, ?, ?)
Hibernate: call identity()
Hibernate: select member0_.id as id0_, member0_.TYPE as TYPE0_, member0_.name as name0_ from Member member0_ where member0_.TYPE='ADMIN'
id: 1 name: 기선 type: ADMIN

결과 쿼리를 보면 재밌습니다. 저는 그냥 @Enumerated 애노테이션 하나 붙였을 뿐인데, 알아서 ADMIN으로 저장해주고, HQL도 알아서 변경해 줍니다. 엘레강트 한 녀석입니다.