저자 Jennie Hall
XML 및 JAXB를 사용한 데이터 교환, 제 1 부에서는 XML 바인딩(JAXB)을 위한 자바 아키텍처가 시스템 간에 데이터를 교환하는 방식을 살펴보았습니다. JAXB 2.0의 주석 지원을 사용하여 비즈니스 파트너를 위한 XML 데이터를 생성하는 것은 기존 개체 모델에서 주석 처리를 하는 것만큼 쉽습니다.
이 팁에서는 JAXB의 바인딩 사용자 정의 기능이 데이터를 보낸 사람과 받는 사람측에서 XML을 어떻게 처리하는지 알아보겠습니다. 바인딩 사용자 정의 기능은 JAXB 스키마 컴파일러에서 생성한 Java 클래스의 특징을 제어하는 수준을 제공합니다. 이 기능을 통해 사용자가 직접 설계하지 않은 스키마에 따라 XML 인스턴스 문서를 처리할 때도 비즈니스 도메인에 사용할 수 있는 개체 모델로 작업할 수 있습니다.
XML 바인딩용 자바 아키텍처(JAXB)에 대한 간단한 개요를 보려면 XML 및 JAXB를 사용한 데이터 교환, 제 1 부의 "JAXB란?" 섹션을 참조하십시오.
샘플 애플리케이션
1부의 시나리오를 사용하여 계속 진행하겠습니다. 동물 병원인 NiceVet은 고객들에게 검진 예약 일정 및 애완동물의 생일 카드를 보내려고 합니다. NiceVet은 생일 카드를 인쇄하고 발송하기 위해 서비스 공급업체인 WePrintStuff와 계약을 맺습니다. 1부에서 우리는 NiceVet의 기존 개체 모델을 주석 처리한 다음 JAXB를 사용하여 자바 개체에서 XML 인스턴스 문서로 데이터를 마샬링하여 WePrintStuff에서 작업하는 데 필요한 일부 데이터를 수집했습니다. JAXB 스키마 생성기를 사용하여 주석 처리한 Java 클래스에서 해당 스키마도 생성했습니다.
받는 쪽인 WePrintStuff에서 스키마 파생 클래스를 생성하기 위해 소스 스키마에 대해 JAXB 스키마 컴파일러를 실행합니다. JAXB는 XML 인스턴스 문서에서 NiceVet의 데이터를 언마샬링하고 이를 Java 콘텐츠 트리에 바인딩할 때 이러한 클래스의 인스턴스를 만듭니다. 그러나 일부 경우에는 JAXB가 스키마 파생 클래스를 생성하고 데이터를 바인딩하는 기본 방식이 적합하지 않을 수도 있습니다. JAXB의 바인딩 사용자 정의 기능은 이러한 경우에 적용할 수 있는 여러 가지 좋은 방법을 제공합니다. 다음 절에서는 이러한 방법을 살펴보겠습니다.
소스 스키마 사용자 정의
WePrintStuff에서 더 쉽게 처리할 수 있는 몇 가지 사용자 정의를 지금 즉시 만들 수 있습니다. 예를 들어 이름으로 인한 혼란을 피할 수 있도록 의미 있는 패키지 이름과 클래스 이름을 사용하겠습니다. 이 작업을 완수하기 위해 사용자 정의 바인딩 선언을 소스 스키마 자체에 추가할 수 있습니다. 이를 인라인 사용자 정의라고도 합니다.
다음은 주석 처리된 스키마의 처음 몇 줄입니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
<!-- JAXB namespace declaration required for inline customization -->
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc"
<!-- JAXB version number required for inline customization -->
jxb:version="2.0">
<xs:annotation>
<xs:appinfo>
<!-- All collections in this schema will use implementation class java.util.ArrayList. -->
<jxb:globalBindings collectionType="java.util.ArrayList"/>
<jxb:schemaBindings>
<!-- Specify the package for the generated classes; avoid naming collisions. -->
<jxb:package name="weprintstuff.generated">
<!-- Specify some Javadoc that describes our package and its uses. -->
<jxb:javadoc><![CDATA[<body> The package weprintstuff.generated contains the
schema-derived classes that make up the object model used to process
print client orders.</body>]]>
</jxb:javadoc>
</jxb:package>
</jxb:schemaBindings>
</xs:appinfo>
</xs:annotation>
인라인 사용자 정의를 사용하려면 JAXB 네임스페이스 선언과 JAXB 버전 번호를 포함해야 합니다. 샘플 애플리케이션에 사용할 JAXB 네임스페이스 접두사는 jxb:입 니다. 다른 범위에 있는 기본 JAXB 바인딩은 재정의할 수 있습니다. 더 낮은 수준의 더 세밀한 범위는 더 높은 수준의 범위에서 만든 선언을 상속하지만 더 낮은 수준의 범위에서 만든 바인딩 선언이 이와 같은 상속된 선언을 재정의할 수 있습니다. 범위에는 전역, 스키마, 정의, 구성 요소(최상위 수준에서 최하위 수준 순서으로 표시)가 있습니다.
앞의 예에서는 이 스키마의 모든 모음이 구현 클래스인 java.util.ArrayList를 사용하도록 지정하는 전역 범위에서 선언을 만들었습니다. 소스 스키마가 다른 스키마를 가져온 경우에는 이 선언이 두 번째 스키마에도 적용됩니다. <globalBindings> 선언은 스키마마다 하나씩만 있을 수 있습니다. 이 선언은 최상위 수준의 스키마에서만 유효합니다.
JAXB 스키마 컴파일러가 스키마 파생 클래스를 생성할 패키지를 스키마 범위에서 지정했습니다. 또한 패키지와 그 용도를 설명하는 패키지 수준의 Javadoc도 몇 개 포함했습니다. 사용자 정의 바인딩 선언을 <annotation><appinfo> 태그 안에 포함했습니다.
이제 원하는 패키지를 만들었으니 Java 명명 규칙과 WePrintStuff의 비즈니스 도메인을 더욱 잘 반영하는 클래스 이름을 몇 개 만들 수 있는지 살펴보겠습니다. 원래 스키마의 기본 바인딩은 ClassAType, ClassBType 등의 이름으로 클래스를 생성합니다. 이러한 이름은 자바 프로그래밍 언어에서 일반적으로 클래스 이름을 지정하는 방식이 아니므로 수정해보겠습니다.
<xs:element name="printOrder" type="PrintOrderType"/>
<xs:complexType name="PrintOrderType">
<xs:annotation>
<xs:appinfo>
<!-- Name the generated class PrintOrder rather than PrintOrderType. -->
<jxb:class name="PrintOrder">
<!-- Provide some Javadoc for PrintOrder. -->
<jxb:javadoc><![CDATA[<code>PrintOrder</code> javadoc goes here]]>
</jxb:javadoc>
</jxb:class>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="notifications" type="notificationsType" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<!-- PrintOrder's notifications property becomes printItems. -->
<jxb:property name="printItems"/>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
...
</xs:complexType>
<xs:complexType name="notificationsType">
<xs:annotation>
<xs:appinfo>
<!-- Name the generated class PrintItems rather than NotificationsType. -->
<jxb:class name="printItems" />
</xs:appinfo>
</xs:annotation>
...
</xs:complexType>
PrintOrderType은 PrintOrder, NotificationsType은 PrintItems 등으로 바뀝니다. 클래스 이름을 바꾸는 일은 간단하지만 적절하지 않은 클래스 구조 때문에 문제에 봉착했습니다. 데이터 주변에 래퍼가 너무 많아 메소드 호출이 길게 이어집니다. 원래 스키마 파생 클래스를 사용할 경우 다음과 같은 모양으로 호출됩니다. 보는 바와 같이 메소드 이름이 이상한 메소드가 모음을 반환하므로 오류입니다.
List<AppointmentType> appointments = printOrder.getNotifications().getAppointments().getAppointment(); List<BirthdayType> birthdays = printOrder.getNotifications().getBirthdays().getBirthday();
수정된 다음 호출은 새 이름을 표시합니다. 이 이름은 해당 호출의 의미를 알려주며 WePrintStuff의 비즈니스 도메인과 더욱 관련성이 있습니다.
List<Appointment> appointments = printOrder.getPrintItems().getAppointmentHolder().getAppointments(); List<Birthday> birthdays = printOrder.getPrintItem().getBirthdayHolder().getBirthdays();
향상된 <jxb:javaType> 사용자 정의(<xjc:javaType>) 및 XmlAdapter에서 파생된 어댑터 클래스를 사용하여 일부 클래스 구조 문제를 해결하려고 했지만 JAXB는 현재 복잡한 XML 형식에 대해 이 사용자 정의를 지원하지 않습니다. 이 문제는 JAXB 문제 추적에 문제 번호 209로 설명되어 있습니다. 다음 단락에서는 간단한 XML 형식에 사용되는 향상된 <jxb:javaType> 사용자 정의의 예를 살펴보겠습니다.
소스 스키마를 아래로 내리면 수신한 각 인쇄 주문에 long 형식의 ID가 있음을 볼 수 있습니다. 그러나 WePrintStuff는 영구 저장소에서 기본 키 전략을 채택하고 있음을 알고 있습니다. 인쇄 주문 기록에서 키는 고객 이름과 주문 ID로 구성됩니다. WePrintStuff에서는 PrintOrderKey 클래스를 사용하여 이 중요 정보를 캡슐화합니다. JAXB 스키마 컴파일러가 어댑터 클래스인 IdAdapter를 사용하여 원래 인쇄 주문 ID를 WePrintStuff의 PrintOrderKey 클래스로 바꾸는 바인딩 사용자 정의를 적용할 것입니다. 다음 코드를 보십시오.
<xs:element name="printOrder" type="PrintOrderType"/>
<xs:complexType name="PrintOrderType">
<xs:sequence>
<xs:element name="notifications" type="notificationsType" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:long" use="required">
<xs:annotation>
<xs:appinfo>
<!-- Use an XmlAdapter-based adapter to create WePrintStuff's PrintOrderKey class. -->
<!-- Specify the name orderKey for this property. -->
<jxb:property name="orderKey">
<jxb:baseType>
<!-- Specify weprintstuff.print.PrintOrderKey as the type of the orderKey property. -->
<!-- Specify the adapter class that will map the schema type to the Java type. -->
<xjc:javaType name="weprintstuff.print.PrintOrderKey"
adapter="weprintstuff.print.IdAdapter"/>
</jxb:baseType>
</jxb:property>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
</xs:complexType>
인쇄 주문 등록 정보의 이름을 orderKey로 변경하고 어댑터 및 주문 키의 형식을 지정했습니다. 언마샬링 프로세스 중에 JAXB가 IdAdapter의 unmarshal() 메소드를 호출하여 id 값을 수신하고 이 값을 주문 ID와 고객 이름이 포함된 새 PrintOrderKey에 통합합니다. 다음은 IdAdapter와 관련된 코드입니다.
public class IdAdapter extends XmlAdapter<String, PrintOrderKey> {
// When marshalling a Java content tree to an XML instance document,
// move from the type that we work with in Java (PrintOrderKey)
// to the type that JAXB understands.
public String marshal(PrintOrderKey key) throws Exception {
return key.getOrderId().toString();
}
// When unmarshalling an XML instance document to a Java content tree,
// move from the type that JAXB understands (String) to the type
// we want to work with in Java technology.
public PrintOrderKey unmarshal(String id) throws Exception {
// WePrintStuff uses natural keys. Add client name and
// convert String ID to required Long.
return new PrintOrderKey("NICEVET", new Long(id));
}
}
방금 검토한 <xjc:javaType> 사용자 정의는 공급업체 확장의 예입니다. JAXB RI(참조 구현)는 JAXB 규격의 일부가 아닌 다른 사용자 정의를 추가로 제공합니다. 이러한 확장을 사용하려면 JAXB RI 공급업체 확장 네임스페이스에 대한 선언을 포함하고 네임스페이스 접두사를 지정해야 합니다.
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
<!-- JAXB RI vendor extension namespace declaration is required. -->
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
<!-- JAXB RI vendor extension namespace prefix is required. -->
jxb:extensionBindingPrefixes="xjc"
jxb:version="2.0">
마지막으로 공급업체 확장을 사용하려면 스키마 컴파일러를 -extension 스위치와 함께 실행해야 합니다. 공급업체 확장이 아닌 표준 <jxb:javaType> 사용자 정의의 예로 niceVet.xsd 및 weprintstuff.print.CustomDataTypeConverter를 참조하십시오. 이러한 파일은 이 테크 팁과 함께 제공하는 샘플 코드에 포함되어 있습니다. 예에서 <jxb:javaType> 사용자 정의를 사용하여 XML dateTime 형식을 출력 가능한 멋진 포맷의 String 날짜로 변환했습니다.
모양은 나아졌지만 가능한 여러 가지 모양으로 예약 일정 알림과 생일 카드를 인쇄하려고 합니다.다음 코드를 보십시오.
<xs:complexType name="AppointmentType">
<xs:annotation>
<xs:appinfo>
<!-- Name has generated class Appointment rather than AppointmentType. -->
<jxb:class name="Appointment">
<jxb:javadoc><![CDATA[<code>Appointment</code> javadoc goes here]]>
</jxb:javadoc>
</jxb:class>
</xs:appinfo>
</xs:annotation>
<xs:complexContent>
<!-- XML Schema extension element causes AppointmentType to derive from printItemType, a type we've added to the schema. -->
<xs:extension base="printItemType">
<xs:sequence>
...
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
...
<!-- Add this complex type to the schema so that Appointment class now derives from PrintItem, a base class that we've implemented. -->
<xs:complexType name="printItemType">
<xs:annotation>
<xs:appinfo>
<!-- Due to this customization, JAXB will not generate a class for printItemType; it will use the PrintItem class that we've written. -->
<jxb:class ref="weprintstuff.print.PrintItem"/>
</xs:appinfo>
</xs:annotation>
</xs:complexType>
다행히도 소스 스키마의 구조를 수정하면서도 동일한 XML 인스턴스 문서 세트의 유효성을 확인하는 스키마의 기능은 그대로 유지할 수 있습니다. 이 예에서는 완전히 새로운 복잡한 형식인 printItemType을 스키마에 추가했습니다. 그런 다음 XML 스키마 확장 요소를 사용하여 복잡한 형식인 AppointmentType을 수정했습니다. 그 결과 AppointmentType이 printItemType에서 파생되었습니다.
이 시점에서 스키마 컴파일러가 클래스를 생성하지 않고 우리가 작성한 지정 클래스를 사용하도록 명령하는 printItemType에 JAXB 사용자 정의를 적용했습니다. PrintItem을 직접 구현했으므로 동작을 포함할 수 있습니다. 특히 Appointment 및 Birthday 같은 하위 클래스를 보다 다양한 방법으로 처리할 수 있는 print() 메소드 동작을 포함할 수 있습니다. 다음은 PrintItem과 관련된 코드입니다.
package weprintstuff.print;
import java.util.*;
public abstract class PrintItem {
private static final Map<String,Printer> printers;
static {
printers = new HashMap<String,Printer>();
printers.put("weprintstuff.generated.Birthday", new BirthdayPrinter());
printers.put("weprintstuff.generated.Appointment", new AppointmentPrinter());
}
public void print() {
Printer p = this.getPrinter();
p.print(this);
}
private Printer getPrinter() {
return printers.get(this.getClass().getName());
}
}
인터페이스에는 다음과 같은 단일 메소드가 있습니다.
Printer
public void print(PrintItem item);
앞에서 검토한 대로 스키마 파생 클래스의 구조가 아직도 문제가 되지만 인쇄 주문에서 항목을 인쇄할 코드는 이제 매우 깔끔합니다. 다음은 main() 메소드에서 발췌한 것입니다.
// Unmarshal the data in the XML instance document to a Java content tree
// made up of instances of the schema-derived classes.
JAXBElement printOrderElement = (JAXBElement)unmarshaller.unmarshal(new FileInputStream(input));
PrintOrder printOrder = (PrintOrder)printOrderElement.getValue();
List<Appointment> appointments = printOrder.getPrintItems().getAppointmentHolder().getAppointments();
for (Appointment a : appointments) {
a.print();
}
List<Birthday> birthdays = printOrder.getPrintItems().getBirthdayHolder().getBirthdays();
for (Birthday b : birthdays) {
b.print();
}
JAXB가 제공하는 또 다른 멋진 사용자 정의 기능은 간단한 XML 형식을 typesafe 열거에 매핑할 수 있다는 것입니다. 이 기능은 WePrintStuff에서 현재 특정 종류의 예약에 대해서만 인쇄 템플리트를 가지고 있으므로 편리합니다. 지원되는 예약 종류를 포함하도록 스키마를 수정하고 스키마 컴파일러가 ApptType의 요소를 Java typesafe enum 클래스에 매핑하도록 하는 사용자 정의를 추가하겠습니다. WePrintStuff에서 지원하지 않는 예약 종류가 있는 XML 인스턴스 문서는 거부됩니다.
<xs:simpleType name="ApptType">
<xs:annotation>
<xs:appinfo>
<!-- Map the elements of this simple type to a Java typesafe enum class. -->
<jxb:typesafeEnumClass/>
</xs:appinfo>
</xs:annotation>
<!-- Use XML Schema elements restriction and enumeration to define the supported appointment types. -->
<xs:restriction base="xs:string">
<xs:enumeration value="Yearly Checkup"/>
<xs:enumeration value="Well Mom Exam"/>
<xs:enumeration value="Teeth Cleaning"/>
<xs:enumeration value="Vaccination"/>
<xs:enumeration value="Senior Pet Checkup"/>
</xs:restriction>
</xs:simpleType>
다음은 결과로 만들어지는 typesafe enum 클래스인 ApptType입니다.
package weprintstuff.generated;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;
@XmlType(name = "ApptType")
@XmlEnum
public enum ApptType {
@XmlEnumValue("Yearly Checkup")
YEARLY_CHECKUP("Yearly Checkup"),
@XmlEnumValue("Well Mom Exam")
WELL_MOM_EXAM("Well Mom Exam"),
@XmlEnumValue("Teeth Cleaning")
TEETH_CLEANING("Teeth Cleaning"),
@XmlEnumValue("Vaccination")
VACCINATION("Vaccination"),
@XmlEnumValue("Senior Pet Checkup")
SENIOR_PET_CHECKUP("Senior Pet Checkup");
private final String value;
ApptType(String v) {
value = v;
}
public String value() {
return value;
}
public static ApptType fromValue(String v) {
for (ApptType c: ApptType.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
지금까지 인라인 바인딩 사용자 정의라는 것을 만들었지만 JAXB도 하나 이상의 외부 바인딩 사용자 정의 파일 형식으로 사용자 정의를 허용합니다. 인라인 사용자 정의와 외부 사용자 정의를 함께 사용할 수 있지만 같은 요소에서는 함께 사용할 수 없습니다. 외부 바인딩 파일은 지정된 스키마를 수정할 수 없을 때나 스키마에서 사용자 정의를 다시 사용하려 할 때 유용합니다. 예를 들어 WePrintStuff에는 미국 주소를 위한 자체 클래스(DomesticAddress)가 있으며 WePrintStuff에서 이 클래스를 사용하여 시스템 전체에서 주소의 개념을 표시합니다.
다음은 외부 바인딩 파일인 binding.xjb입니다.
<!-- XML Schema namespace is required, as are the JAXB namespace and version. -->
<jxb:bindings version="2.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Specify the schema name and root schema node. -->
<jxb:bindings schemaLocation="niceVet.xsd" node="/xs:schema">
<!-- Specify the schema node to which this customization should apply with an XPath expression. -->
<jxb:bindings node="//xs:complexType[@name='AddressType']">
<!-- Direct the schema compiler to use the DomesticAddress class rather than generating a class for complex type AddressType. -->
<jxb:class ref="weprintstuff.print.DomesticAddress"/>
</jxb:bindings> <!-- node="//xs:complexType[@name='AddressType']" -->
</jxb:bindings> <!-- schemaLocation="niceVet.xsd" node="/xs:schema" -->
</jxb:bindings>
바인딩 사용자 정의 파일은 ASCII 텍스트 파일일 뿐입니다. 유효한 바인딩 파일은 스키마 이름과 노드를 지정해야 합니다. 우리는 XPath 식을 사용하여 노드를 확인합니다. 앞에서 우리는 스키마 컴파일러에게 복잡한 형식인 AddressType의 클래스를 생성하지 않고 WePrintStuff의 DomesticAddress 클래스를 사용하도록 지시하는 사용자 정의를 적용했습니다. 이것은 앞서 PrintItem 기반 클래스의 예에서 보여준 것과 같은 사용자 정의입니다. 앞의 예에서는 사용자 정의를 인라인으로 선언한 점만 다릅니다. 바인딩 사용자 정의 파일을 스키마 컴파일러에 제공하는 구문은 다음과 같습니다.
xjc -b bindings schema
여러 개의 바이딩 파일을 하나의 스키마에 적용하거나, 하나의 바인딩 파일을 여러 스키마에 적용할 수 있고, 여러 바인딩 파일을 여러 스키마에 적용할 수도 있습니다. 각 바인딩 파일에는 각각의 -b 스위치가 있어야 합니다.
스키마 파생 클래스 생성
명령줄에서 스키마 컴파일러 xjc에 대해 다음 명령을 사용하여 스키마 파생 클래스를 생성합니다.
xjc -d ./src -b binding.xjb -extension niceVet.xsd
스키마 컴파일러가 다음과 같은 내용을 출력하여 클래스를 생성했음을 알려줍니다.
parsing a schema... compiling a schema... weprintstuff\generated\Adapter1.java weprintstuff\generated\Adapter2.java weprintstuff\generated\Appointment.java weprintstuff\generated\ApptType.java weprintstuff\generated\Birthday.java weprintstuff\generated\ObjectFactory.java weprintstuff\generated\Owner.java weprintstuff\generated\Pet.java weprintstuff\generated\PrintItems.java weprintstuff\generated\PrintOrder.java weprintstuff\generated\package.html
JAXB 스키마 컴파일러에는 여러 가지 옵션이 있습니다. 예를 들어 -readOnly 스위치에 대한 응답으로 생성된 클래스를 read only로 표시합니다. 자세한 내용을 보려면 옵션을 사용하지 않거나 -help 스위치를 사용하여 xjc를 호출하십시오.
장점
소스 스키마를 수정하고, 사용자 정의를 만들었으며, 스키마 파생 클래스를 생성해보았습니다. 이제 남은 일은 인쇄 프로그램을 실행하여 JAXB가 NiceVet에서 제공한 XML 데이터를 바인딩한 후 예약 일정 알림 및 생일 카드를 인쇄하는 것입니다. XML 인스턴스 문서를 살펴보겠습니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<printOrder id="1219271208522">
<notifications>
<appointments>
<appointment>
<apptType>Yearly Checkup</apptType>
<apptDate>2008-09-15T00:00:00-07:00</apptDate>
<owner>
<firstName>Joe</firstName>
<lastName>Outdoors</lastName>
<address>
<addressLine1>123 Whitewater Street</addressLine1>
<city>OurTown</city>
<state>CA</state>
<zip>90347</zip>
<zipExt>1234</zipExt>
</address>
</owner>
<pet>
<name>Honcho</name>
<species>Dog</species>
</pet>
</appointment>
<appointment>
<apptType>Well Mom Exam</apptType>
<apptDate>2008-09-12T00:00:00-07:00</apptDate>
<owner>
<firstName>Missy</firstName>
<lastName>Fairchild</lastName>
<address>
<addressLine1>456 Scenic Drive</addressLine1>
<city>West OurTown</city>
<state>CA</state>
<zip>90349</zip>
<zipExt>6789</zipExt>
</address>
</owner>
<pet>
<name>Miss Kitty</name>
<species>Cat</species>
</pet>
</appointment>
</appointments>
<birthdays>
<birthday>
<age>7</age>
<birthday>2000-09-07T00:00:00-07:00</birthday>
<owner>
<firstName>Violet</firstName>
<lastName>Flowers</lastName>
<address>
<addressLine1>22375 Willow Court</addressLine1>
<city>West OurTown</city>
<state>CA</state>
<zip>90349</zip>
<zipExt>6789</zipExt>
</address>
</owner>
<pet>
<name>Tom</name>
<species>Cat</species>
</pet>
</birthday>
</birthdays>
</notifications>
</printOrder>
다음은 main() 메소드를 다르게 사용한 것입니다.
// The XML instance document received from NiceVet contains NiceVet's print order.
File input = new File("niceVet.xml");
// Create a JAXBContext for the weprintstuff.generated package.
JAXBContext ctx = JAXBContext.newInstance("weprintstuff.generated");
// Create an unmarshaller.
Unmarshaller unmarshaller = ctx.createUnmarshaller();
// Unmarshal the data in the XML instance document to a Java content tree made up of instances of the schema-derived classes.
JAXBElement printOrderElement = (JAXBElement)unmarshaller.unmarshal(new FileInputStream(input));
PrintOrder printOrder = (PrintOrder)printOrderElement.getValue();
// Print out the print items.
List<Appointment> appointments = printOrder.getPrintItems().getAppointmentHolder().getAppointments();
for (Appointment a : appointments) {
a.print();
}
List<Birthday> birthdays = printOrder.getPrintItems().getBirthdayHolder().getBirthdays();
for (Birthday b : birthdays) {
b.print();
}
결과를 확인하십시오. 누구도 다시는 예약이나 생일을 놓칠 수 없게 됩니다.
Hi Joe! Our records show that your dog Honcho has a Yearly Checkup appointment scheduled on 09/15/2008. Please call us 24 hours prior to your appointment if you need to reschedule. Sincerely, NiceVet Hi Missy! Our records show that your cat Miss Kitty has a Well Mom Exam appointment scheduled on 09/12/2008. Please call us 24 hours prior to your appointment if you need to reschedule. Sincerely, NiceVet Hi Violet! Our records show that your cat Tom will turn 7 years old on 09/07. Happy Birthday, Tom, from all of us at NiceVet!
샘플 애플리케이션 실행
샘플 애플리케이션을 실행하려면 샘플 코드를 다운로드하고 압축을 풉니다. <sample-install-dir>/schema-to-java 디렉토리를 이동하고 "스키마 파생 클래스 생성" 절에서 설명한 대로 스키마 파생 클래스를 생성합니다.
NetBeans IDE를 실행하고 File -> Open Project를 선택합니다. Open Project 대화 상자에서 샘플 코드의 압축을 푼 디렉토리로 이동하여 schema-to-java 폴더를 선택합니다. Open as Main Project 확인란을 선택합니다. Open Project Folder를 클릭합니다. schema-to-java 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Run Project를 선택합니다.
결론
XML 및 JAXB를 사용한 데이터 교환, 제 1 부와 제 2 부에서는 JAXB를 통해 비즈니스 파트너 간의 데이터 흐름을 관리하는 방법을 알아보았습니다. 데이터를 교환하는 양측에서 XML을 처리하는 기능을 사용하면 JAXB가 시스템 간에 보다 간단하고 생산적으로 통합을 수행할 수 있습니다.
참고 자료 및 리소스
이 팁의 샘플 코드
Java EE 5 Tutorial
Kohsuke Kawaguchi의 블로그 - Kohsuke Kawaguchi는 썬 마이크로시스템즈의 엔지니어로서, 여러 프로젝트 중 JAXB 관련 프로젝트를 담당합니다.
JSR 222: JAXB 규격
저자 정보
Jennie Hall은 금융 부문에서 근무하는 개발자입니다.
이 글의 영문 원본은
Exchanging Data With XML and JAXB, Part 2
에서 보실 수 있습니다.
"Java SE" 카테고리의 다른 글
- STRINGTOKENIZER에서 SCANNER까지 (댓글 2개 / 트랙백 1개) 2005/04/26
- 정적 인스턴스 초기화 블록 사용하기 (댓글 2개 / 트랙백 0개) 2004/04/13
- QUEUE와 DELAYED 프로세싱 (댓글 3개 / 트랙백 0개) 2004/11/04
- Callable을 사용하여 Runnable로부터 결과 반환 (댓글 0개 / 트랙백 0개) 2008/02/20
- 가비지 콜렉션 (댓글 3개 / 트랙백 0개) 2004/06/30
- 스윙에서의 멀티 쓰레딩 (댓글 2개 / 트랙백 0개) 2003/12/12
- SWING COMPONENTS의 저장과 재구성 (댓글 5개 / 트랙백 0개) 2003/08/05
- 스플래시 스크린과 MUSTANG (댓글 1개 / 트랙백 2개) 2005/12/20
- WSIT에서의 지원 토큰과 발급된 토큰 위임 (댓글 20개 / 트랙백 2개) 2007/09/03
- Singleton 패턴에 대한 재고찰 (댓글 4개 / 트랙백 1개) 2006/04/21
댓글을 달아 주세요