느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라
article thumbnail

스프링 핵심 기술 활용하기 챕터를 공부하고 있는데 해당 부분에 코드와 sql 분리시키기라는 기술적 분야를 보고 있다. 코드와 sql을 분리시킬경우 xml로 분리하는 경우만 생각하고 있었는데, 토비의 스프링에서는 JAXB라는 기술을 설명한다. 여기서 JAXB란 JAXB(Java Architecture for XML Binding)의 약자이다.

 

JAXB는 XML문서정보를 거의 동일한 구조의 오브젝트로 직접 매핑해준다. DOM은 XML정보를 마치 자바의 리플렉션 API를 사용해서 오브젝트를 조작하는 것처럼 간접적으로 접근해야 하는 불편함이 있다. 그에 비해 JAXB는 XML의 정보를 그대로 담고 있는 오브젝트 트리 구조로 만들어주기 때문에 XML 정보를 오브젝트처럼 다룰 수 있어 편리하다. 

 

JAXB API가 XML 과 Object를 매핑하는 과정

JAXB 테스트를 해보기 위해 다음의 sqlmap.xsd XML 스키마 파일을 만들어서 프로젝트의 루트단에 놓는다.

 

[sqlmap.xsd]

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
       targetNamespace="http://www.example.org/sqlmap"
       xmlns:tns="http://www.example.org/sqlmap"
       elementFormDefault="qualified">
       <element name="sqlmap">
              <complexType>
                     <sequence>
                           <element name="sql" maxOccurs="unbounded" type="tns:sqlType"></element>
                     </sequence>
              </complexType>
       </element>
       <complexType name="sqlType">
              <simpleContent>
                     <extension base="string">
                           <attribute name="key" use="required" type="string" />
                     </extension>
              </simpleContent>
       </complexType>
</schema>

파일을 만들었으면 파일이 있는 경로에서 아래의 명령어를 수행한다. 스키마 컴파일은 xjc라는 명령어로 수행하는데 xjc에 대한 약자에 대한 설명은 찾지 못하였으나 개인적으로 xml java compiler 정도의 약자일 듯 하다.

 

그리고 옵션들은 다음과 같은 의미를 갖는다. -p [패키지 경로] -d [디렉토리 경로]

xjc -p com.copocalypse.jaxb sqlmap.xsd -d src/main/java

즉, xjc -p [패키지경로] [xsd파일] -d [디렉토리경로] 의 명령어를 수행하면 된다.

 

 

결과 

xml 스키마에 맞춰서 자바파일들이 생성되었다. 이중 내가 설정한 파일에 맞춰 생성된 자바파일은 두개이다.

 

[Sqlmap.java]

package com.copocalypse.jaxb;
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;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "sql"
})
@XmlRootElement(name = "sqlmap")
public class Sqlmap {
    @XmlElement(required = true)
    protected List<SqlType> sql;
    public List<SqlType> getSql() {
        if (sql == null) {
            sql = new ArrayList<SqlType>();
        }
        return this.sql;
    }
}

 

[SqlType.java]

package com.copocalypse.jaxb;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "sqlType", propOrder = {
    "value"
})
public class SqlType {
    @XmlValue
    protected String value;
    @XmlAttribute(name = "key", required = true)
    protected String key;
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String value) {
        this.key = value;
    }
}

 

이제 JABX API를 사용해서 xml과 오브젝트의 매핑을 수행하기 위하여 테스트 코드를 작성하고자 한다. 매핑 클래스에 들어갈 데이터를 아래와 같이 작성한다.

 

[sqlmap.xml]

<?xml version="1.0" encoding="UTF-8"?>
<sqlmap xmlns="http://www.example.org/sqlmap"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.example.org/sqlmap ../../../../../sqlmap.xsd">
       
       <sql key="add">insert</sql>
       <sql key="get">select</sql>
       <sql key="delete">delete</sql>
</sqlmap>

 

데이터 작성이 끝났으면 다음과 같이 JUnit 테스트를 수행하여 테스트가 잘 수행되는지 확인할 수 있다.

[JabxTest.java]

package com.copocalypse.web.jaxb;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.junit.Test;

import com.copocalypse.jaxb.SqlType;
import com.copocalypse.jaxb.Sqlmap;

public class JabxTest {

    @Test
    public void readSqlMap() throws JAXBException {
        String contextPath = Sqlmap.class.getPackage().getName();
        JAXBContext context = JAXBContext.newInstance(contextPath);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        Sqlmap sqlmap = (Sqlmap) unmarshaller.unmarshal(getClass().getResourceAsStream("sqlmap.xml"));

        List<SqlType> list = sqlmap.getSql();
        
        assertThat(list.size(), is(3));
        assertThat(list.get(0).getKey(), is("add"));
        assertThat(list.get(0).getValue(), is("insert"));
        
        assertThat(list.get(1).getKey(), is("get"));
        assertThat(list.get(1).getValue(), is("select"));
        
        assertThat(list.get(2).getKey(), is("delete"));
        assertThat(list.get(2).getValue(), is("delete"));
        
    }

}
profile

느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라

@주현태

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!