1. 개요
javax.xml.transform.TransformerConfigurationException: Could not load the translet class ....
2. 원인
2-1. 사이즈가 문제?
정확한 원인은 알 수 없지만 읽어들이는 파일(xsl)이 너무 커서 그런 것 같다는 생각에 몇번 더 테스트를 했다. 조금씩 파일 크기를 줄여가면서 테스트한 결과는.
-rw-r--r-- 1 root root 211100 May 23 18:28 e020 -rw-r--r-- 1 root root 210914 May 23 18:28 e021
20번 파일에서는 에러가 났고 21번 파일에서는 에러가 안났다. 조금 더 문제가 되는 파일 사이즈를 찾아보려고 더 테스트를 했다.
-rw-r--r-- 1 root root 210826 May 23 18:30 e026
26번 파일은 21번 파일보다 크기가 더 작은데 에러가 난다..
2-2. 라인 수가 문제?
다만 에러가 안난 21번 파일은 2069라인, 에러가 나는 26번 파일은 2070라인으로 라인 수가 더 많다. 그렇다면 문제는 문서의 크기보다는 라인수 때문일까?
하지만 이어지는 테스트에서 동일하게 2069라인으로 맞춰도 에러가 났다. 그리고 에러가 안난 21번 파일에 라인을 더 추가해서 테스트해도 에러가 나지 않았다.
현재로서는 단순히 문서의 크기도, 라인 수의 문제도 아닌 것 같다.
2-3. 더 테스트
이래저래 테스트한 결과 아래 32번 파일(2059라인)은 에러 발생, 33번 파일(2056라인)은 에러가 안났다.
-rw-r--r-- 1 root root 210916 May 23 18:39 e032 -rw-r--r-- 1 root root 210745 May 23 18:39 e033
좀 더 세밀한 테스트 진행 결과는 다음과 같다.
-rw-r--r-- 1 root root 211143 May 23 19:04 e046 -rw-r--r-- 1 root root 211142 May 23 19:04 e047 -rw-r--r-- 1 root root 211145 May 23 19:04 e048
위 3개 파일은 라인수가 동일하지만, 46번 파일만 에러가 나고 47번, 48번 파일은 에러가 안났다. 차이점은 46번 파일에 비워져 있는 <td></td> 사이에 값을 넣어주자 에러가 난 것이다. 혹시 element 수에 영향을 받는 것은 아닌가? 하는 가설을 세울 수는 있게 됐다.
3. TemplatesImpl.java
코드를 보면서 해야겠는데 답답한 마음에 일단 구글링하여 jdk 1.8의 소스를 봤다.
319 * Defines the translet class and auxiliary classes. 320 * Returns a reference to the Class object that defines the main class 321 */ 322 private void defineTransletClasses() 323 throws TransformerConfigurationException { 324 325 if (_bytecodes == null) { 326 ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); 327 throw new TransformerConfigurationException(err.toString()); 328 } 329 330 TransletClassLoader loader = (TransletClassLoader) 331 AccessController.doPrivileged(new PrivilegedAction() { 332 public Object run() { 333 return new TransletClassLoader(ObjectFactory.findClassLoader()); 334 } 335 }); 336 337 try { 338 final int classCount = _bytecodes.length; 339 _class = new Class[classCount]; 340 341 if (classCount > 1) { 342 _auxClasses = new Hashtable(); 343 } 344 345 for (int i = 0; i < classCount; i++) { 346 _class[i] = loader.defineClass(_bytecodes[i]); 347 final Class superClass = _class[i].getSuperclass(); 348 349 // Check if this is the main class 350 if (superClass.getName().equals(ABSTRACT_TRANSLET)) { 351 _transletIndex = i; 352 } 353 else { 354 _auxClasses.put(_class[i].getName(), _class[i]); 355 } 356 } 357 358 if (_transletIndex < 0) { 359 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); 360 throw new TransformerConfigurationException(err.toString()); 361 } 362 } 363 catch (ClassFormatError e) { 364 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); 365 throw new TransformerConfigurationException(err.toString()); 366 } 367 catch (LinkageError e) { 368 ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); 369 throw new TransformerConfigurationException(err.toString()); 370 } 371 }
이걸 봐서 딱히 답이 없다..
4. 기타
XSLT Error (javax.xml.transform.TransformerConfigurationException): Could not load the translet class
URL : https://issues.apache.org/jira/browse/XALANJ-1549
I am using XSLTC with TraX API. When my XSL size grows bigger, I get an error as below while getting new Transformer from the Templates.
5. XALANJ-1805
class file generated by xsltc is too large to run: java.lang.ClassFormatError
URL : https://issues.apache.org/jira/browse/XALANJ-1805
6. 눈물의 해결
어찌되었던 xalan 라이브러리 문제라고 보고 xalan 2.7.2 최신 버전을 적용해보기로 했다. 잘된다.
- 테스트하던 톰켓의 라이브러리 폴더($CATALINA_HOME/lib)에 jar 파일 4개를 넣어주니 잘 된다.
- 톰켓 lib에 안넣고 war 파일 안에 4개 파일 적용해도 잘 된다.
여담으로. -Xbootclasspath/p로 해도 당연히 잘 된다.
CATALINA_OPTS="-Xbootclasspath/p:${CATALINA_HOME}/lib/xalan/xalan.jar:${CATALINA_HOME}/lib/xalan/xercesImpl.jar:${CATALINA_HOME}/lib/xalan/xml-apis.jar:${CATALINA_HOME}/lib/xalan/serializer.jar"
javax.xml.transform.TransformerFactory 클래스를 찾을 때,
- -Xbootclasspath를 잡지 않으면 : rt.jar 에서 처리
- -Xbootclasspath를 잡으면 : 내가 적용한 jar 에서 처리