제목 그대로다. 운영 도중에 XML Parsing Error 가 발생했다 🙀
로컬과 개발환경, 그리고 3개월 간 운영에서 이슈없이 잘 되던 기능이었다.
그런데 어제부터 갑자기 아래와 같은 원인으로 오류가 발생하면서 기능이 멈추는 현상이 발생했다.
java.lang.NoSuchMethodError: org.json.JSONTokener.<init>(Ljava/io/Reader;)
코딩에 `갑자기` 가 없다는 것을 안다. 결국은 내가 무지 했거나 완벽하게 분석, 설계하지 못해서 발생한거다.
그럼에도 이 포스팅을 작성함으로써 나를 포함한 다른 이들에게 도움이 되었으면 한다 😇
원인은 JSONTockener 클래스가 내 라이브러리에서 중첩되어 있는 상황에서
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 의 구현체가 담긴 라이브러리를 더 불러와야 하는데...
중에서 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')
'Backend > JAVA' 카테고리의 다른 글
[Java] Comparator 로 복잡한 정렬 비즈니스 녹여내기 (0) | 2022.11.21 |
---|---|
[Java] Root(/) path 진입 시 Swagger 로 이동시키는 방법 (0) | 2021.07.14 |
[JAVA] SHA256 암호화 Util (0) | 2021.01.13 |
[JAVA] CURL 로 다른 API 호출하는 방법 (with. HttpClient) (0) | 2020.12.01 |
[JAVA] byte[] to File, File to MultipartFile (fin. byte[] to MultipartFile) (0) | 2020.09.09 |
댓글