JaeWon's Devlog
article thumbnail
반응형

1. 1. JAXB(Java Architecture for XML Binding)

- JAXB는 Java Object 를 XML 로 직렬화 해주거나, XML 을 Java Object 로 역직렬화 해주는 Java API 입니다.

  • 마샬링(Marshalling) : Java Object -> XML
  • 언마샬링(UnMarshalling) : XML -> Java Object

- 기본적으로 JDK6 ~ 9 버전에는 JAXB 가 내장되어 있어 라이브러리를 따로 추가할 필요가 없습니다.(JDK 11 부터는 Dependency 추가가 필요합니다)

- 최근 Object 는 관련해서는 대부분 JSON(JavaScript Object Notation)을 많이 사용하지만, XML 도 종종 사용되고 있습니다.

- JSON 을 다룰 때 사용되는 Jackson 라이브러리를 통해서도 XML 파싱은 가능하지만 해당 글에서는 JAXB 를 사용해보도록 하겠습니다.

2. 2. JAXB Annotation

  • @XmlRootElement
    - XML 의 Root Element 명을 정의.
    - ex) @XmlRootElement(name = "header")
    - 마샬링 시에는 Element 이름을 정의하고, 언마샬링 시에는 이름에 해당하는 Element 속성 또는 Element 를 저장.
  • @XmlElement
    - XML 의 Element 명을 정의.
    -ex) @XmlElement(name = "body")
    - 마샬링 시에는 Element 이름을 정의하고, 언마샬링 시에는 이름에 해당하는 Element 속성 또는 Element 를 저장.
  • @XmlType
    - XML Schema 이름과 Namespace 를 정의.
    - propOrder 속성을 사용하여 XML 표현 시 요소들의 표현 순서 정의 가능.
    - ex) @XmlType(propOrder = {"header", "body"}
  • @XmlElementWrapper
    - 다른 XML 요소들을 감싸는 역할.
    - List 같은 컬렉션 객체들을 XML 변활할 때 사용.
  • @XmlTransient
    - XML에 포함하지 않은 필드에 사용.
  • @XmlAttribute
    - ID 필드가 요소 대신 속성으로 매핑되도록 정의.

3. 3. JAXB 사용하기

- 예를 들기 위해 아래와 같은 XML 형식의 데이터가 있다고 가정하고 진행하겠습니다.

<java />
<?xml version="1.0" encoding="UTF-8"?> <User> <Header> <TimeStamp>20230816105312</TimeStamp> </Header> <Body> <UserName>황재원</UserName> <UserJob>Developer</UserJob> <UserBlog>http://dev-jwblog.tistory.com</UserBlog> </Body> </User>

3.1. 3-0. JAXB 사용 준비하기

- 위에서 말씀드렸듯이 JDK6 ~ 9 버전에는 라이브러리가 내장되어 있어서 따로 추가할 필요가 없습니다.


JDK 11 을 사용하신다면 아래 Dependency 를 추가가 필요합니다.
<java />
// build.gradle implementation 'javax.xml.bind:jaxb-api' runtimeOnly 'com.sun.xml.bind:jaxb-impl:3.0.0' implementation 'org.glassfish.jaxb:jaxb-runtime' implementation 'javax.activation:activation:1.1.1'

- 위와 예제와 같은 형태의 XML 이 있다면 동일하게 객체를 생성합니다.

  • UserXml.class
<java />
@XmlRootElement(name = "User") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "UserType", propOrder = { "header", "body" }) @Builder @AllArgsConstructor @NoArgsConstructor public class UserXml { @XmlElement(name = "Header", required = true, nillable = true) private Header header; @XmlElement(name = "Body", required = true, nillable = true) private Body body; }
  • Header.class
<java />
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "header", propOrder = { "timeStamp" }) @Builder @NoArgsConstructor @AllArgsConstructor public class Header { @XmlElement(name = "TimeStamp", required = true, nillable = true) private String timeStamp; }
  • Body.class
<java />
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "body", propOrder = { "userName", "userJob", "userBlog" }) @Builder @AllArgsConstructor @NoArgsConstructor public class Body { @XmlElement(name = "UserName", required = true, nillable = true) private String userName; @XmlElement(name = "UserJob", required = true, nillable = true) private String userJob; @XmlElement(name = "UserBlog", required = true, nillable = true) private String userBlog; }

3.2. 3-1. 마샬링(JavaObject -> XML)


해당 객체를 생성하는 방법은 다양하지만, 해당 글에서는 Builder 를 사용하여 생성합니다.

- 아래는 마샬링 테스트 입니다.

  • Marshalling Test(JavaObject -> XML)
<java />
public class UserXmlTest { @Test void test() { Header header = Header.builder() .timeStamp("20230816105312") .build(); Body body = Body.builder() .userName("황재원") .userJob("Developer") .userBlog("https://dev-jwblog.tistory.com") .build(); UserXml userXml = UserXml.builder() .header(header) .body(body) .build(); try { // XML 변환[S] // XML 파싱에 필요한 정보를 생성 JAXBContext context = JAXBContext.newInstance(UserXml.class); // 마샬링에 필요한 객체 생성 Marshaller marshaller = context.createMarshaller(); // 마샬링 옵션을 통해 XML 결과를 보기 좋게 출력 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); StringWriter stringWriter = new StringWriter(); marshaller.marshal(userXml, stringWriter); // XML 변환[E] System.err.println(stringWriter.toString()); } catch (JAXBException e) { throw new RuntimeException(e); } } }

- 테스트 결과는 아래와 같습니다.

3.3. 3-2. 언마샬링(XML -> JavaObject)

- 반대로 위 예제 XML 데이터를 JavaObject 로 변환해보도록 하겠습니다.


테스트를 위해서 XML 파일을 읽어서 변환하도록 하지만, 만약 API 로 하여 String 으로 전달받아도 방법은 동일하고, unmarshaller.unmarshal() 메소드에서 받고자 하는 형태로 변환하시면 됩니다.

- 객체는 위와 동일하고 마샬링 대신 언마샬링을 사용합니다.

  • UnMarshalling Test(XML -> JavaObject)
<java />
public class UserXmlTest { @Test void unMarshalling_test() { try { // XML 데이터 FileInputStream fileInputStream = new FileInputStream("C:\\marshall\\UserXml.xml"); // JavaObject 변환[S] // XML 파싱에 필요한 정보를 생성 JAXBContext context = JAXBContext.newInstance(UserXml.class); // 언마샬링에 필요한 객체 생성 Unmarshaller unmarshaller = context.createUnmarshaller(); UserXml userXml = (UserXml) unmarshaller.unmarshal(fileInputStream); // JavaObject 변환[E] System.err.println(userXml.toString(); } catch (Exception e) { } } }

- 테스트 결과는 아래와 같습니다.

4. 4. 번외

- JAXB API 를 이용하면 간단하게 XML 파싱이 가능합니다.

- 그러나, JaxbContext 를 초기화(생성)하고 마샬러, 언마샬러를 생성하는 부분에서 JaxbContext 를 1회 생성 후 재사용을 권장하고 있습니다.(Thread-Safe)

- 생성 비용이 적지 않기 때문에 마샬/언마샬을 수행될 때마다 매번 생성하는 것보다 한 번 생성하고 재사용하는 편이 좋습니다.

- 다만, 마샬러와 언마샬의 경우에는 스레드에 안전하지 않기 때문에 반대로 수행될 때마다 다시 생성하는 것을 권장하고 있습니다.


참고

- https://velog.io/@huk00j/JAXB-marshal%EB%A7%88%EC%83%AC-unmarshal%EC%96%B8%EB%A7%88%EC%83%AC

- https://tychejin.tistory.com/135

- https://madplay.github.io/post/jaxb-marshal-unmarshal

반응형
profile

JaeWon's Devlog

@Wonol

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