본문 바로가기
Backend/JAVA

[Java] 운영 도중에 XML Parsing Error 가 발생했다! (with. NoSuchMethodError)

by 지구 2021. 8. 6.

제목 그대로다. 운영 도중에 XML Parsing Error 가 발생했다 🙀

로컬과 개발환경, 그리고 3개월 간 운영에서 이슈없이 잘 되던 기능이었다.
그런데 어제부터 갑자기 아래와 같은 원인으로 오류가 발생하면서 기능이 멈추는 현상이 발생했다.

java.lang.NoSuchMethodError: org.json.JSONTokener.<init>(Ljava/io/Reader;)

코딩에 `갑자기` 가 없다는 것을 안다. 결국은 내가 무지 했거나 완벽하게 분석, 설계하지 못해서 발생한거다.
그럼에도 이 포스팅을 작성함으로써 나를 포함한 다른 이들에게 도움이 되었으면 한다 😇 

 


원인은 JSONTockener 클래스가 내 라이브러리에서 중첩되어 있는 상황에서

com.vaadin.external.google 의 org.json 패키지

 

org.json 라이브러리의 org.json 패키지

JSONObject resultJson = XML.toJSONObject("<XML...>");

XML 를 JSONObject 로 치환할 때 사용하는 toJSONObject() 메소드 내부적으로 `JSONTockener` 객체를 사용해서 발생하는 이슈였다. (위에서 캡쳐한 서로 다른 두 라이브러리의 `JSONTockener` 객체는 생성자 포멧도 다른 그냥 서로 다른 객체이다.)

> 관련 stackoverflow question

 


그래서 찾은 대안은 크게 두 가지가 있었는데,

#1. 클래스가 다른 버전으로 중첩되지 않도록 특정 라이브러리에서 json 관련된 패키지를 exclude 시키는 방법과

testCompile("org.springframework.boot:spring-boot-starter-test") {
    exclude group: "com.vaadin.external.google", module:"android-json"
}

#2. JAXB API 를 사용하도록 소스를 수정하는 방법이다. (JAXB API 공식문서)

 

라이브러리에 대한 종속성은 회사 프로젝트의 모든 core 를 담당하는 팀에서 관리하는 영역이기도 하고,

다른 사이드 이펙트가 발생할 여지가 있다고 판단하여 JAXB API 를 사용하기로 결정했다.

 


그렇게, JAXB API 에 매핑할 객체를 선언하고 테스트 코드를 만들어서 돌려보는데 ...

@XmlRootElement(namespace="http://my.com/", name="MY_XML_ROOT")
@XmlAccessorType(XmlAccessType.FIELD)
public class MyXmlParsing {
    @XmlElement(name="RESULT_CODE", namespace="http://my.com/")
    private String returnCd;

    @XmlElement(name="RESULT_MSG", namespace="http://my.com/")
    private String returnMsg;
}

...

@Test
void sendTicket() throws JAXBException {
    // given
    String coopStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
        + "<MY_XML_ROOT xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://my.com/\">\n"
        + "\t<RESULT_CODE>0000</RESULT_CODE>\n"
        + "\t<RESULT_MSG>정상처리</RESULT_MSG>\n"
        + "</MY_XML_ROOT>";
        
    // when
    StringReader stringReader = new StringReader(coopStr);
    JAXBContext jaxbContext = JAXBContext.newInstance(MyXmlParsing.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    MyXmlParsing myXmlParsing = (MyXmlParsing) unmarshaller.unmarshal(stringReader);
    
    // then
    assertThat(myXmlParsing).isNotNull();
    assertThat(myXmlParsing.getReturnCd()).isEqualTo("0000");
    assertThat(myXmlParsing.getReturnMsg()).isEqualTo("정상처리");
}

이번엔 이런 에러가 발생했다. 😑

javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.

jaxb-api 라이브러리는 있는데 ?!

하지만 이 라이브러리로만으로는 해결할 수 없고, JAXB 의 구현체가 담긴 라이브러리를 더 불러와야 하는데...

  1. jakarta (참고: 공홈)
  2. glassfish (참고: 공홈)

중에서 glassfish 를 선택했고, 따라서 아래 라이브러리를 추가해주었더니 잘 됐다 :)

implementation('javax.xml.bind:jaxb-api:2.3.0')
// implementation('javax.activation:activation:1.1') // 위 라이브러리에 내장
implementation('org.glassfish.jaxb:jaxb-runtime:2.3.0')

 

반응형

댓글