JAXB(Java Architecture for XML Binding)는 자바 프로그래밍 언어 애플리케이션에서 XML 컨텐츠의 사용을 간소화해주는 기술로서, XML 문서의 XSD 스키마를 바탕으로 하여 XML 문서와 JavaBeans 기술 컴포넌트 간의 바인딩을 지정함으로써 작업을 수행한다. 지난 J2EE 테크팁에서는 JAXB를 이용한 XML 직렬화와 JAXB에서 RelaxNG 이용하기를 다룬 바 있으며, 두 팁 모두 Java WSDP(Java Web Services Developer Pack) 1.6 패키지에 포함되어 있는 JAXB 1.0이 사용되었다.
JAXB 2.0, JSR 222에는 JAXB 1.0에서 개선된 중요한 항목이 다수 포함되어 있는데, 그중 일부를 소개하면 다음과 같다.
- 모든 W3C XML 스키마 기능에 대한 지원. JAXB 1.0에서는 W3C XML 스키마의 일부 기능에 대해 바인딩이 지정되지 않았다. 이는 FCS 릴리즈에서 완벽하게 지원될 예정이지만, 현재의 얼리 액세스 버전에서는 아직 지원 수준이 미흡한 상태이다.
- Java-to-XML 바인딩 지원, 그리고 이 바인딩을 제어하기 위한
javax.xml.bind.annotation패키지 추가. JAXB 1.0에서는 XML Schema-to-Java의 매핑은 지정되었지만 Java-to-XML Schema의 매핑은 지정되지 않았다.
- 생성되는 스키마 파생 클래스의 수 대폭 감소.
- JAXP 1.3 검증 API를 통한 추가 검증 기능 제공.
- 더 작아진 런타임 라이브러리.
본 팁에서는 이러한 개선사항 중 다음의 두 가지를 예시한다 - JAXP 검증 API를 이용한 검증(마샬링/언마샬링의 일부로서)과 Java-to-Schema 바인딩.
본 팁과 관련한 코드는 다운로드 아카이브에서 찾을 수 있으며, 예제를 실행하려면 JAXB 2.0 참조 구현의 최신 얼리 액세스 3 버전이 필요하다. JAXB 2.0 참조 구현의 얼리 액세스 3 버전은 Java WSDP 2.0 패키지에도 포함되어 있다.
JAXP 1.3 검증 스키마를 이용한 언마샬링/마샬링
JAXB 2.0에서 개선된 사항 중 하나가 바로 JAXP 1.3 검증 API를 이용한 추가 검증 기능이다. 그럼, 먼저 JAXP 1.3 검증 스키마를 이용한 JAXB 2.0 언마샬링/먀샬링 기능을 살펴보록 한다. 자바 애플리케이션은 JAXB를 이용하여 XML 인스턴스 문서를 자바 컨텐트 객체로 언마샬링 할 수 있으며, 옵션으로 자바 컨텐츠 객체를 생성하기 전에 소스 XML 문서를 검증할 수 있다. 자바 애플리케이션은 또한 JAXB를 이용하여 자바 컨텐츠 객체를 XML 인스턴스 문서로 마샬링 할 수 있다.
XML 문서를 언마샬링 하려면 먼저 XML 문서의 스키마를 해당 스키마를 나타내는 일련의 자바 인터페이스 및 클래스로 바인드해야 하고, 그런 다음 인터페이스와 클래스를 컴파일한다. 본 팁의 예제에서는 구입 주문서 스키마 po.xsd를 이용하도록 한다. 이는 Java WSDP 1.6 패키지에 포함된 JAXB 예제에서 사용되는 것과 동일한 스키마이며, JAXB 예제는 Java Web Services Developer Pack 1.6 튜토리얼에 설명되어 있다. po.xsd 스키마 검토 시, quantity 엘리먼트와 partNum 속성에 지정된 제한사항에 특히 유의할 것.
<xsd:element name="quantity">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:maxExclusive value="100"/>
</xsd:restriction>
<xsd:attribute name="partNum" type="SKU"
use="required"/>
수량은 100을 초과할 수 없으며 부품번호에는 반드시 SKU 타입이 기재되어야 한다.
JAXB 2.0의 스키마도 JAXB 1.0의 경우와 마찬가지로 XML 바인딩 컴파일러(xjc)를 이용하여 바인드하고, 그런 다음 javac 명령어를 이용하여 생성된 인터페이스와 클래스를 컴파일한다. 예제 아카이브의 경우, 바인딩 및 컴파일 단계는 빌드 파일인 build.xml 에서 ant 태스크로 제공된다.
바인딩 및 컴파일을 완료한 후에는 XML 문서를 언마샬링 할 수 있다. 본 팁에서 사용하는 XML 문서 po.xml은 po.xsd 스키마에 지정된 제한사항을 위반하는 정보가 포함된 구입주문서이고, 특히 구입주문서 내의 특정 항목은 100을 초과하는 수량과 SKU 타입과 일치하지 않는 partNum 속성을 지정하고 있다.
<item partNum="002" >
<productName>Reliving the Ordeal</productName>
<quantity>150</quantity>
<USPrice>11.99</USPrice>
</item>
JAXB 2.0의 언마샬링은 JAXB 1.0의 언마샬링과 거의 동일하다. 먼저 JAXB API에 대한 엔트리 포인트를 제공하는 JAXBContext 객체를 생성한 다음, 언마샬링 프로세스를 제어하는 Unmarshaller 객체를 생성한다.
JAXBContext jc = JAXBContext.newInstance( "techtip" ); Umarshaller u = jc.createUnmarshaller();
언마샬링 프로세스에서 JAXB 2.0이 JAXB 1.0과 다른 점이 바로 검증 부분인데, JAXB 1.0에서는 다음을 지정함으로써 언마샬링 프로세스의 일부로서 소스 데이터를 관련 스키마와 대조하여 검증할 수 있다.
unmarshaller.setValidating(true);
JAXB 2.0에서는 JAXP 1.3 스키마 검증 프레임워크를 이용하여 검증 기능을 보다 향상시켰다. 이처럼 강화된 레벨의 검증을 이용하려면 먼저 W3C XML Schema 1.0 언어를 위한 SchemaFactory 인스턴스를 생성한다.
SchemaFactory sf = SchemaFactory.newInstance(
javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
SchemaFactory 인스턴스는 새로운 JAXP 1.3 Schema 객체를 생성하는 데 사용된다.
Schema schema = sf.newSchema(new File("po.xsd"));
그런 다음 setSchema 메소드를 이용하여 이어지는 언마샬링 동작을 검증하는 데 사용할 JAXP 1.3 Schema 객체(이 경우에는 po.xsd)를 식별한다. 한편, 이 메소드에 null을 패스하면 검증 기능은 디스에이블("사용하지 않음") 상태가 된다.
u.setSchema(schema);
애플리케이션은 기본값 이벤트 핸들러를 오버라이드하여 검증 오류 처리를 커스터마이즈할 수 있는 옵션을 가지는데, 이 경우에는 메소드 콜 setEventHandler(ValidationEventHandler)가 사용된다.
JAXB 1.0으로 언마샬링을 하는 이전의 접근법(소위 '구조적 언마샬링')은 유효하지 않은 XML 컨텐츠에 대해 더 엄격한 편이다. JAXB 1.0은 복구 불가능한 구조적 불일치가 탐지되면 언마샬링 프로세스를 취소하고 UnmarshalException을 throw한다. 실례로, 예상치 않은 엘리먼트나 속성에 마주치면 언마샬링을 중단할 수 있다.
이와 달리 JAXB 2.0은 보다 유연한 언마샬링을 허용하는데, 이는 부적절한 XML 컨텐츠의 언마샬링 과정에서의 예측 가능성을 더욱 높여준다. JAXB 2.0의 경우, 컨텐츠 모델 내의 엘리먼트 위치를 기준으로 하여 엄격하게 적용시키기 보다는 엘리먼트 이름 별로 xml을 언마샬링한다.
각자의 커스텀 이벤트 핸들러를 지정하는 방법은 다음과 같다.
u.setEventHandler(new DefaultValidationEventHandler());
커스텀 검증 이벤트 핸들러는 반드시 ValidationEventHandler 인터페이스와 handleEvent 메소드를 구현해야 한다. JAXB Provider가 경고 또는 오류를 처리한 후에 현재의 언마샬링, 검증, 또는 마샬링 연산을 계속하려고 시도할 경우에는 불(boolean) 리턴 값이 true로 설정되어야 한다. 프로바이더가 적절한 UnmarshalException, ValidationException, 또는 MarshalException으로 현재의 연산을 종료할 경우에는 리턴 값이 false로 설정되어야 한다. JAXB 2.0의 기본값 ValidationHandler는 항상 true를 리턴한다는 점에 유의할 것(단, handleEvent가 오버라이드되지 않아야 함). 다음은 커스텀 이벤트 핸들러의 예제이다.
public class MyValidationEventHandler implements
ValidationEventHandler{
public boolean handleEvent(ValidationEvent ve) {
if (ve.getSeverity()==ve.FATAL_ERROR ||
ve .getSeverity()==ve.ERROR){
ValidationEventLocator locator = ve.getLocator();
//print message from valdation event
System.out.println("Message is " + ve.getMessage());
//output line and column number
System.out.println("Column is " +
locator.getColumnNumber() +
" at line number " + locator.getLineNumber());
}
return true;
}
}
JAXB 스펙은 오류 발생 시 모든 프로바이더 구현이 검증 오류를 보고할 것을 요구하고 있지만, 구현이 데이터 프로세싱을 중단할 필요까지는 없다. 한편, XML 문서가 유효하지 않더라도 JAXB 구현은 XML 문서를 성공적으로 언마샬링 할 수 있다.
po.xml이 언마샬링된 후에는 마샬링된 객체를 다른 자바 객체와 마찬가지로 처리할 수 있다. 예를 들어, shipTo 주소를 디스플레이하려면 다음 절차를 따르도록 한다.
JAXBElement<?> poElement =
JAXBElement<?>)u.unmarshal(
new FileInputStream( "po.xml" ) );
PurchaseOrderType po = (
PurchaseOrderType)poElement.getValue();
USAddress address = po.getShipTo();
컨텐츠를 다시 XML 파일로 마샬링하려면 JAXB 1.0과 동일한 단계를 거치도록 한다. (앞서 언마샬링 과정에서 본 것처럼) JAXBContext 객체를 생성한 후에는, 마샬링 프로세스를 제어하는 Marshaller 객체를 생성한다. 예를 들어, 다음의 코드 단편은 Marshaller를 생성하여 컨텐츠를 incorrectpo.xml이라는 이름의 파일로 마샬링하는 경우를 보여주고 있다.
Marshaller m = jc.createMarshaller();
m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE );
OutputStream os = new FileOutputStream(
"incorrectpo.xml" );
m.marshal(po, os);
JAXB.FORMATTED.OUTPUT 속성은 Marshaller가 출력된 XML 데이터를 줄바꿈과 들여쓰기로 포맷할 것인지 여부를 제어한다.
본 팁의 예제 코드에는 표시되어 있지 않지만, JAXB 2.0은 마샬링 시에(언마샬링 시에도) 검증을 지원한다. 한편, JAXB 1.0의 경우에는 언마샬링 시에만 검증을 규정하고, JAXB 컨텐츠 트리의 온디맨드 검증을 지원하는데, 마샬링 시의 검증은 웹 서비스 때문에 추가된 것이다. 웹 서비스 프로세싱 모델은 데이터를 읽어들일 때는 어느 정도 느슨하고 반대로 데이터를 기록할 때는 엄격해야 한다. 이 모델에 부합하도록, JAXB 2.0은 사용자가 xml 문서를 JAXB 양식으로 수정할 경우 문서가 무효화되지 않도록 하기 위해 마샬링 시의 검증을 추가하였다.
Java-to-Schema 바인딩을 이용하여 자바 클래스에서 XML 생성하기
앞서 얘기한 것처럼, JAXB 1.0의 경우 XML Schema-to-Java 매핑은 지정되었지만 Java-to-XML Schema의 매핑은 지정되지 않았다. 한편, JAXB 2.0은 Java-to-XML Schema의 매핑을 지정함으로써 이 작업을 완수함과 동시에 "A Metadata Facility for the Java Programming Language", JSR 175에 명시된 주석을 이용하여 이 바인딩을 제어한다.
본 팁에서는 JAXB 2.0을 이용하여 기존의 자바 클래스로부터 XML 파일을 생성한 다음 생성된 XML 파일의 내용을 콘솔로 프린트하는 방법을 예시해보도록 한다. 사용되는 두 가지 클래스는 Scientist와 Person이며, 여기서 Person 객체는 Scientist 객체에 인캡슐레이트된다.
클래스는 XML Schema 컴플렉스 타입 또는 XML Schema 심플 타입으로 매핑되는데, XML Schema 타입은 클래스에 포함된 JavaBean 속성 및 필드의 매핑을 기초로 하여 파생된다. JAXB 2.0에서 주석은 Java-to-Schema 바인딩 프레임워크에 대해 자바 클래스를 취급하는 방법을 지시하기 위해 사용된다. 톱 레벨 값 클래스에 대해서는 주석 @Xmltype을 이용하여 컴플렉스 스키마 타입으로 매핑한다:
@XmlType
public class Person {
private String name;
private int age;
.....
톱 레벨 클래스에 @XmlRootElement 주석이 첨부될 경우, 클래스 값은 XML 문서 내의 XML 루트 엘리먼트로 표시된다:
@XmlRootElement
public class Scientist {
private Person person;
private String researchInstitute;
private Collection publications;
...
이 주석들은 Scientist 객체가 루트 엘리먼트이고 Person 객체는 Xmltype이라는 것을 지정한다. 정의된 주석 타입으로는 XmlAttribute, XmlElement, XmlSchema 등을 포함한 여러 종류가 있으며, javax.xml.bind.annotation API 문서에서 전체 목록을 구할 수 있다.
주석과 기본값 매핑은 기존 코드를 최소한으로 변경하여 클래스를 스키마에 매핑할 수 있도록 설계되었으며, 기본값 매핑은 주석이 지정되지 않더라도 프로그램 엘리먼트에 적용되는 것으로 간주되는 기본값 주석을 기초로 하여 지정된다. 이와 관련한 자세한 내용을 보려면 최종본 JAXB 2.0 스펙의 섹션 8.12를 참조할 것. 본 팁의 코드 예제의 경우, Person 클래스에 @XmlType 주석을 첨부할 필요가 없으며, 주석이 없더라도 JavaBeans 객체는 여전히 해당 타입에 정확히 매핑된다(주석에 코멘트를 붙여서 테스트해보면 알 수 있다). 기본값 바인딩이 충분치 않을 때는 커스터마이징 주석을 지정해야 하는데, 예를 들어 필드 또는 속성의 기본값 바인딩을 위한 커스터마이징 주석을 지정하려면 @XmlAttribute을 이용해야 한다.
Java-to-XML Schema 매핑이 갖추어진 상태에서는 XMLSchema를 제공하지 않고 자바 객체를 마샬링할 수 있다. 먼저 JavaContext 객체를 생성하여 해당 컨텍스트 경로를 지정한다. 이 예제에서는 Scientist 자바 객체(Person 객체의 생성을 요구하는)가 컨텍스트 경로를 제공한다. 다음으로, JavaContext 객체를 marshaller에 패스한다.
JAXBContext context =
JAXBContext.newInstance(Scientist.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
해당 속성을 이용하여 필요한 Scientist와 Person 객체를 생성한 후에는 마샬링 된 XML 파일로 어떤 연산이든 수행할 수 있다. XML 컨텐츠를 콘솔로 프린트 아웃하는 경우를 한 예로 들 수 있다.
Scientist scientist = js.getScientist(); m.marshal(scientist, System.out);
JAXB 2.0에 관한 더 자세한 내용은 JAXB 2.0 프로젝트 페이지를 참조할 것.
예제 코드 실행하기
예제 패지키에는 팁에서 다룬 기법을 예시하는 본 팁이 포함되어 있다. 예제를 설치하고 실행하려면 다음의 작업 절차를 따르도록 한다.
- J2SE(Java 2 Platform, Standard Edition) 5.0이 설치되어 있지 않다면 J2SE 5.0 다운로드 페이지에서 다운로드하여 설치한다. JAXB 2.0은 주석과 같은 새로운 J2SE 5.0 언어 기능을 이용하기 때문에 J2SE 5.0을 필요로 한다.
- JAXB 2.0 프로젝트 다운로드 페이지에서 최신의 JAXB 2.0 번들을 다운로드하여 설치한다.
- 팁과 관련한 예제 아카이브를 다운로드한다. 다운로드한 아카이브를 <JAXB_RI>
/samples디렉토리에 압축을 푼다. 이 때, <JAXB_RI>는 JAXB 2.0 RI EA 3을 설치한 디렉토리이다. 이제 새로 압축을 푼 디렉토리가 <JAXB_RI>/samples/techtip으로 표시되어야 한다. 예를 들어, EA3 릴리즈를 Windows 컴퓨터의C:\Sun\에 설치했다면 새로 생성된 디렉토리는C:\Sun\jaxb-ri-20050622\samples\techtip이 되어야 한다.
팁의build.xml파일은 JAXB 2.0 EA3 번들에 정의된 디렉토리 구조에 의존하기 때문에 이 zip 파일을 이 디렉토리에서 압축을 푸는 것이 중요하다.classpath및 실행 속성은 이미build.xml파일에 정의되어 있으므로, 해당 타깃을 컴파일하여 실행하기만 하면 된다.
언마샬링/마샬링 예제를 실행하려면 다음 단계를 수행한다:
- <JAXB_RI>
/samples/techtip디렉토리로 내비게이트하여 다음의 명령어를 실행한다.ant compile
이 명령어는po.xsd스키마로부터 자바 클래스와 예제 자바 클래스를 생성하고 컴파일하는데 사용된다. JAXB 2.0 패키지에는 ant 바이너리가 포함되어 있지 않다는 점에 유의할 것. Java WSDP 1.6이 설치되어 있다면, <JWSDP_HOME>/apache-ant/bin디렉토리에 위치한 ant 바이너리를 이용할 수 있다(이 때, <JWSDP_HOME>는 Java WSDP 1.6이 설치된 곳을 가리킴). 또는 apache 웹 사이트에서 ant를 다운로드할 수도 있다.
po.xml문서를 언마샬링하고 JAXP 1.3 스키마 검증 프레임워크를 이용하여 검증을 거친 다음 마샬링을 수행한다. 이 작업에는 다음의 명령어를 사용한다.ant run-validate마샬링 연산은incorrectpo.xml파일을 생성하게 되는데, 출력에는 다음의 내용이 포함되어야 한다.Message is cvc-type.3.1.3: The value '150' of element 'quantity' is not valid. Column is 31 at line number 28 Bugsy Brown 99 9th Avenue New York, NY 12345 US Still able to marshal invalid documentJava-to-Schema 바인딩 예제를 실행하려면 다음의 명령어를 실행한다.ant run-javaToSchema
출력에는 다음의 내용이 포함되어야 한다.<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <scientist> <person> <name>Linus Pauling</name> <age>93</age> <sex>Male</sex> </person> <publications xmlns: xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Respect for vitamin C </publications> <publications xmlns: xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">The Nature of the Chemical Bond </publications> </scientist>
필자 소개
Kim LiChong은 썬 마이크로시스템즈 Java Web Services Performance Engineering Group 기술진의 멤버로서, XML 파싱 성능에 대해 특히 지대한 관심을 가지고 있으며, StAX 1.0 White Paper: Streaming APIs for XML Parsers의 공동 저자 중 한 사람이기도 하다. 그는 또한 XML 파싱 성능 측정에 사용되는 마이크로벤치마크인 xmltest의 공동 소유자이다. xmltest에 관한 자세한 내용을 보려면 xmltest 프로젝트 페이지를 참조할 것.
"Java EE" 카테고리의 다른 글
- JAX-WS 핸들러 구성, 패키징, 배치하기 (댓글 2개 / 트랙백 0개) 2006/10/19
- Enterprise Bean에서 보안 주석 사용하기 (댓글 4개 / 트랙백 0개) 2007/05/28
- 엔터프라이즈용 Java Application Verification Kit, 2부 (댓글 1개 / 트랙백 0개) 2005/10/05
- Java Persistence를 최상으로 구현하는 방법 (댓글 12개 / 트랙백 0개) 2007/07/23
- SAAJ 소개 (댓글 1개 / 트랙백 0개) 2005/06/08
- 커스텀 ELResolver를 이용하여 통합 EL 확장하기 (댓글 4개 / 트랙백 0개) 2006/10/19
- JAX-WS를 이용한 웹 서비스 개발 (댓글 1개 / 트랙백 0개) 2006/01/18
- JAXR (JAVA API FOR XML REGISTRIES) (댓글 1개 / 트랙백 0개) 2005/05/18
- GlassFish에서 호출 흐름 모니터링하기 (댓글 3개 / 트랙백 0개) 2006/06/16
- Groovy, Grails, MySQL 및 Java Persistence API의 조합 (댓글 0개 / 트랙백 0개) 2008/08/20
댓글을 달아 주세요
좋은 정보 감사해요~
2007/09/19 04:45