메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Castor를 이용한 XML 데이터 바인딩

한빛미디어

|

2002-03-12

|

by HANBIT

12,817

저자: 다이온 알마에르, 역 김대곤

이 기사에서는 XML 데이터 바인딩 API를 이용해 XML 파일에서 자료를 읽어오고, 저장하는 작업을 수행할 것이다. 이와 같은 작업을 수행하려고 할 때 뇌리에 스치는 의문점은 "왜 이런 작업을 수행하는가?, SAX[1]나 DOM[2]를 사용하지 않고 다른 API를 사용하는 이유는 무엇인가?" 하는 점이다. 그 이유는 자바를 사용해 XML을 다루는 간단한 작업 수행을 하려면 너무 많은 양의 코드를 작성해야 되고 그 작업량으로 인해 압도되어 작업을 그만두게 되기 때문이다.

필자는 JDOM 프로젝트 사이트에서 우연히 그동안 찾고자 노력했던 것을 발견하였다. DOM은 특정 언어에 종속되지 않도록 작성되었기 때문에 전혀 자바같이 느껴지지 않는다. JDOM 프로젝트는 현재의 DOM를 사용하여 놀라운 성과를 이루어냈고, 그것은 필자가 자바 프로그램안에서 DOM를 사용하고자 하는 방법이다.

특정 어플리케이션의 경우, 데이터를 "파싱"하는 것에 대한 생각조차 하고싶지 않다. 그저 자바 객체를 사용하고, 그것을 저장하거나 공유하기 위해 XML형태로 저장할 수만 있다면 좋겠다. XML 데이터 바인딩은 파싱을 생각하지 않고 자바와 XML를 연결하는 작업을 수행할 수 있도록 해 준다. 이러한 작업을 수행할 수 있게 해 주는 몇몇 프레임워크가 있지만 여기서는 Exolab의 오픈 소스 프레임워크인 Castor를 사용할 것이다. Castor는 자바 객체, XML 문서, SQL 테이블, LDAP 디렉토리를 연결해 주는 프레임워크이다. Castor 프로젝트의 일부인 Castor XML를 사용해 직접 작업하여 보자.

여기서는 주소록 XML 문서 개발을 통하여 기존의 DOM/SAX과 Castor XML의 차이점을 살펴 보게 될 것이다. XML 데이터 바인딩 프레임워크을 통해 주소록 XML문서를 생성, 조회, 변경해보자.

이 기사에 사용된 소스코드는 Java2 플랫폼을 지원하는 모든 JVM(자바 가상 머신)에서 실행된다.

여기서 수행할 두 가지 작업은 다음과 같다.
  1. 연락처를 이용한 간단한 데이터 바인딩의 생성, 수정, 조회
  2. 주소록 데이터 바인딩의 개발.
간단한 데이터 바인딩의 생성/수정/조회

이제 주소록에 포함될 연락처를 만들어 보자. 연락처는 XML문서 형태와 자바 객체 형태를 넘나들게 된다.
  • XML형태의 연락처 생성하기
  • 자바 객체 형태의 연락처 생성하기
  • 연락처 JavaBean를 생성하기 위해 Castor XML를 사용하여 XML문서를 읽기.
  • Castor XML를 사용하여 연락처 XML문서 생성하기
  • Castor XML를 사용하여 연락처를 수정하기.
단계 1 : XML형태의 연락처 생성하기

일단 XML형태의 연락처를 만들자.


  Michael Owen
  
222 Bazza Lane, Liverpool, MN
111-222-3333 michael@owen.com 720.111.2222 111.222.3333
이 기사에서 제공되는 소스코드를 다운로드 받고 싶다면 여기를 클릭해라. 코드에는 인명 및 연락처 디렉토리 뿐만 아니라 castor.properties 파일, readme 파일도 포함하고 있다. 이 코드로 작업하려면 caster.jar 또는 castor-xml.jar 파일도 있어야 한다.
단계 2 : 자바 객체 형태의 연락처 생성하기

이전 단계에서 XML형태로 연락처 정의를 했기 때문에 이러한 정의에 대응되는 자바 객체를 생성해야 한다. 쉽게 말해 JavaBean의 규칙을 따라 XML에 정의된 각 요소(element)의 이름과 이에 대응되는 get, set 메소드를 만들자. 요소의 이름이 name이라면, 이에 대응되는 자바 객체의 메소드는 getNamesetName이 된다. 하이픈(-)을 사용한 경우에는 하이픈 다음에 오는 첫 문자를 대문자로 표시하도록 하겠다. 따라서 home-phone에 대응되는 메소드는 getHomePhone()가 된다. 이러한 규칙을 염두에 두고 Person.java를 살펴보자.

public class Person {
  private String name;
  private String address;
  private String ssn;
  private String email;
  private String homePhone;
  private String workPhone;

// -- allows us to create a Person via the constructor
public Person(String name, String address, String ssn, 
     String email, String homePhone, String workPhone) {
    this.name = name;
    this.address = address;
    this.ssn = ssn;
    this.email = email;
    this.homePhone = homePhone;
    this.workPhone = workPhone;
  }

// -- used by the data-binding framework
  public Person() { }

// -- accessors
  public String getName() { return name; }

  public String getAddress() { return address; }

  public String getSsn() { return ssn; }

  public String getEmail() { return email; }

  public String getHomePhone() { return homePhone; }

  public String getWorkPhone() { return workPhone; }

// -- mutators
  public void setName(String name) { this.name = name; }

  public void setAddress(String address) {
    this.address = address;
  }

  public void setSsn(String ssn) { this.ssn = ssn; }

  public void setEmail(String email) { this.email = email;  }

  public void setHomePhone(String homePhone) {
    this.homePhone = homePhone;
  }

  public void setWorkPhone(String workPhone) {
    this.workPhone = workPhone;
  }
}
단계 3 : Castor XML를 사용하여 JavaBean 생성하기

지금까지는 단순한 XML 문서, 간단한 JavaBean을 다루는 것과 같은 아주 쉬운 작업이었다. 이제부터 Castor를 사용하여 단계 1에서 만들었던 XML를 파일을 읽어서 JavaBean(연락처 객체)을 생성할 것이다. 여기에서 프레임워크의 놀라운 능력을 보게 될 것이다. 개발자에게는 일반적인 JavaBean을 사용하는 것처럼 느껴지겠지만 XML를 읽어 객체를 생성하는 작업이므로 일반적인 JavaBean을 사용과는 확실히 구별된다.

아래의 코드는 XML를 읽어 JavaBean를 생성하고 연락처 정보를 보여주는 코드이다.

import org.exolab.castor.xml.*;
import java.io.FileReader;

public class ReadPerson {
  public static void main(String args[])  {
    try {
     Person person = (Person)  
             Unmarshaller.unmarshal(Person.class,
               new FileReader("person.xml"));
     System.out.println("Person Attributes");
     System.out.println("-----------------");
     System.out.println("Name: " + person.getName() );
     System.out.println("Address: " + person.getAddress() );
     System.out.println("SSN: " + person.getSsn() );
     System.out.println("Email: " + person.getEmail() );
     System.out.println("Home Phone: " + 
                             person.getHomePhone() );
     System.out.println("Work Phone: " +  
                             person.getWorkPhone() );
    } catch (Exception e) {
      System.out.println( e );
    }
  }
}
Java & XML, 2nd Edition
이러한 작업의 비밀은 Unmarshaller 클래스 안에 있으며 이 예제에서는 static method unmarshal()을 다루었다. 우리는 단순하게 읽어들어야 할 XML파일과 생성해야 할 객체를 지정해 주기만 하면 된다. 그러면 프레임워크는 자동적으로 XML 문서를 읽어 단계 2에서 언급했던 규칙에 따라 요소에 대응되는 set()메소드를 사용해 생성된 자바 객체에 값을 할당한다. 그 후에는 원하는 객체의 메소드를 호출할 수 있다. SAX의 이벤트 헨들러를 사용할 필요도 없고, DOM 트리를 구성할 필요도 없다. 물론 XML를 사용하고 있는지는 알 필요도 없다.

단계 4 : Castor XML를 사용하여 연락처 XML 문서 생성하기

지금까지는 XML를 파일을 읽어서 자바 객체를 생성했다. 하지만 반대로 자바 객체를 단순히 파일로 저장해서 XML 파일을 생성할 수도 있다. DOM 트리를 파일로 저장하는 것보다 훨씬 간단하고 편리하다.

다음은 자바 객체 연락처의 XML 형태인 bob_person.xml 파일을 생성하는 코드이다.

import org.exolab.castor.xml.*;
import java.io.FileWriter;

public class CreatePerson {
  public static void main(String args[]) {
  try {
// -- create a person to work with
    Person person = new Person("Bob Harris", 
     "123 Foo Street", "222-222-2222", 
      "bob@harris.org", "(123) 123-1234",
      "(123) 123-1234");

// -- marshal the person object out as a 
    FileWriter file = new FileWriter("bob_person.xml");
    Marshaller.marshal(person, file);
    file.close();
  } catch (Exception e) {
    System.out.println( e );
  }
  }
}
위 코드에서는 생성자에 초기값을 넘겨 연락처 객체를 생성하였다. 그런 후, Marshaller 클래스를 사용하여 생성된 연락처 객체를 bob_person.xml라는 이름을 가진 파일로 XML문서를 저장하였다.

단계 5 : Castor XML을 사용하여 연락처 수정하기

지금까지는 XML파일로 된 연락처를 읽은 후, 연락처 객체를 XML파일로 저장하는 방법에 대해 살펴보았다. 이제부터는 이와 같은 두 가지 방법을 함께 사용하여 기존 XML형태의 연락처를 수정할 수 있다.

아래 코드는 person.xml를 읽어 객체를 생성하고, 생성된 객체의 이름을 변경하여 객체를 다시 XML파일로 저장하는 작업을 보여주고 있다.


import org.exolab.castor.xml.*; 
import java.io.FileWriter; 
import java.io.FileReader; 
 
public class ModifyPerson { 
  public static void main(String args[]) { 
  try { 
// -- read in the person 
    Person person = (Person)  
      Unmarshaller.unmarshal(Person.class,  
        new FileReader("person.xml")); 
// -- change the name 
    person.setName("David Beckham"); 
 
// -- marshal the changed person back to disk 
    FileWriter file = new FileWriter("person.xml"); 
    Marshaller.marshal(person, file); 
    file.close(); 
  } catch (Exception e) { 
    System.out.println( e ); 
    } 
  } 
}
이상에서 살펴본 것처럼 연락처 XML파일을 수정할 때 XML관련 API를 사용할 필요가 전혀 없다. 이제 주소록을 만드는 본격적인 작업으로 넘어가 보자.

주소록을 위한 데이터 바인딩 작성

여기서는 주소록을 연락처의 집합으로 정의한다. 주소록을 위한 데이터 바인딩 작성을 위해서는 데이터 바인딩 프레임워크를 위한 매핑 정의가 필요하다. 여기서는 주소록을 Person 객체의 java.util.Collection로 설정하는 방법과 매핑 속성에 대해 배우게 될 것이다.

여기서는 다음과 같은 과정을 수행해 나갈 것이다.
  1. XML 파일 형태의 주소록 작성.
  2. 주소록을 표현하는 주소록 자바 객체 작성.
  3. Castor XML이 읽기 및 저장을 수행할 수 있도록 mapping.xml 만들기
  4. Castor XML를 사용하여 주소록 정보 출력하기.
단계 1 : XML 파일 형태의 주소록 작성

주소록은 이미 정의했던 여러 연락처들을 태그 안에 포함시킨 형태이다.
 
 
   
    
23 Whistlestop Ave
111-222-3333 roykeane@manutd.com 720.111.2222 111.222.3333
123 Foobar Lane
222-333-444 juanveron@manutd.com 720.111.2222 111.222.3333
단계 2 : 주소록을 표현하는 주소록 자바 객체 작성

XML로 주소록을 정의 하였기 때문에 이것을 표현할 자바 객체를 해야 한다. 주소록을 표현하는 AddressBook 객체는 연락처 객체(Person)의 java.util.List를 가진다.
 
import java.util.List;
import java.util.ArrayList;

public class Addressbook {
  private String addressBookName;
  private List   persons = new ArrayList();

  public Addressbook() { }

// -- manipulate the List of Person objects
  public void addPerson(Person person) {
    persons.add(person);
  }

  public List getPersons() {
    return persons;
  }

// -- manipulate the name of the address book
  public String getName() {
    return addressBookName;
  }

  public void setName(String name) {
    this.addressBookName = name;
  }
}
주소록 작업시 사용할 프로그래밍 인터페이스가 작성되고, 주소록의 XML형태가 정의 되었으니 이제 이 둘을 함께 연결할 필요가 있다. 연결해주는 작업은 mapping.xml 파일이 담당한다.

단계 3 : Castor XML이 읽기 및 저장을 수행할 수 있도록 mapping.xml 만들기

연락처 예제에서는 JavaBean 정의규칙에 근거하여 Castor 프레임워크가 작동할 수 있었기 때문에 매핑 파일을 만들 필요가 없었다.

그러나 이제 매핑 파일을 사용하여 다음과 같은 정보를 Castor 프레임워크에 제공해야 한다.
  • 주소록은 연락처 객체의 Collection를 가짐.
  • 연락처 요소가 Name이라는 속성을 가지도록 변경.
  • 속성을 사용하여 주소록에 이름을 부여함
다음은 매핑 파일인 mapping.xml이다.
 
 
 
 
 
A mapping file for our Address Book application 
 
 
   
     
   
   
   
   
   
   
 
 
 
   
     
   
   
 
 

매핑 파일을 살펴보면 매핑이 자바 클래스 관점에서 작성되었다는 사실을 알 수 있다. 우리는 Person.javaAddress.java를 작성하였으며 매핑 파일은 각 클래스를 설명하는 요소를 가지고 있다.

각 class 요소는 field 요소를 가지고 있다. 필드 요소들은 Castor 프레임워크에 필드 이름, 타입, 요소/속성 여부, 집합 객체인지 단일 객체인지를 알려준다.

아래 보이는 mapping.xml의 일부분은 name이라는 이름을 가진 String타입의 속성을 가졌음을 나타내고 있다. 이 부분을 통해 Castor 프레임웍은 XML 문서에
가 있다는 사실을 알게 된다.
 

    

다음 스니펫은 Castor 프레임워크가 연락처의 Collection를 사용할 수 있도록 한다. 우리의 경우는 java.util.List이다.


이 매핑 파일에 더욱 복잡한 내용을 정의할 수는 있지만 이렇게 함으로서 주제에서 벗어날 우려도 있기 때문에 이 정도만 언급하기로 한다. mapping 파일에 대한 더 자세한 사항은 Castor 웹 사이트를 방문해 보길 바란다.

단계 4 : Castor XML를 사용하여 주소록 정보 출력하기

우리는 주소록의 출력하기 위해서 address.xml 파일을 읽을 것이다. 앞에서 본 person.xml를 읽어오는 간단한 작업과는 달리 매핑파일을 읽어 들여야 한다.

다음은 ViewAddressBook.java 소스이다.
 
import org.exolab.castor.xml.*;
import org.exolab.castor.mapping.*;

import java.io.FileReader;
import java.util.List;
import java.util.Iterator;

public class ViewAddressbook {
  public static void main(String args[]) {
    try {
     // -- Load a mapping file
     Mapping mapping = new Mapping();
     mapping.loadMapping("mapping.xml");

     Unmarshaller un = new Unmarshaller(Addressbook.class);
     un.setMapping( mapping );

     // -- Read in the Addressbook using the mapping
     FileReader in = new FileReader("addressbook.xml");
     Addressbook book = (Addressbook) un.unmarshal(in);
     in.close();

     // -- Display the addressbook
     System.out.println( book.getName() );

     List persons = book.getPersons();
     Iterator iter = persons.iterator();

     while ( iter.hasNext() ) {
       Person person = (Person) iter.next();

       System.out.println("\n" + person.getName() );
       System.out.println("-----------------------------");
       System.out.println("Address = "+ person.getAddress());
         System.out.println("SSN = " + person.getSsn() );
       System.out.println("Home Phone = " +  
                             person.getHomePhone() );
       }
    } catch (Exception e) {
      System.out.println( e );
    }
  }
}
앞에서 작성했던 연락처 예제와 실제적인 차이점은 더 이상 static 메소드인 Unmarshaller.unmarshal()를 사용할 필요가 없다는 것이다. 이제는 Unmarshaller 객체를 생성하고 기존에 만든 mapping.xml를 사용하여 만든 Mapping() 객체를 Unmarshaller 객체에 메시지로 넘겨주기만 하면 된다.

Mapping mapping = new Mapping();
mapping.loadMapping("mapping.xml");

Unmarshaller un = new Unmarshaller(Addressbook.class);
un.setMapping( mapping );
결론

XML를 사용하여 작업하기 위해서 복잡한 DOM, SAX, JAXP등 다른 모든 TLA(세자리 약어)들을 배울 필요가 없다는 사실을 보았다. CastorXML은 XML과 자바 객체를 연결하는 간단하면서도 강력한 메커니즘을 제공한다. 다이온 알마에르(Dion Almaer)는 EJB/J2EE와 B2B 기술의 교육 분야의 선도 기업이며 TheServerSide.com의 J2EE의 커뮤니티를 후원하고 있는 미들웨어 회사(www.middleware-company.com)의 책임 기술자이다.
[1] SAX : DOM과 마찬가지로 XML 파싱을 위해 만들어진 표준 인터페이스 (이벤트 기반의 API 제공)
[2] DOM : W3C에서 제안한 언어 및 플랫폼이 중립적으로 기술된 인터페이스의 표준 (Tree 기반의 API 제공)
[3] Castor API를 사용하는 단계에서는 Castor의 API만으로 실행되지 않는다. Apache의 Xerces가 필요하다.
TAG :
댓글 입력
자료실

최근 본 책0