mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-01 07:19:15 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@11779 1b8cb986-b30d-0410-93ca-fae66ebed9b2
503 lines
23 KiB
XML
503 lines
23 KiB
XML
<chapter id="persistent-classes" revision="2">
|
|
<title>영속 클래스들</title>
|
|
|
|
<para>
|
|
영속 클래스들은 비지니스 문제의 엔티티들(예를 들어 E-Commerce 어플리케이션에서 고객이나 주문)을 구현하는
|
|
어플리케이션 내의 클래스들이다. 영속 클래스들의 인스턴스들은 영속 상태에 있는 것으로 전혀 간주되지 않는다 -
|
|
대신에 하나의 인스턴스는 transient 또는 detached 상태일 수 있다.
|
|
</para>
|
|
|
|
<para>
|
|
Hibernate는 이들 클래스들이 Plain Old Java Object (POJO) 프로그래밍 모형으로서 알려진, 몇몇 간단한
|
|
규칙들을 따를 경우에 가장 잘 동작한다. 하지만 이들 규칙들 중 어떤 것도 어려운 사양들이 아니다. 진정 Hibernate3는
|
|
당신의 영속 객체들의 특징에 대해 매우 적은 것을 가정한다. 당신은 다른 방법들로 도메인 모형을 표현할 수 있다 :
|
|
예를 들어 <literal>Map</literal> 인스턴스의 트리들을 사용하기.
|
|
</para>
|
|
|
|
<sect1 id="persistent-classes-pojo">
|
|
<title>간단한 POJO 예제</title>
|
|
|
|
<para>
|
|
대부분의 자바 어플리케이션들은 고양이과들을 표현하는 영속 클래스를 필요로 한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package eg;
|
|
import java.util.Set;
|
|
import java.util.Date;
|
|
|
|
public class Cat {
|
|
private Long id; // identifier
|
|
|
|
private Date birthdate;
|
|
private Color color;
|
|
private char sex;
|
|
private float weight;
|
|
private int litterId;
|
|
|
|
private Cat mother;
|
|
private Set kittens = new HashSet();
|
|
|
|
private void setId(Long id) {
|
|
this.id=id;
|
|
}
|
|
public Long getId() {
|
|
return id;
|
|
}
|
|
|
|
void setBirthdate(Date date) {
|
|
birthdate = date;
|
|
}
|
|
public Date getBirthdate() {
|
|
return birthdate;
|
|
}
|
|
|
|
void setWeight(float weight) {
|
|
this.weight = weight;
|
|
}
|
|
public float getWeight() {
|
|
return weight;
|
|
}
|
|
|
|
public Color getColor() {
|
|
return color;
|
|
}
|
|
void setColor(Color color) {
|
|
this.color = color;
|
|
}
|
|
|
|
void setSex(char sex) {
|
|
this.sex=sex;
|
|
}
|
|
public char getSex() {
|
|
return sex;
|
|
}
|
|
|
|
void setLitterId(int id) {
|
|
this.litterId = id;
|
|
}
|
|
public int getLitterId() {
|
|
return litterId;
|
|
}
|
|
|
|
void setMother(Cat mother) {
|
|
this.mother = mother;
|
|
}
|
|
public Cat getMother() {
|
|
return mother;
|
|
}
|
|
void setKittens(Set kittens) {
|
|
this.kittens = kittens;
|
|
}
|
|
public Set getKittens() {
|
|
return kittens;
|
|
}
|
|
|
|
// addKitten not needed by Hibernate
|
|
public void addKitten(Cat kitten) {
|
|
kitten.setMother(this);
|
|
kitten.setLitterId( kittens.size() );
|
|
kittens.add(kitten);
|
|
}
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
준수할 네 개의 주요 규칙들이 다음에 있다:
|
|
</para>
|
|
|
|
|
|
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
|
<title>아규먼트 없는 생성자를 구현하라 </title>
|
|
|
|
<para>
|
|
<literal>Cat</literal>은 아규먼트 없는 생성자를 갖는다. 모든 영속 클래스들은 Hibernate는
|
|
<literal>Constructor.newInstance()</literal>를 사용하여 그것들을 초기화 시킬 수 있도록 디폴트 생성자
|
|
(public이 아닐 수 있다)를 가져야 한다. 우리는 Hibernate 내에서 런타임 프락시 생성을 위한 최소한의
|
|
<emphasis>패키지</emphasis> 가시성(visibility)를 가진 디폴트 생성자를 가질 것을 강력하게 권장한다.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="persistent-classes-pojo-identifier" revision="2">
|
|
<title>identifier 프로퍼티를 제공하라(옵션)</title>
|
|
|
|
<para>
|
|
<literal>Cat</literal>은 <literal>id</literal>로 명명된 하나의 프로퍼티를 갖는다. 이 프로퍼티는
|
|
데이터베이스 테이블의 프라이머리 키 컬럼으로 매핑된다. 이 프로퍼티는 어떤 것으로 명명될 수도 있고, 그것의 타입은
|
|
임의의 원시 타입, 원시 "wrapper" 타입, <literal>java.lang.String</literal> 또는 <literal>java.util.Date</literal>일
|
|
수 있다. (만일 당신의 리거시 데이터베이스 테이블이 composite 키들을 갖고 있다면, 당신은 이들 타입들을 가진
|
|
사용자 정의 클래스를 사용할 수도 있다 - 나중에 composite 식별자들에 대한 절을 보라)
|
|
</para>
|
|
|
|
<para>
|
|
identifier 프로퍼티는 엄격하게 옵션이다. 당신은 그것을 생략할 수도 있고, Hibernate로 하여금 내부적으로
|
|
객체 식별자들을 추적하도록 할 수 있다. 하지만 우리는 이것을 권장하지 않는다.
|
|
</para>
|
|
|
|
<para>
|
|
사실, 어떤 기능은 identifier 프로퍼티를 선언하는 클래스들에 대해서만 이용 가능하다:
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
detached 객체들에 대한 Transitive reattachment(cascade update 또는 cascade merge)
|
|
- <xref linkend="objectstate-transitive"/>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>Session.saveOrUpdate()</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>Session.merge()</literal>
|
|
</para>
|
|
<para>
|
|
를 보라
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
우리는 당신이 영속 클래스들에 대해 일관되게 명명된 identifier 프로퍼티들을 선언할 것을 권장한다. 게다가 우리는
|
|
당신이 nullable 타입(예를 들어 non-primitive)을 사용할 것을 권장한다.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="persistent-classes-pojo-final">
|
|
<title>final이 아닌 클래스들을 선호하라(옵션)</title>
|
|
<para>
|
|
Hibernate의 중심 특징인, 프락시(<emphasis>proxies</emphasis>)들은 final이 아닌 영속 클래스들 또는 모두
|
|
public 메소드들로 선언된 인터페이스의 구현인 영속 클래스들에 의존한다.
|
|
</para>
|
|
<para>
|
|
당신은 Hibernate로 인터페이스를 구현하지 않은 <literal>final</literal> 클래스들을 영속화 시킬 수 있지만
|
|
당신은 lazy 연관 페칭(lazy association fetching)에 대해 프락시들을 사용할 수 없을 것이다 -그것은 퍼포먼스
|
|
튜닝을 위한 당신의 옵션들을 제한시킬 것이다.
|
|
</para>
|
|
<para>
|
|
당신은 또한 non-final 클래스들 상에 <literal>public final</literal> 메소드들을 선언하는 것을 피해야 한다.
|
|
만일 당신이 <literal>public final</literal> 메소드를 가진 클래스를 사용하고자 원할 경우, 당신은
|
|
<literal>lazy="false"</literal>를 설정함으로써 명시적으로 프락싱을 사용 불가능하도록 해야 한다.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="persistent-classes-pojo-accessors" revision="2">
|
|
<title>영속 필드들을 위한 accessor들과 mutator들을 선언하라(옵션)</title>
|
|
|
|
<para>
|
|
<literal>Cat</literal>은 그것의 모든 영속 필드들에 대해 accessor 메소드들을 선언한다. 많은 다른 ORM 도구들은
|
|
인스턴스 변수들을 직접 영속화 시킨다. 우리는 관계형 스키마와 클래스의 내부적인 데이터 구조들 사이에 간접적인 수단을
|
|
제공하는 것이 더 좋다고 믿고 있다. 디폴트로 Hibernate는 자바빈즈 스타일 프로퍼티들을 영속화 시키고, <literal>getFoo</literal>,
|
|
<literal>isFoo</literal>와 <literal>setFoo</literal> 형식의 메소드 이름들을 인지한다. 당신은 진정으로
|
|
특정 프로퍼티에 대한 직접적인 필드 접근으로 전환할 수도 있다.
|
|
</para>
|
|
|
|
<para>
|
|
프로퍼티들은 public으로 선언될 필요가 <emphasis>없다</emphasis> - Hibernate는 디폴트로
|
|
<literal>protected</literal> get/set 쌍 또는 <literal>private</literal> get/set
|
|
쌍을 가진 프로퍼티를 영속화 시킬 수 있다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="persistent-classes-inheritance">
|
|
<title>상속 구현하기</title>
|
|
|
|
<para>
|
|
서브클래스는 또한 첫 번째 규칙들과 두 번째 규칙들을 주시해야 한다. 그것은 슈퍼클래스 <literal>Cat</literal>으로부터
|
|
그것의 identifier 프로퍼티를 상속받는다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package eg;
|
|
|
|
public class DomesticCat extends Cat {
|
|
private String name;
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
protected void setName(String name) {
|
|
this.name=name;
|
|
}
|
|
}]]></programlisting>
|
|
</sect1>
|
|
|
|
<sect1 id="persistent-classes-equalshashcode" revision="1">
|
|
<title><literal>equals()</literal>와 <literal>hashCode()</literal> 구현하기</title>
|
|
|
|
<para>
|
|
만일 당신이 다음의 경우라면, 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal>
|
|
메소드들을 오버라이드 시켜야 한다.
|
|
</para>
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
하나의 <literal>Set</literal> 속에 영속 클래스들의 인스턴스들을 집어넣고자 의도하고
|
|
(many-valued 연관들에 대해 권장되는 방법)
|
|
<emphasis>그리고</emphasis>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
detached 인스턴스들의 reattachment(재첨부)를 사용하고자 의도하는
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다.
|
|
따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게
|
|
만들고자 원할 경우, 우리는 <literal>equals()</literal>와 <literal>hashCode()</literal>를 구현해야 한다.
|
|
</para>
|
|
|
|
<para>
|
|
가장 명백한 방법은 두 객체들의 identifier 값을 비교함으로써 <literal>equals()</literal>/<literal>hashCode()</literal>를
|
|
구현하는 것이다. 만일 그 값이 동일하다면, 둘다 동일한 데이터베이스 행이어야 하고, 그러므로 그것들은 같다(둘다 하나의
|
|
<literal>Set</literal>에 추가되는 경우에, 우리는 <literal>Set</literal> 속에서 하나의 요소만을 갖게 될 것이다).
|
|
불행하게도, 우리는 생성되는 식별자들을 갖는 그 접근법을 사용할 수 없다! Hibernate는 오직 식별자 값들을 영속화 되는 객체들에
|
|
할당할 것이고, 새로이 생성된 인스턴스는 임의의 identifier 값을 갖지 않을 것이다! 만일 인스턴스가 저장되지 않고 현재 하나의
|
|
<literal>Set</literal> 속에 있을 경우에, 그것을 저장하는것은 하나의 식별자 값을 그 객체에게 할당할 것이다. 만일
|
|
<literal>equals()</literal>와 <literal>hashCode()</literal>가 그 식별자 값에 기초할 경우, hash 코드는
|
|
<literal>Set</literal>의 계약을 파기하여 변경될 것이다. 이 문제에 대한 전체 논의에 대해서는 Hibernate 웹 사이트를 보라.
|
|
이것은 Hibernate 쟁점이 아닌, 객체 identity와 equality에 관한 통상의 자바 의미론임을 노트하라.
|
|
</para>
|
|
|
|
<para>
|
|
우리는 <emphasis>Business key equality</emphasis>를 사용하여 <literal>equals()</literal>와 <literal>hashCode()</literal>를
|
|
구현할 것 권장한다. Business key equality는 <literal>equals()</literal> 메소드가 비지니스 키, 즉 실세계에서 우리의 인스턴스를
|
|
식별하게 될 키(<emphasis>natural</emphasis> 후보 키)를 형성하는 프로퍼티들만을 비교한다는 점을 의미한다 :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[public class Cat {
|
|
|
|
...
|
|
public boolean equals(Object other) {
|
|
if (this == other) return true;
|
|
if ( !(other instanceof Cat) ) return false;
|
|
|
|
final Cat cat = (Cat) other;
|
|
|
|
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
|
|
if ( !cat.getMother().equals( getMother() ) ) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public int hashCode() {
|
|
int result;
|
|
result = getMother().hashCode();
|
|
result = 29 * result + getLitterId();
|
|
return result;
|
|
}
|
|
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
하나의 비지니스 키는 데이터베이스 프라이머리 키 후보 만큼 견고하지 않아야 한다(<xref linkend="transactions-basics-identity"/>를 보라).
|
|
대개 변경할 수 없는 프로퍼티 또는 유일한(unique) 프로퍼티는 대개 비지니스 키에 대한 좋은 후보들이다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="persistent-classes-dynamicmodels">
|
|
<title>동적인 모형들</title>
|
|
|
|
<para>
|
|
<emphasis>다음 특징들은 현재 실험적으로 고려되고 있으며 장래에는 변경될 수 있음을 노트하라.</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
영속 엔티티들은 반드시 실행시에 POJO 클래스들로 또는 자바빈즈 객체들로 표현되어야할 필요는 없다. Hibernate는
|
|
또한 (실행 시에 <literal>Map</literal>들을 가진 <literal>Map</literal>들을 사용하여) 동적인 모형들을 지원하고
|
|
DOM4J 트리들로서 엔티티들에 대한 표현을 지원한다. 이 접근법으로, 당신은 영속 클래스들을 작성하지 않고, 오직 매핑 파일들
|
|
만을 작성한다.
|
|
</para>
|
|
|
|
<para>
|
|
디폴트로, Hibernate는 통산의 POJO 모드로 동작한다. 당신은 <literal>default_entity_mode</literal> 구성 옵션을
|
|
사용하여 특별한 <literal>SessionFactory</literal>에 대해 디폴트 엔티티 표현 모드를 설정할 수 있다
|
|
(<xref linkend="configuration-optional-properties"/>을 보라).
|
|
</para>
|
|
|
|
<para>
|
|
다음 예제들은<literal>Map</literal>들을 사용하는 표현을 설명한다. 먼저 매핑 파일에서, <literal>entity-name</literal>은
|
|
클래스 이름 대신에(또는 클래스 이름에 덧붙여) 선언되어야 한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class entity-name="Customer">
|
|
|
|
<id name="id"
|
|
type="long"
|
|
column="ID">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
|
|
<property name="name"
|
|
column="NAME"
|
|
type="string"/>
|
|
|
|
<property name="address"
|
|
column="ADDRESS"
|
|
type="string"/>
|
|
|
|
<many-to-one name="organization"
|
|
column="ORGANIZATION_ID"
|
|
class="Organization"/>
|
|
|
|
<bag name="orders"
|
|
inverse="true"
|
|
lazy="false"
|
|
cascade="all">
|
|
<key column="CUSTOMER_ID"/>
|
|
<one-to-many class="Order"/>
|
|
</bag>
|
|
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
심지어 비록 연관들이 대상(target) 클래스 이름들을 사용하여 선언될지라도, 연관들의 대상(target) 타입은 또한 POJO가 아닌
|
|
동적인 엔티티일 수 있음을 노트하라.
|
|
</para>
|
|
|
|
<para>
|
|
<literal>SessionFactory</literal>에 대한 디폴트 엔티티 모드를 <literal>dynamic-map</literal>으로 설정한 후에,
|
|
우리는 <literal>Map</literal>들을 가진 <literal>Map</literal>들에 대해 실행 시에 작업할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Session s = openSession();
|
|
Transaction tx = s.beginTransaction();
|
|
Session s = openSession();
|
|
|
|
// Create a customer
|
|
Map david = new HashMap();
|
|
david.put("name", "David");
|
|
|
|
// Create an organization
|
|
Map foobar = new HashMap();
|
|
foobar.put("name", "Foobar Inc.");
|
|
|
|
// Link both
|
|
david.put("organization", foobar);
|
|
|
|
// Save both
|
|
s.save("Customer", david);
|
|
s.save("Organization", foobar);
|
|
|
|
tx.commit();
|
|
s.close();]]></programlisting>
|
|
|
|
<para>
|
|
dynamic 매핑의 장점들은 엔티티 클래스 구현에 대한 필요 없이도 프로토타이핑을 위한 빠른 전환 시간이다. 하지만 당신은
|
|
컴파일 시 타입 체킹을 잃고 실행 시에 많은 예외상황들을 다루게 될 것이다. Hibernate 매핑 덕분에,
|
|
나중에 고유한 도메인 모형 구현을 상단에 추가하는 것이 허용되어서, 데이터베이스 스키마가 쉽게 정규화 되고 소리가 울려 퍼질 수 있다.
|
|
</para>
|
|
|
|
<para>
|
|
엔티티 표현 모드들은 또한 하나의 단위 <literal>Session</literal> 기준에 대해 설정될 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
|
|
|
|
// Create a customer
|
|
Map david = new HashMap();
|
|
david.put("name", "David");
|
|
dynamicSession.save("Customer", david);
|
|
...
|
|
dynamicSession.flush();
|
|
dynamicSession.close()
|
|
...
|
|
// Continue on pojoSession
|
|
]]></programlisting>
|
|
|
|
|
|
<para>
|
|
<literal>EntityMode</literal>를 사용하는 <literal>getSession()</literal>에 대한 호출은
|
|
<literal>SessionFactory</literal>가 아닌, <literal>Session</literal> API에 대한 것임을 노트하길 바란다.
|
|
그 방법으로, 새로운 <literal>Session</literal>은 기본 JDBC 커넥션, 트랜잭션, 그리고 다른 컨텍스트 정보를 공유한다.
|
|
이것은 당신이 두 번째 <literal>Session</literal> 상에서 <literal>flush()</literal>와 <literal>close()</literal>를
|
|
호출하지 말아야 하고, 또한 트랜잭션 및 커넥션 핸들링을 주된 작업 단위에게 맡긴다는 점을 의미한다.
|
|
</para>
|
|
|
|
<para>
|
|
XML 표현 가용성들에 대한 추가 정보는 <xref linkend="xml"/>에서 찾을 수 있다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="persistent-classes-tuplizers" revision="1">
|
|
<title>Tuplizer들</title>
|
|
|
|
<para>
|
|
<literal>org.hibernate.tuple.Tuplizer</literal>, 그리고 그것의 서브-인터페이스들은 데이터의 조각에 대한
|
|
특별한 표현의 <literal>org.hibernate.EntityMode</literal>가 주어지면 그 표현을 관리하는 책임이 있다. 만일
|
|
주어진 데이터 조각이 하나의 데이터 구조로 간주될 경우, 그때 하나의 tuplizer는 그런 데이터 구조를 생성시키는 방법과
|
|
그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다.
|
|
예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된
|
|
프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다.
|
|
<literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 인터페이스와
|
|
<literal>org.hibernate.tuple.component.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의
|
|
Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할
|
|
책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다.
|
|
</para>
|
|
|
|
<para>
|
|
사용자들은 또한 그들 자신의 tuplizer들을 플러그 시킬 수 있다. 아마 당신은 dynamic-map entity-mode 동안에 사용되는
|
|
<literal>java.util.HashMap</literal> 대신에 하나의 <literal>java.util.Map</literal> 구현을 필요로 한다;
|
|
또는 아마 당신은 디폴트로 사용되는 방도 보다는 하나의 다른 다른 프릭시 산출 방도를 필요로 한다. 둘다 하나의 맞춤형 tuplizer를
|
|
정의함으로써 성취될 것이다. Tuplizer들 정의들은 그것들이 관리할 수단인 엔티티 매핑 또는 컴포넌트 매핑에 첨부된다. 우리의
|
|
고객 엔티티에 대한 예제로 되돌아가면:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
<class entity-name="Customer">
|
|
<!--
|
|
Override the dynamic-map entity-mode
|
|
tuplizer for the customer entity
|
|
-->
|
|
<tuplizer entity-mode="dynamic-map"
|
|
class="CustomMapTuplizerImpl"/>
|
|
|
|
<id name="id" type="long" column="ID">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
|
|
<!-- other properties -->
|
|
...
|
|
</class>
|
|
</hibernate-mapping>
|
|
|
|
|
|
public class CustomMapTuplizerImpl
|
|
extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
|
|
// override the buildInstantiator() method to plug in our custom map...
|
|
protected final Instantiator buildInstantiator(
|
|
org.hibernate.mapping.PersistentClass mappingInfo) {
|
|
return new CustomMapInstantiator( mappingInfo );
|
|
}
|
|
|
|
private static final class CustomMapInstantiator
|
|
extends org.hibernate.tuple.DynamicMapInstantitor {
|
|
// override the generateMap() method to return our custom map...
|
|
protected final Map generateMap() {
|
|
return new CustomMap();
|
|
}
|
|
}
|
|
}]]></programlisting>
|
|
|
|
|
|
</sect1>
|
|
|
|
<para>
|
|
TODO: property 패키지와 proxy 패키지 내에 user-extension 프레임웍을 문서화 할 것.
|
|
</para>
|
|
|
|
</chapter>
|
|
|