Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

[Spring 레퍼런스] 15장 O/X 매퍼(Mapper)를 사용한 XML 마샬링(Marshalling)

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.




15. O/X 매퍼(Mapper)를 사용한 XML 마샬링(Marshalling)

15.1 소개
이번 장에서는 스프링의 Object/XML 매핑지원을 설명할 것이다. Object/XML 매핑(줄여서 O/X 매핑)은 XML 문서를 객체로 변환하거나 객체를 XML로 변환하는 행위이다. 이 변환과정은 XML 먀샬링(Marshalling)이나 XML 직렬화(Serialization)라고도 알려져 있다. 이번 장에서는 혼용가능한 이 용어들을 사용할 것이다.

O/X 매핑분야에서는 marshaller가 객체(그래프)를 XML로 직렬화하는 책임을 진다. 유사한 방법으로 unmarshaller가 XML을 객체 그래프로 역직렬화한다. 이 XML은 DOM 문서나 입력 스트림, 출력 스트림, SAX 핸들러의 형식을 받을 수 있다.

O/X 매핑이 필요한 곳에 스프링을 사용하는 이점이 몇가지 있다.

쉬운 설정.  스프링의 빈 팩토리는 JAXB 컨텍스트, JiBX 바인딩 팩토리 등을 생성할 필요없이 마샬러의 설정을 쉽게한다. 어플리케이션 컨텍스트의 다른 빈들처럼 마살러를 설정할 수 있다. 게다가 설정을 더 쉽게 하는 XML 스키마기반의 설정을 다수의 마살러에도 사용할 수 있다.

일관된 인터페이스.  스프링의 O/X 매핑은 두개의 전역 인터페이스 Marshaller와 Unmarshaller인터페이스를 통해서 수행된다. 이러한 추상화를 통해서 마샬링을 하는 클래스를 약간만 변경하거나 전혀 변경하지 않고 상대적으로 쉽게 O/X 매핑 프레임워크를 바꿀 수 있다. 이 접근은 비침투적인 방법으로 각 기술의 장점을 이용해서 믹스앤매치(mix-and-match) 접근으로 XML 마샬링을 할 수 있게 하는 부가적인 이점이 있다.

일관된 예외 계층.  스프링은 의존하는 O/X 매핑도구의 예외를 최상위(root) 예외가 XmlMappingException인 자신만의 예외계층으로의 변환을 제공한다. 기대하는 대로 이러한 런타임 예외는 원래의 예외를 감싸기 때문에 정보를 잃어버리지 않는다.


15.2 마살러(Marshaller)와 언마샬러(Unmarshaller)
소개부분에서 얘기했듯이 마샬러는 객체를 XML롤 직렬화하고 언마샬러는 XML 스트림을 객체로 역직렬화한다. 이번 섹션에서 이 목적에 사용하는 스프링의 두 인터페이스를 설명할 것이다.


15.2.1 마샬러
스프링은 org.springframework.oxm.Marshaller 인터페이스뒤에 모든 마샬링 작업을 추상화한다. 여기의 주요 메서드들은 다음 목록에 나와 있다.

public interface Marshaller {
  /**
   * Marshals the object graph with the given root into the provided Result.
   */
  void marshal(Object graph, Result result)
    throws XmlMappingException, IOException;
}

Marshaller 인터페이스는 주어진 객체를 주어진 javax.xml.transform.Result로 마샬링하는 하나의 메인메서드를 가진다. 결과는 기본적으로 XML 출력 추상화를 나타내는 태깅(tagging) 인터페이스이다. 구현체(concrete implementations)는 다음 표에 나타난 대로 다양한 XML 표현을 감싼다.

Result 구현체 XML 표현을 감싼다
DOMResult org.w3c.dom.Node
SAXResult org.xml.sax.ContentHandler
StreamResult java.io.File, java.io.OutputStream, or java.io.Writer






Note
marshal() 메서드가 첫 파라미터로 평범한 객체를 받기는 하지만 대부분의 Marshaller 구현체는 임의의 객체들을 다룰 수는 없다. 대신에 객체 클래스는 매핑 파일에서 매핑되거나 어노테이션으로 표시되거나 마샬러와 등록되거나 공통적인 기반 클래스를 가져야 한다. 이것을 다루는 O/X 기술을 어떻게 선택해야 하는지는 이번 장의 후반 섹션들을 참고해라.




15.2.2 언마샬러
Marshaller와 유사하게 org.springframework.oxm.Unmarshaller 인터페이스가 있다.

public interface Unmarshaller {
  /**
   * Unmarshals the given provided Source into an object graph.
   */
  Object unmarshal(Source source)
    throws XmlMappingException, IOException;
}

이 인터페이스도 주어진 javax.xml.transform.Source (XML 입력 추상화)를 읽어서 읽어들인 객체를 반환하는 하나의 메서드를 가진다. 결과에 따라 Source는 세개의 구현체를 가진 태깅인터페이스이다. 각각은 다음 표에 나온 여러가지 XML 표현을 감싼다.

Source 구현체 XML 표현을 감싼다
DOMSource org.w3c.dom.Node
SAXSource org.xml.sax.InputSource와 org.xml.sax.XMLReader
StreamSource java.io.File, java.io.InputStream, java.io.Reader






두 개의 분리된 마샬링 인터페이스(Marshaller와 Unmarshaller)이 있기는 하지만 이 둘을 하나의 클래스에 구현한 Spring-WS에서 모든 구현체가 있다. 즉, 마샬러 클래스를 연결하고 이를 applicationContext.xml에서 마살러와 언마살러 둘 다로 참조할 수 있다.


15.2.3 XmlMappingException
스프링은 의존하는 O/X 매핑도구의 예외를 루트 예외가 XmlMappingException인 자신만의 예외 계층으로 변환한다. 기대하는 대로 이러한 런타임 예외는 원래의 예외를 감싸기 때문에 잃어버리는 정보는 없다.

추가적으로 MarshallingFailureException와 UnmarshallingFailureException는 의존하는 O/X 매핑 도구가 마샬링 작업과 언마샬링 작업을 구분하지 않더라도 마살링 작업과 언마샬링 작업을 구분할 수 있게 한다.

O/X 매핑 예외계층은 다음 그림에 나와있다.

O/X 매핑 예외 계층

O/X 매핑 예외 계층



15.3 마샬러(Marshaller)와 언마샬러(Unmarshaller)의 사용
스프링의 OXM을 다양한 상황에 사용할 수 있다. 다음 예제에서 XML 파일로 스프링이 관리하는 어플리케이션의 설정을 마샬링하는데 스프링의 OXM을 사용할 것이다. 이 설정을 표현하는데 간단한 JavaBean을 사용할 것이다.

public class Settings {
  private boolean fooEnabled;

  public boolean isFooEnabled() {
    return fooEnabled;
  }

  public void setFooEnabled(boolean fooEnabled) {
    this.fooEnabled = fooEnabled;
  }
}

어플리케이션 클래스는 어플리케이션의 설정을 저장하는데 이 빈을 사용한다. 클래스는 메인 메서드외에 두 개의 메서드를 가진다. saveSettings()는 settings.xml라는 파일에 설정 빈을 저장하고 loadSettings()는 이러한 설정을 다시 로드한다. main() 메서드는 스프링의 어플리케이션 컨텍스트를 생성하고 이 두 메서드를 호출한다.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class Application {
  private static final String FILE_NAME = "settings.xml";
  private Settings settings = new Settings();
  private Marshaller marshaller;
  private Unmarshaller unmarshaller;

  public void setMarshaller(Marshaller marshaller) {
    this.marshaller = marshaller;
  }

  public void setUnmarshaller(Unmarshaller unmarshaller) {
    this.unmarshaller = unmarshaller;
  }

  public void saveSettings() throws IOException {
    FileOutputStream os = null;
    try {
      os = new FileOutputStream(FILE_NAME);
      this.marshaller.marshal(settings, new StreamResult(os));
    } finally {
      if (os != null) {
        os.close();
      }
    }
  }

  public void loadSettings() throws IOException {
    FileInputStream is = null;
    try {
      is = new FileInputStream(FILE_NAME);
      this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
    } finally {
      if (is != null) {
        is.close();
      }
    }
  }

  public static void main(String[] args) throws IOException {
    ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    Application application = (Application) appContext.getBean("application");
    application.saveSettings();
    application.loadSettings();
  }
}

Application에는 marshaller와 unmarshaller 프로퍼티가 둘 다 설정되어야 한다. 다음의 applicationContext.xml를 사용해서 이 작업을 할 수 있다.

<beans>
  <bean id="application" class="Application">
    <property name="marshaller" ref="castorMarshaller" />
    <property name="unmarshaller" ref="castorMarshaller" />
  </bean>
  <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>

이 어플리케이션 컨텍스트는 Castor를 사용하지만 이 장의 뒷부분에서 설명하는 다른 마샬러 인스턴스 중 어떤 것이라도 사용할 수 있다. Castor는 기본적으로 더이상의 어떤 설정도 필요로 하지 않기 때문에 빈 정의가 훨씬 간단하다. 또한 CastorMarshaller는 Marshaller와 Unmarshaller를 모두 구현하고 있으므로 어플리케이션의 marshaller와 unmarshaller 모두에서 castorMarshaller 빈을 참조할 수 있다.

이 예제 어플리케이션은 다음의 settings.xml 파일을 만든다.

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>


15.4 XML 스키마 기반의 설정
마살러를 OXM 네임스페이스의 태그를 사용해서 더욱 간결하게 설정할 수 있다. 이러한 태그를 사용하려면 우선 XML 설정파일의 앞부분에 적절한 스키마를 참조해야 한다. 다음은 'oxm'과 관련된 부분이다.

<?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:oxm="http://www.springframework.org/schema/oxm"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/oxm
    http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

지금은 다음의 태그를 사용할 수 있다.

  • jaxb2-marshaller
  • xmlbeans-marshaller
  • jibx-marshaller
각각의 마살러 부분에서 각 태그를 설명할 것이다. 예제로 보자면 JAXB2 마샬러를 설정하는 방법은 다음과 같을 것이다.

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>


15.5 JAXB
JAXB 바인딩 컴파일러는 W3C XML 스키마를 하나 이상의 자바 클래스, jaxb.properties 파일, 어쩌면 몇몇 리소스 파일들로 변환한다. JAXB도 어노테이션이 붙은 자바 클래스에서 스키마를 생성하는 방법을 제공한다.

스프링은 XML 마샬링 전략으로 JAXB 2.0 API를 지원한다. 다음의 Marshaller와 Unmarshaller는 Section 15.2, “마살러(Marshaller)와 언마샬러(Unmarshaller)”에서 설명한다. 여기에 상응하는 통합 틀래스들은 org.springframework.oxm.jaxb 패키지에 있다.


15.5.1 Jaxb2Marshaller
Jaxb2Marshaller 클래스는 스프링의 Marshaller와 Unmarshaller를 모두 구현하고 있다. Jaxb2Marshaller 클래스가 동작하려면 contextPath 프로퍼티로 설정할 수 있는 컨텍스트 경로가 필요하다. 컨텍스트 경로는 스키마로 만들어낸 클래스를 포함하고 있는 자바 패키지명을 콜론(:)으로 구분한 목록이다. Jaxb2Marshaller 클래스는 마샬러가 지원해야 하는 클래스들의 배열을 설정할 수 있는 classesToBeBound 프로퍼티도 제공한다. 스키마 유효성확인은 다음과 같이 빈에 하나 이상의 스키마 리소스를 지정해서 수행한다.

<beans>
  <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
      <list>
        <value>org.springframework.oxm.jaxb.Flight</value>
        <value>org.springframework.oxm.jaxb.Flights</value>
      </list>
    </property>
    <property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
  </bean>
  ...
</beans>


15.5.1.1 XML 스키마기반의 설정
jaxb2-marshaller 태그는 org.springframework.oxm.jaxb.Jaxb2Marshaller를 설정한다. 다음은 그 예제이다.

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

아니면 class-to-be-bound 자식태그로 바인딩해야 할 클래스의 목록을 마샬러에 제공할 수 있다.

<oxm:jaxb2-marshaller id="marshaller">
  <oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
  <oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
  ...
</oxm:jaxb2-marshaller>

사용할 수 있는 속성은 다음과 같다.

속성 설명 필수여부
id 마샬러의 아이디 필수아님
contextPath JAXB 컨텍스트 경로 필수아님






15.6 Castor
Castor XML 매핑은 오픈소스 XML 바인딩 프레임워크이다. Castor XML 매핑은 자바 객체모델에 있는 데이터를 XML 문서로 변환하거나 그 반대로 변환할 수 있게 한다. 기본적으로 Castor XML 매핑은 다른 어떤 설정도 필요없지만 Castor의 동작을 더 세밀하게 제어하려면 매핑파일을 사용해야 한다.

Castor에 대한 자세한 내용은 Castor 웹사이트를 참고해라. 스프링 통합 클래스는 org.springframework.oxm.castor 패키지에 있다.


15.6.1 CastorMarshaller
JAXB로 작업할 때처럼 CastorMarshaller는 Marshaller와 Unmarshaller 인터페이스를 모두 구현하고 있다. 다음과 같이 연결할 수 있다.

<beans>
  <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
  ...
</beans>


15.6.2 Mapping
Castor의 기본 마샬링 동작에 의존할 수도 있지만 그 이상의 제어를 해야할 것이다. 이는 Castor 매핑 파일을 사용해서 할 수 있다. 자세한 내용은 Castor XML Mapping을 참고해라.

아래에서 클래스패스 리소스를 가리키는 mappingLocation 리소스 프로퍼티를 사용해서 매핑을 설정할 수 있다.

<beans>
  <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
    <property name="mappingLocation" value="classpath:mapping.xml" />
  </bean>
</beans>


15.7 XMLBeans
XMLBeans은 XML 스키마를 완전히 지원하는 XML 바인딩 도구로 정확한 전체 XML Infoset을 제공한다. XMLBeans는 다른 대부분의 O/X 매핑 프레임워크들이 취하는 XML 스키마에서 생성한 모든 클래스들은 XmlObject로 모두 만들어지고 그 안에 XML 바인딩 정보가 들어있는 것과는 다른 접근을 취한다.

XMLBeans의 자세한 정보는 XMLBeans 웹사이트를 참고해라. Spring-WS 통합 클래스들은 org.springframework.oxm.xmlbeans 패키지에 있다.


15.7.1 XmlBeansMarshaller
XmlBeansMarshaller는 Marshaller와 Unmarshaller를 모두 구현하고 있다. 다음과 같이 설정할 수 있다.

<beans>
  <bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
  ...
</beans>

Note
XmlBeansMarshaller는 모든 java.lang.Object가 아니라 XmlObject 타입의 객체들만 마샬링할 수 있다.



15.7.1.1 XML 스키마 기반의 설정
xmlbeans-marshaller 태그는 org.springframework.oxm.xmlbeans.XmlBeansMarshaller를 설정한다. 다음은 그 예제이다.

<oxm:xmlbeans-marshaller id="marshaller"/>

사용할 수 있는 속성은 다음과 같다.
속성 설명 필수여부
id 마샬러의 아이디 필수아님
options 이 마샬러에 사용해야 하는 XmlOptions의 빈 이름. 보통은 XmlOptionsFactoryBean 정의이다. 필수아님









15.8 JiBX
JiBX 프레임워크는 JDO가 ORM에 제공하는 것과 유사한 해결책을 제공한다. 즉, 바인딩 정의가 자바 객체를 XML로 변환하거나 XML을 자바 객체로 변환하는 방법에 대한 규칙을 정의한다. 클래스의 바인딩과 컴파일을 준비한 후에 JiBX 바인딩 컴파일러는 클래스의 인스턴스를 XML로 변환하거나 XML을 클래스의 인스턴스로 변하는 작업을 다루는 코드를 추가해서 클래스 파일을 개선시킨다.

JiBX에 대한 자세한 내용은 JiBX 웹사이트를 참고해라. 스프링 통합 클래스들은 org.springframework.oxm.jibx 패키지에 있다.


15.8.1 JibxMarshaller
JibxMarshaller 클래스는 Marshaller와 Unmarshaller 인터페이스를 모두 구현하고 있다. JibxMarshaller 클래스가 동작하려면 targetClass 프로퍼티를 사용해서 설정할 수 있는 마샬링할 클래스의 이름이 필요하다. 선택적으로 bindingName 프로퍼티를 사용해서 바인딩 이름을 설정할 수 있다. 다음 예제에서는 Flights 클래스를 바인딩한다.

<beans>
  <bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
    <property name="targetClass">org.springframework.oxm.jibx.Flights</property>
  </bean>
  ...

JibxMarshaller는 하나의 클래스에 설정한다. 여러 클래스를 마샬링하고 싶다면 다른 targetClass 프로퍼티 값을 가진 JibxMarshaller를 여러 개 설정해야 한다.


15.8.1.1 XML 스키마에 기반한 설정
jibx-marshaller 태그는 org.springframework.oxm.jibx.JibxMarshaller를 설정한다. 다음은 그 예제이다.

<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>

사용할 수 있는 속성은 다음과 같다.
속성 설명 필수여부
id 마샬러의 아이디 필수아님
target-class 이 마샬러의 대상 클래스 필수
bindingName 이 마샬러가 사용하는 바인딩 이름 필수아님







15.9 XStream
XStream는 객체를 XML로 직렬화하거나 그 반대로 하는 간단한 라이브러리이다. XStream는 어떤 매핑도 필요로하지 않고 깔끔한 XML을 생성한다.

XStream에 대한 자세한 정보는 XStream 웹사이트를 참고해라. 스프링 통합 클래스들은 org.springframework.oxm.xstream 패키지에 있다.


15.9.1 XStreamMarshaller
XStreamMarshaller는 어떤 설정도 필요로 하지 않고 어플리케이션 컨텍스트에서 직접 설정할 수 있다. XML을 추가로 커스터마이징하기 위해 클래스에 매핑된 문자열 별칭으로 이루어진 별칭 맵(alias map)을 설정할 수 있다.

<beans>
  <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
    <property name="aliases">
      <props>
        <prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
      </props>
    </property>
  </bean>
  ...
</beans>

Warning
기본적으로 XStream은 보안허점이 될 수도 있는 언마샬링되는 임의의 클래스들을 허용한다. 그래서 다음과 같이 XStreamMarshaller에 supportedClasses 프로퍼티를 설정하기를 권장한다.


<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
  <property name="supportedClasses" value="org.springframework.oxm.xstream.Flight"/>
  ...
</bean>

이는 등록된 클래스들만 언마샬링할 수 있다는 것을 보장할 것이다.

추가적으로 지원하는 클래스만 언마샬링되어야 한다는 것을 보장하기위해 커스텀 컨버터를 등록할 수 있다.

Note
XStream은 XML 직렬화 라이브러리이지 데이터 바인딩 라이브러리가 아니다. 그러므로 XStream은 제한된 네임스페이스를 지원한다. 그러므로 웹서비스내에서 사용하기에는 별로 알맞지 않다.

2013/01/24 07:08 2013/01/24 07:08