2010년 7월 27일 화요일

JAXB의 XmlJavaTypeAdapter 애너테이션

JAXB를 이용하여 XML-Binding을 처리할 때 유용한 애너테이션들이 많이 있다.
그 중의 하나인 XmlJavaTypeAdapter를 살펴보기로 한다.

아래의 소스코드를 살펴 보자

package sample.maven.jaxws;

import java.sql.Timestamp;

import javax.xml.bind.annotation.XmlType;

@XmlType
public class User {
  private long userId;
  private String loginId;
  private String userName;
  private Timestamp createDate;
  public long getUserId() {
    return userId;
  }
  public void setUserId(long userId) {
    this.userId = userId;
  }
  public String getLoginId() {
    return loginId;
  } 
  public void setLoginId(String loginId) {
    this.loginId = loginId;
  }
  public String getUserName() {
    return userName;
  }
  public void setUserName(String userName) {
    this.userName = userName;
  }
  public Timestamp getCreateDate() {
    return createDate;
  }
  public void setCreateDate(Timestamp createDate) {
    this.createDate = createDate;
  }
}

대부분의 dateTime 처리와 관련하여 java.util.Date 타입을 처리하면 문제가 될 게 없다.
Jaxb에서도 java.util.Date 처리를 기본적으로 지원하고 있다.
하지만 Anyframe의 QueryService는 java.util.Date로 매핑을 하게 되면 시분초를 싸그리 없애버린다.
java.sql.Date도 아닌데 말이다.
어쨋거나 어쩔 수 없이 또는 이런 저런 이유로 Timestamp를 데이터 타입으로 사용해야 하는 경우가 있다.
디폴트 생성자도 없는 Timestamp를 Jaxb는 기본적으로 처리할 수가 없다.
따라서 Jaxb가 Timestamp를 java.util.Date로 처리할 수 있도록 어뎁터(Adapter)를 구현해 주어야 한다.

Adapter를 지정하지 않은 경우에 CXF가 웹서비스를 초기화하는 과정에서 아래와 같은 에러메시지가 출력된다.

Timestamp를 사용하는 bean
package sample.maven.jaxws;

import java.sql.Timestamp;

import javax.xml.bind.annotation.XmlType;

@XmlType
public class User {
  private long userId;
  private String loginId;
  private String userName;
  private Timestamp createDate;
  public long getUserId() {
    return userId;
  }
  public void setUserId(long userId) {
    this.userId = userId;
  }
  public String getLoginId() {
    return loginId;
  } 
  public void setLoginId(String loginId) {
    this.loginId = loginId;
  }
  public String getUserName() {
    return userName;
  }
  public void setUserName(String userName) {
    this.userName = userName;
  }
  public Timestamp getCreateDate() {
    return createDate;
  }
  public void setCreateDate(Timestamp createDate) {
    this.createDate = createDate;
  }
}


에러 메시지
... 39 more
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
java.sql.Timestamp does not have a no-arg default constructor.
this problem is related to the following location:
at java.sql.Timestamp
at public java.sql.Timestamp sample.maven.jaxws.User.getCreateDate()
at sample.maven.jaxws.User
at private sample.maven.jaxws.User sample.maven.jaxws.jaxws_asm.GetUserResponse._return
at sample.maven.jaxws.jaxws_asm.GetUserResponse



XmlAdapter
package sample.maven.jaxws;

import java.sql.Timestamp;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateTimestampAdapter extends XmlAdapter {

  @Override
  public Timestamp unmarshal(Date v) throws Exception {
    return new Timestamp(v.getTime());
  }

  @Override
  public Date marshal(Timestamp v) throws Exception {
    return new Date(v.getTime());
  }
}


@XmlJavaTypeAdapter를 적용한 User 빈
package sample.maven.jaxws;

import java.sql.Timestamp;

import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlType
public class User {
  private long userId;
  private String loginId;
  private String userName;
  private Timestamp createDate;
  public long getUserId() {
   return userId;
  }
  public void setUserId(long userId) {
    this.userId = userId;
  }
  public String getLoginId() {
    return loginId;
  } 
  public void setLoginId(String loginId) {
    this.loginId = loginId;
  }
  public String getUserName() {
    return userName;
  }
  public void setUserName(String userName) {
    this.userName = userName;
  }
  @XmlJavaTypeAdapter(value=DateTimestampAdapter.class)
  public Timestamp getCreateDate() {
    return createDate;
  }
  public void setCreateDate(Timestamp createDate) {
    this.createDate = createDate;
  }
}

댓글 없음:

댓글 쓰기