본문 바로가기

프로그래머로 살아가기/Java

JAXB를 사용하여 Java Object를 한번에 XML로 변환하기


Java Object를 XML로 변환하고자 할때 과거에는 포맷에 맞춰서 XML을 일일이 출력해주는 방식도 사용을 했었다.

그렇지만 굉장히 노가다이고, 짜증나는 작업이 아닐수 없다. 

이런 노가다를 줄이기 위하여 Java Object를 XML로 변환해주는 많은 툴들이 나와있다.

그중에 가장 많이 사용되는 것이 JAXB(Java Architecture for XML Binding) 이다.

Using JAXB

기본적인 지식을 얻고 싶다면 아래의 주소에서 확인을 하자.
http://java.sun.com/developer/technicalArticles/WebServices/jaxb/


Maven을 사용하고 있다면 Pom.xml에 Dependency를 추가하여 필요한 라이브러리를 다운받자. 

         <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.0.5</version>
        </dependency>


Java annotation을 사용하여 편리하게 어떤 내용을 XML에 포함 시킬것인가 말것인가, 그리고 어떤 이름으로 XML에 표현할 것인가를 나타낼 수 있다.


아래 예제 소스는 Hibernate Entity class로써 DB table에 매핑되는 데이터를 나타낸다.

굵은 글쓰로 나타낸것이 JAXB에서 참조하는 annotation이다.

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;


@Entity
@Table(name="vct")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Vct extends AbstractEntity<Long>{
   
    /**
     *
     */
    private static final long serialVersionUID = 8595404797996134818L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
   
    @ManyToOne(targetEntity = VctInfo.class, optional = false)
    @JoinColumn(name = "vctinfo_id", nullable = false, updatable = false)
    @org.hibernate.annotations.ForeignKey(name = "fk_vct_vctinfo")
    private VctInfo vctinfo;
   
    @ManyToOne(targetEntity = Uct.class, optional = false)
    @JoinColumn(name = "uct_id", nullable = false, updatable = false)
    @org.hibernate.annotations.ForeignKey(name = "fk_vct_uct")
    private Uct uct;
   
    @Column(name = "name", length = 100, nullable = false)
    private String name;
   
    @Column(name="vct_parentid" , nullable=true)
    private Long vctParentId;
   
    @Column(name="sort_order" , nullable=false)
    private Integer sortOrder;
   
    @Column(name="visible" , nullable=false)
    private CategoryVisible visible;
   
    @Column(name="moved" , nullable=false)
    private CategoryMoved moved;
   
    @Column(name="shortcut" , nullable=false)
    private CategoryType shortcut;
   
    @Column(name="hierachy" , length=1024, nullable=false)
    private String hierachy;
   
    @Column(name="hierachyStr" , length=1024, nullable=false)
    private String hierachyStr;   

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public VctInfo getVctinfo() {
        return vctinfo;
    }

    public void setVctinfo(VctInfo vctinfo) {
        this.vctinfo = vctinfo;
    }

    public Uct getUct() {
        return uct;
    }

    public void setUct(Uct uct) {
        this.uct = uct;
    }
   
    public String getName() {
        return name;
    }

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

    public Long getVctParentId() {
        return vctParentId;
    }

    public void setVctParentId(Long vctParentId) {
        this.vctParentId = vctParentId;
    }

    public Integer getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(Integer sortOrder) {
        this.sortOrder = sortOrder;
    }

    public CategoryVisible getVisible() {
        return visible;
    }

    public void setVisible(CategoryVisible visible) {
        this.visible = visible;
    }

    public CategoryMoved getMoved() {
        return moved;
    }

    public void setMoved(CategoryMoved moved) {
        this.moved = moved;
    }

    public CategoryType getShortcut() {
        return shortcut;
    }

    public void setShortcut(CategoryType shortcut) {
        this.shortcut = shortcut;
    }

    public String getHierachy() {
        return hierachy;
    }

    public void setHierachy(String hierachy) {
        this.hierachy = hierachy;
    }
   
    public String getHierachyStr() {
        return hierachyStr;
    }

    public void setHierachyStr(String hierachyStr) {
        this.hierachyStr = hierachyStr;
    }

    @Override
    public boolean equals(final Object other) {
        if (!(other instanceof Vct))
            return false;
        Vct castOther = (Vct) other;
        return new EqualsBuilder().append(id, castOther.id).isEquals();
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("id", id).append("vctinfo",
                vctinfo).append("uct", uct).append("vctParentId", vctParentId)
                .append("sortOrder", sortOrder).append("visible", visible)
                .append("moved", moved).append("shortcut", shortcut).append(
                        "hierachy", hierachy).append("hierachyStr", hierachyStr).toString();
    }
}


이 Entity class를 XML로 변환하고 싶다고 한다면 다음과 같이 해주면 된다.

        JAXBContext context = JAXBContext.newInstance(Vct.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        m.marshal( vct, response.getWriter());

물론 vct에는 어떤 값이 들어있어야 한다.


이 Vct라는 class의 List값을 출력하고 싶을때는 다음과 같은 List용 class를 생성한다.

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "vcts")
@XmlAccessorType(XmlAccessType.FIELD)
public class VctList {

    @XmlElement(name = "vct")
    protected List<Vct> vcts;

    public List<Vct> getVctList() {
        if (vcts == null) {
            vcts = new ArrayList<Vct>();
        }
        return this.vcts;
    }

    public void setVctList(List<Vct> vcts) {
        this.vcts = vcts;
    }
}

VctList라는 class는 Vct의 리스트를 가지고 있는 class이고,

annotation으로 vcts라는 이름으로 XML의 root element를 만든다고 나타냈다.

아래의 class는 Spring의 View interface를 구현하여 웹상에서 xml을 바로 볼수 있게 해줄 목적으로 만들었다.

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.springframework.web.servlet.View;


public class VctXmlView implements View {

    private Object modelKeyName;

    public VctXmlView(Object key) {
        modelKeyName = key;
    }

    @Override
    public String getContentType() {
        return "text/xml;charset=utf-8";
    }

    @SuppressWarnings("unchecked")
    @Override
    public void render(Map model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        if (model == null) {
            return;
        }
        response.setContentType(getContentType());
        List<Vct> vcts = (List<Vct>) model.get(modelKeyName);
        VctList vctList = new VctList();
        vctList.setVctList(vcts);

        if (vcts == null) {
            return;
        }

        JAXBContext context = JAXBContext.newInstance(VctList.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        m.marshal(vctList, response.getWriter());

    }
}

실행한 결과는 다음과 같다.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<vcts>
<vct>
<id>1</id>
<vctinfo>
<country>
<id>1</id>
<name>KR</name>
  </country>
<createUser>
<email></email>
<name></name>
<password></password>
<readLevel></readLevel>
<writeLevel></writeLevel>
  </createUser>
<createdAt>2009-05-18T15:05:51+09:00</createdAt>
<description></description>
<language>
<description>한국어</description>
<name>Ko</name>
</language>
            <name></name>
</vctinfo>
<uct>
<createUser>
<email></email>
<name>breeze</name>
<password></password>
                <readLevel>uctVct</readLevel>
<writeLevel>uctVct</writeLevel>
</createUser>
<createdAt>2009-05-14T14:28:10+09:00</createdAt>
<description></description>
<hierachy>6 7 8 9 11</hierachy>
            <hierachyStr></hierachyStr>
<name>itemshop</name>
<parentId>9</parentId>
</uct>
<name>아이템몰</name>
<sortOrder>1</sortOrder>
        <visible>show</visible>
<moved>notMoved</moved>
<shortcut>shortcut</shortcut>
<hierachy>1</hierachy>
<hierachyStr>아이템몰</hierachyStr>
</vct>
    <vct>
<id>2</id>
<vctinfo>
<country>
<id>1</id>
<name>KR</name>
</country>
            <createUser>
<email></email>
<name>breeze</name>
<password></password>
<readLevel>uctVct</readLevel>
<writeLevel>uctVct</writeLevel>
</createUser>
            <createdAt>2009-05-18T15:05:51+09:00</createdAt>
<description>Shop에서 사용할 VCT</description>
<language>
<description>한국어</description>
<name>Ko</name>
</language>
<name>Itene Shop</name>
        </vctinfo>
<uct>
<createUser>
<email></email>
<name>breeze</name>
<password></password>
<readLevel>uctVct</readLevel>
                <writeLevel>uctVct</writeLevel>
</createUser>
<createdAt>2009-05-19T16:23:26+09:00</createdAt>
<description>hair chage item</description>
<hierachy>6 7 8 9 11 20</hierachy>
<hierachyStr></hierachyStr>
            <name>Hair change</name>
<parentId>11</parentId>
</uct>
<name></name>
<vctParentId>1</vctParentId>
<sortOrder>1</sortOrder>
        <visible>show</visible>
<moved>notMoved</moved>
<shortcut>shortcut</shortcut>
<hierachy>1 2</hierachy>
<hierachyStr></hierachyStr>
</vct>
</vcts>