 |
|
데이터 모델 사용자 정의하기
이 튜토리얼의 앞에서 설명한 예제에서는 간단한 CodeGen 사용자
정의를 살펴보았으며, CodeGen이 기본 설정을 사용하여 HR-XML TimeCard
스키마를 처리하는 방법에 대해서도 설명했다. 이제 몇 가지 강력한 사용자 정의를 살펴볼 것이다.
데이터 모델 사용자 정의하기
CodeGen에서 기본 설정을 사용하여 생성된 데이터 모델 코드에는 몇 가지 단점이 있다. 그 중 하나는
스키마 유형 이름이 모두 Type으로 끝나기 때문에 해당하는 생성된
클래스 이름이 필요 이상으로 길어질 수 있다는 것이다. 스키마 네임스페이스 org.hrxml.ns에서
생성된 패키지 이름은 합리적이긴 하지만 구체적으로 TimeCard 문서를
위한 데이터 모델임을 나타내는 패키지 이름을 사용하는 것이 더 효과적이다.
Listing 11에서는 생성된 데이터 모델 클래스의 또 다른 약점을 보여 준다. 여기에서는
java.math.BigInteger를 사용해서 xs:integer
유형을 나타낸다. 이 유형이 표준 Java 클래스를 사용하여 xs:integer를 가장
정확하게 표현할 수 있는 유형이기는 하지만 BigInteger는 간단한
int 프리미티브 또는 java.lang.Integer 오브젝트
유형에 비해 사용하기가 까다롭다. 아쉽게도, xs:int 유형이 더 적합하다
하더라도 xs:integer 유형을 사용하여 스키마를 작성하는 경우가 종종 있기
때문에 생성된 코드에서 BigInteger 값을 처리해야 한다. GenderCode에
허용되는 실제 값이 모두 한 자리 숫자인(listing 하단의 원래 스키마 부분 참조) 이 예제가 이에 해당한다.
Listing 11. xs:integer 생성 예제
/**
* Schema fragment(s) for this class:
* <pre>
* <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:integer"
* name="GenderCode"/>
* </pre>
*/
public class GenderCode
{
private BigInteger genderCode;
/**
* Get the 'GenderCode' element value.
*
* @return value
*/
public BigInteger getGenderCode() {
return genderCode;
}
/**
* Set the 'GenderCode' element value.
*
* @param genderCode
*/
public void setGenderCode(BigInteger genderCode) {
this.genderCode = genderCode;
}
}
<xsd:simpleType name="GenderCodeType">
<xsd:annotation>
<xsd:documentation>Must conform to ISO 5218 - Representation of Human Sexes
(0 - Not Known; 1 - Male; 2 - Female; 9 - Not specified)</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer">
<xsd:pattern value="[0129]"/>
</xsd:restriction>
</xsd:simpleType>
|
Listing 12에서는 생성된 데이터 모델의 이러한 특성을 개선하기 위한 사용자 정의를 보여
준다. package="org.hrxml.timecard" 속성은 생성된 클래스에 사용할
Java 패키지를 지정한다. type-substitutions="xs:integer xs:int"
속성은 CodeGen에서 적용할 스키마 유형 대체를 정의한다. 이 경우에는 xs:integer가 스키마에서
참조될 때마다 xs:int 유형을 사용한다. 목록에 유형 이름을 추가하여 여러 쌍의 대체를 정의할
수 있다. 이 경우 공백을 구분 기호로 사용하여 쌍과 쌍을 구분하고 각 쌍에 포함된 각각의 유형
이름을 구분해야 한다.
중첩된 name-converter 요소는 Java 이름으로 변환할 XML
이름에 대한 처리 방법을 구성한다. 이 예제의 경우, strip-suffixes="Type"
속성은 CodeGen이 이름 끝에 있는 Type을 항상 제거하도록 한다. 이 속성을 사용하여 제거할 여러 대체 항목을 공백으로 구분된 목록으로
제공할 수 있다. 또한 strip-prefixes 속성과 여러 다른 형식의
사용자 정의를 사용하여 이름 앞쪽에 있는 불필요한 텍스트를 제거할 수도 있다. 이름 변환 중에
실제로 특별한 작업을 수행하려는 경우 기본 이름 변환 클래스를 사용자의 고유한 구현으로 바꿀
수도 있다. 이러한 name-converter 옵션에 대한 자세한 설명은 JiBX CodeGen
문서에서 볼 수 있다.
마지막으로, 중첩된 class-decorator 요소는 코드 생성
시퀀스에 데코레이터를 추가한다. 이 예제에서는 CodeGen 배포판의 일부로 제공되는 사전 정의된
데코레이터를 사용하며, 이 데코레이터는 컬렉션 값에 유용하게 사용할 수 있는 지원 메소드를
추가한다. CodeGen은 구성된 코드 생성 데코레이터를 차례대로 호출하여 데이터 모델 클래스에
대한 소스 코드를 생성하며, 이러한 데코레이터를 통해 CodeGen에서 생성된 필드, 메소드 및 클래스
구문을 수정하거나 추가할 수도 있다. 이러한 각 구문은 Eclipse AST(Abstract Syntax Tree)
구현을 통해 데코레이터에게 AST 구성 요소로 전달된다. 제공된 데코레이터(여기에서 메소드를
추가하는 데 사용한 org.jibx.schema.codegen.extend.CollectionMethodsDecorator
데코레이터 및 java.io.Serializable 인터페이스와 버전 ID(선택적)를
데이터 모델 클래스에 추가하는 데 사용된 org.jibx.schema.codegen.extend.SerializableDecorator
포함)는 Eclipse AST를 사용하여 CodeGen을 확장하는 예제를 제공한다. 따라서 이러한 클래스의
코드를 기반으로 사용자 고유의 데코레이터를 쉽게 작성할 수 있다.
Listing 12. TimeCard 사용자 정의 예제
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
type-substitutions="xs:integer xs:int">
<name-converter strip-suffixes="Type"/>
<class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
</schema-set> |
custgen1 Ant 대상을 사용하여 Listing 12 사용자 정의를 실행하거나
custom1 대상을 사용하여 생성, 컴파일, 바인딩 및 테스트를 차례대로
실행할 수 있다. Listing 13에서는 사용자 정의의 적용 결과를 보여 준다. TimeCardType
클래스 이름이 TimeCard로 변경되었고, List
get 및 set 메소드 외에도 size, add, 인덱싱된 get 및 clear 메소드가 추가되었다. GenderCode
클래스의 경우 BigInteger 참조가 단순 int 프리미티브 유형으로 바뀌었다.
Listing 13. 사용자 정의된 데이터 모델
/**
* Schema fragment(s) for this class:
* <pre>
* ...
* </pre>
*/
public class TimeCard
{
...
private List<ReportedTime> reportedTimeList = new ArrayList<ReportedTime>();
...
/**
* Get the list of 'ReportedTime' element items.
*
* @return list
*/
public List<ReportedTime> getReportedTimes() {
return reportedTimeList;
}
/**
* Set the list of 'ReportedTime' element items.
*
* @param list
*/
public void setReportedTimes(List<ReportedTime> list) {
reportedTimeList = list;
}
/**
* Get the number of 'ReportedTime' element items.
* @return count
*/
public int sizeReportedTime() {
return reportedTimeList.size();
}
/**
* Add a 'ReportedTime' element item.
* @param item
*/
public void addReportedTime(ReportedTime item) {
reportedTimeList.add(item);
}
/**
* Get 'ReportedTime' element item by position.
* @return item
* @param index
*/
public ReportedTime getReportedTime(int index) {
return reportedTimeList.get(index);
}
/**
* Remove all 'ReportedTime' element items.
*/
public void clearReportedTime() {
reportedTimeList.clear();
}
...
}
/**
* Schema fragment(s) for this class:
* <pre>
* <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int"
* name="GenderCode"/>
* </pre>
*/
public class GenderCode
{
private int genderCode;
/**
* Get the 'GenderCode' element value.
*
* @return value
*/
public int getGenderCode() {
return genderCode;
}
/**
* Set the 'GenderCode' element value.
*
* @param genderCode
*/
public void setGenderCode(int genderCode) {
this.genderCode = genderCode;
}
} |
 |

|
사용하지 않는 정의 제거
첫 번째 사용자 정의 예제에서는 간단한 원래 스키마를 사용하여 생성된 데이터 모델에 포함된
유형 정의를 제어하는 방법을 살펴보았다. 이 예제에서는 generate-all="false"를
사용하여 모든 전역 정의가 생성되지 않도록 설정하고 includes 목록을
사용하여 특정 정의를 생성하도록 설정했다. Listing 14에서는 이러한 속성이 추가된 TimeCard
스키마에 대한 수정된 사용자 정의를 보여 준다. 이 경우에는 TimeCard
표현에 사용되는 모든 항목과 함께 TimeCard 요소가 생성된 데이터 모델에
포함된다.
Listing 14. TimeCard 구성 요소만을 사용한 사용자 정의
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
type-substitutions="xs:integer xs:int" generate-all="false">
<name-converter strip-suffixes="Type"/>
<class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
<schema name="TimeCard.xsd" includes="TimeCard"/>
</schema-set> |
CodeGen에서 custgen2 Ant 대상을 사용하여 이 사용자 정의를 실행하거나
custom2 대상을 사용하여 생성, 컴파일, 바인딩 및 테스트를 차례대로
실행할 수 있다. 이 변경으로 인해 데이터 모델의 최상위 레벨 클래스 수가 15개에서 10개로 줄어들면서
데이터 모델이 단순해진다.
|