Java / Maven에서“Xerces hell”을 다루고 있습니까?


732

제 사무실에서 Xerces라는 단어 만 언급하면 ​​개발자들의 격렬한 분노를 불러 일으킬 수 있습니다. SO에 대한 다른 Xerces 질문을 간략하게 살펴보면 거의 모든 Maven 사용자 가이 문제로 인해 어느 시점에서 "만져"있는 것으로 나타납니다. 불행히도 문제를 이해하려면 Xerces의 역사에 대한 약간의 지식이 필요합니다 ...

역사

  • Xerces는 Java 생태계에서 가장 널리 사용되는 XML 파서입니다. Java로 작성된 거의 모든 라이브러리 또는 프레임 워크는 일부 용량 (직접적으로는 아니지만 전 이적으로)에서 Xerces를 사용합니다.

  • 공식 바이너리에 포함 된 Xerces jar 는 현재까지 버전이 없습니다. 예를 들어, Xerces 2.11.0 구현 jar의 이름은 xercesImpl.jarnot xercesImpl-2.11.0.jar입니다.

  • Xerces 팀 은 Maven을 사용하지 않으므로 Maven Central에 공식 릴리스를 업로드하지 않습니다 .

  • Xerces 는 단일 jar ( xerces.jar) 로 출시 되었지만 하나는 API ( xml-apis.jar)를 포함하고 다른 하나는 해당 API ( xercesImpl.jar) 구현을 포함하는 두 개의 jar로 분할되었습니다 . 이전의 많은 Maven POM은 여전히에 대한 종속성을 선언합니다 xerces.jar. 과거 어느 시점에서 Xerces는로 출시되었는데 xmlParserAPIs.jar, 일부 이전 POM도 의존합니다.

  • Jar를 Maven 리포지토리에 배포하는 사람들이 xml-apis 및 xercesImpl jar에 할당 한 버전은 종종 다릅니다. 예를 들어, xml-apis에는 버전 1.3.03이 제공되고 xercesImpl에는 버전 2.8.0이 제공 될 수 있습니다 (둘 다 Xerces 2.8.0의 것임). 사람들은 종종 xml-apis jar에 구현 된 사양의 버전을 태그하기 때문입니다. 여기에는 매우 훌륭하지만 불완전한 분류가 있습니다 .

  • 문제를 복잡하게하기 위해 Xerces는 JRE에 포함 된 JAXP (Java API for XML Processing)의 참조 구현에 사용되는 XML 파서입니다. 구현 클래스는 com.sun.*네임 스페이스 아래에 다시 패키지되므로 일부 JRE에서 사용하지 못할 수 있으므로 직접 액세스하는 것이 위험합니다. 그러나 모든 Xerces 기능이 java.*and javax.*API 를 통해 노출되는 것은 아닙니다 . 예를 들어 Xerces 직렬화를 노출하는 API가 없습니다.

  • 혼란스러운 혼란에 더해 거의 모든 서블릿 컨테이너 (JBoss, Jetty, Glassfish, Tomcat 등)는 하나 이상의 /lib폴더에 Xerces와 함께 제공 됩니다.

문제

갈등 해결

위의 이유 중 일부 또는 전부에 대해 많은 조직에서 POM에 Xerces의 사용자 지정 빌드를 게시하고 사용합니다. 작은 응용 프로그램이 있고 Maven Central 만 사용하는 경우에는 실제로 문제가되지 않지만 Artifactory 또는 Nexus가 여러 저장소 (JBoss, Hibernate 등)를 프록시하는 엔터프라이즈 소프트웨어의 경우 빠르게 문제가됩니다.

Artifactory에 의해 프록시되는 xml-apis

예를 들어 조직 A는 다음 xml-apis과 같이 게시 할 수 있습니다 .

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

한편 조직 B는 다음과 같은 내용 jar을 게시 할 수 있습니다 .

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

B jar는 A보다 낮은 버전이지만 jarMaven은 서로 다른 인공물을 가지고 있기 때문에 동일한 인공물인지 알지 못합니다 groupId. 따라서 충돌 해결을 수행 할 수 없으며 두 가지 모두 jar해결 된 종속성으로 포함됩니다.

여러 xml-api로 해결 된 종속성

클래스 로더 지옥

위에서 언급했듯이 JRE는 JAXP RI에서 Xerces와 함께 제공됩니다. 모든 Xerces Maven 종속성을 <exclusion>s 또는<provided>에 의존하는 타사 코드는 사용중인 JDK의 JAXP에 제공된 버전에서 작동하거나 작동하지 않을 수 있습니다. 또한, 서블릿 컨테이너에 Xerces 항아리가 포함되어 있습니다. 서블릿 버전을 삭제하고 컨테이너가 JAXP 버전에서 실행되기를 희망합니까? 서블릿 버전을 유지하는 것이 더 좋으며, 애플리케이션 프레임 워크가 서블릿 버전에서 실행되기를 바랍니다. 위에서 설명한 해결되지 않은 충돌 중 하나 또는 두 개가 제품에 쉽게 들어가면 (대규모 조직에서 쉽게 발생), 클래스 로더가 런타임에 어떤 Xerces 버전을 선택하는지 궁금해하고 클래스 로더 지옥에 빠지게됩니다. Windows 및 Linux에서 동일한 jar을 선택합니다 (아마도).

솔루션?

우리는 모든 Xerces에 메이븐 종속성을 표시하려고했습니다 <provided>또는으로 <exclusion>,하지만이 유물은 (많은 별칭이 주어진 (특히 큰 팀) 시행하기가 어렵습니다 xml-apis, xerces, xercesImpl, xmlParserAPIs, 등). 또한 타사의 libs / frameworks는 JAXP 버전 또는 서블릿 컨테이너가 제공하는 버전에서 실행되지 않을 수 있습니다.

Maven으로이 문제를 어떻게 가장 잘 해결할 수 있습니까? 의존성에 대해 세밀한 제어를 수행 한 다음 계층화 된 클래스 로딩에 의존해야합니까? 모든 Xerces 종속성을 전체적으로 제외하고 모든 프레임 워크 / lib가 JAXP 버전을 사용하도록 강제 할 수있는 방법이 있습니까?


업데이트 : Joshua Spiewak는 Xerces 빌드 스크립트의 패치 버전을 XERCESJ-1454 에 업로드하여 Maven Central에 업로드 할 수 있습니다. 이 문제에 투표 / 감시 / 기고하고이 문제를 한 번에 해결하겠습니다.


8
이 자세한 질문에 감사드립니다. xerces 팀의 동기를 이해하지 못합니다. 나는 그들이 제품을 자랑스럽게 생각하고 다른 제품을 사용하는 것을 좋아하지만 xerces와 maven의 현재 상태는 수치스럽지 않다고 생각합니다. 그럼에도 불구하고, 그들은 나에게 이해가되지 않더라도 원하는 것을 할 수 있습니다. 소나타 입 사람들에게 어떤 제안이 있는지 궁금합니다.
트래비스 슈니 버거

35
이것은 아마도 주제가 아닐 수도 있지만, 아마도 내가 본 것 중 더 좋은 게시물 일 것입니다. 질문과 관련하여 설명하는 것은 우리가 직면 할 수있는 가장 고통스러운 문제 중 하나입니다. 위대한 이니셔티브!
Jean-Rémy Revy

2
@TravisSchneeberger 대부분의 복잡성은 Sun이 JRE 자체에서 Xerces를 사용하기로 선택했기 때문입니다. 당신은 Xerces 사람들을 비난 할 수 없습니다.
Thorbjørn Ravn Andersen

일반적으로 시행 착오를 거쳐 모든 종속 라이브러리를 만족시키는 Xerces 버전을 찾으려고합니다. 불가능한 경우 WAR로 리팩토링하여 애플리케이션을 별도의 WAR (별도의 클래스 로더)로 분할하십시오. 이 도구는 (내가 쓴)에 무슨 일이 일어나고 있는지 이해하는 데 도움이 jhades.org 항아리의 클래스 경로를 조회 할 수 있도록하여, 및 클래스 - 서버가 시작되지 않을 때 그것은 아직 경우에도 작동
각도 대학

Windows의 git bash에서 servicemix를 시작하는 동안이 오류가 발생하면 간단한 설명입니다. 대신 "normal"cmd에서 시작하십시오.
Albert Hendriks가

답변:


112

2013 년 2 월 20 일 이후 Maven Central에는 Xerces의 2.11.0 JAR (및 소스 JAR!) 이 있습니다! Maven Central의 Xerces를 참조하십시오 . 왜 그들이 https://issues.apache.org/jira/browse/XERCESJ-1454를 해결하지 못했는지 궁금합니다 ...

나는 사용했다 :

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

그리고 모든 의존성이 제대로 해결되었습니다 xml-apis-1.4.01!

그리고 가장 중요한 것은 (과거에 분명하지 않은) Maven Central의 JAR 은 공식 Xerces-J-bin.2.11.0.zip배포판 과 동일한 JAR 입니다.

그러나 xml-schema-1.1-beta버전을 찾을 수 없습니다 - classifier추가 종속성으로 인해 Maven 버전이 될 수 없습니다 .


9
그건하지만 매우 혼란 그 xml-apis:xml-apis:1.4.01입니다 새로운 보다는 xml-apis:xml-apis:2.0.2?? search.maven.org/…
Hendy Irawan

혼란 스럽지만 Justingarrik이 자신의 게시물에서 말한 것처럼 버전이없는 Xerces 항아리를 타사에서 업로드했기 때문입니다. xml-apis 2.9.1은 1.3.04와 동일하므로 1.4.01은 1.3.04보다 더 새롭고 숫자가 더 큽니다.
liltitus27

1
pom.xml에 xercesImpl과 xml-api가 모두 있으면 xml-apis 종속성을 삭제하십시오! 그렇지 않으면 2.0.2는 못생긴 머리를 양육합니다.
MikeJRamsey56

64

솔직히, 우리가 잘 w /를 JAXP 버전, 그래서 작품을 만난 것을 거의 모든 우리는 항상 제외 xml-apis 하고 xercesImpl.


13
이를 위해 pom.xml 스 니펫을 추가 할 수 있습니까?
chzbrgla

10
이것을 시도하면 JavaMelody와 Spring이 java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal런타임에 발생합니다.
David Moles

David Moles의 응답에 추가하기 위해, 전 이적 종속성의 수십 개가 ElementTraversal이 필요하다는 것을 알았습니다. Spring과 Hadoop의 다양한 것들이 가장 일반적입니다.
Scott Carey

2
java.lang.NoClassDefFoundError : org / w3c / dom / ElementTraversal을 얻는 경우 pom-xmls.1.4.01을 pom에 추가하십시오 (다른 모든 종속 버전 제외)
Justin Rowe

1
ElementTraversal은 Xerces 11에 추가되고 xml-apis : xml-apis : 1.4.01 종속에서 사용할 수있는 새로운 클래스입니다. 따라서 클래스를 프로젝트에 수동으로 복사하거나 클래스 로더에서 클래스가 중복되는 전체 종속성을 사용해야 할 수도 있습니다. 그러나 JDK9에는이 클래스가 포함되어 있으므로 기능을 제거해야 할 수도 있습니다.
Sergey Ponomarev

42

금지 된 종속성 규칙과 함께 maven 집행자 플러그인을 사용할 수 있습니다. 이를 통해 원하지 않는 모든 별칭을 금지하고 원하는 별칭 만 허용 할 수 있습니다. 이 규칙은 위반시 프로젝트의 maven 빌드에 실패합니다. 또한이 규칙이 엔터프라이즈의 모든 프로젝트에 적용되는 경우 플러그인 구성을 회사 상위 pom에 둘 수 있습니다.

보다:


33

이것이 이것이 질문에 정확하게 대답하지는 않지만 의존성 관리를 위해 Gradle을 사용하는 Google에서 오는 ppl의 경우 :

Gradle의 모든 xerces / Java8 문제를 다음과 같이 제거했습니다.

configurations {
    all*.exclude group: 'xml-apis'
    all*.exclude group: 'xerces'
}

36
maven을 사용하면 약 4000 줄의 XML이 필요합니다.
teknopaul

그 문제를 해결하지 못했습니다. Android-Gradle 사용자를위한 다른 힌트가 있습니까?
nyxee

2
@teknopaul XML은 구성을 위해 순수하게 사용됩니다. Groovy는 고급 프로그래밍 언어입니다. 때때로 당신은 마술을 위해 그루비 대신 XML을 명시 적으로 사용하기를 원할 수 있습니다.
Dragas

16

대답해야 할 질문이 하나 있다고 생각합니다.

응용 프로그램의 모든 것이 함께 사용할 수있는 xerces * .jar가 있습니까?

그렇지 않다면 기본적으로 망하고 OSGI와 같은 것을 사용해야 할 때 동시에 다른 버전의 라이브러리를로드 할 수 있습니다. 기본적으로 jar 버전 문제를 클래스 로더 문제로 대체한다는 점에 유의하십시오 ...

그러한 버전이 있으면 저장소가 모든 종류의 종속성에 대해 해당 버전을 반환하도록 할 수 있습니다. 추악한 해킹이며 클래스 패스에서 동일한 xerces 구현을 여러 번 수행하지만 여러 버전의 xerces를 사용하는 것보다 낫습니다.

xerces에 대한 모든 종속성을 제외하고 사용하려는 버전에 하나를 추가 할 수 있습니다.

어떤 종류의 버전 확인 전략을 maven 용 플러그인으로 작성할 수 있는지 궁금합니다. 이것은 아마도 가장 좋은 해결책 일 것입니다. 그러나 가능한 모든 연구와 코딩이 필요하다면.

런타임 환경에 포함 된 버전의 경우, 서버의 lib 폴더가 고려되기 전에 응용 프로그램 클래스 경로에서 제거되거나 응용 프로그램 항아리가 클래스로드를 위해 먼저 고려되는지 확인해야합니다.

결론적으로 말하면 엉망이며 변경되지 않습니다.


1
다른 클래스 로더에 의해로드 된 같은 jar에서 같은 클래스는 여전히 ClassCastException입니다 (모든 표준 컨테이너에서)
Ajax

3
바로 그거죠. 그것이 내가 쓴 이유입니다. 기본적으로 jar 버전 문제를 클래스 로더 문제로 대체한다는 경고를
받으십시오

7

여기에서 다루지 않은 또 다른 옵션이 있습니다 : Maven의 Xerces 종속성을 선택적 으로 선언 :

<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>...</version>
   <optional>true</optional>
</dependency>

기본적으로이 작업은 모든 부양 가족 이 Xerces 버전 을 선언 하도록 하거나 프로젝트가 컴파일되지 않도록하는 것입니다. 그들이이 의존성을 무시하고 싶을지라도 환영 할 수 있지만 잠재적 인 문제를 소유 할 것입니다.

이는 다운 스트림 프로젝트에 다음과 같은 강력한 동기를 부여합니다.

  • 적극적인 결정을 내립니다. 그들은 같은 버전의 Xerces와 함께 가거나 다른 것을 사용합니까?
  • 실제로 파싱 (예 : 단위 테스트) 및 클래스 로딩을 테스트하고 클래스 경로를 어지럽히 지 않도록합니다.

모든 개발자가 새로 도입 된 종속성을 추적하지는 않습니다 (예 :) mvn dependency:tree. 이 접근 방식은 문제를 즉시 주목할 것입니다.

그것은 우리 조직에서 잘 작동합니다. 소개 전에는 OP가 설명하는 것과 같은 지옥에 살았습니다.


문자 그대로 version 요소 내에서 dot-dot-dot를 사용해야합니까, 아니면 2.6.2와 같은 실제 버전을 사용해야합니까?
chrisinmtown

3
@chrisinmtown 실제 버전입니다.
다니엘

6

모든 maven 프로젝트는 xerces에 따라 중지해야하지만 실제로는 그렇지 않습니다. XML API와 Impl은 1.4 이후 Java의 일부였습니다. Java 또는 Swing에 의존한다고 말하는 것과 같이 xerces 또는 XML API에 의존 할 필요가 없습니다. 이것은 암시 적입니다.

내가 maven repo의 보스라면 xerces 의존성을 재귀 적으로 제거하는 스크립트를 작성 하고이 repo에 Java 1.4가 필요하다는 내용의 나를 읽어보십시오.

실제로 org.apache 가져 오기를 통해 Xerces를 직접 참조하기 때문에 실제로 깨지는 것은 Java 1.4 수준 (2002 년 이후에 완료) 또는 승인 된 라이브러리를 통해 JVM 수준의 솔루션으로 가져 오는 코드 수정이 필요합니다.


자세한 리팩터링을 수행 할 때 Java 파일 및 구성 텍스트에서 패키지 및 클래스 이름도 검색해야합니다. 개발자는 Impl 클래스의 FQN을 Class.forName 및 유사한 구문에서 사용되는 상수 문자열에 넣었 음을 알 수 있습니다.
Derek Bennett

이것은 모든 SAX 구현이 동일한 것을 수행한다고 가정하지만 이는 사실이 아닙니다. xercesImpl 라이브러리는 java.xml.parser 라이브러리에없는 구성 옵션을 허용합니다.
Amalgovinus

6

XML 지옥 수준을 식별하려면 먼저 디버깅해야합니다. 제 생각에는 첫 번째 단계는

-Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

명령 행에. 그래도 문제가 해결되지 않으면 라이브러리 제외를 시작하십시오. 그렇지 않은 경우 추가

-Djaxp.debug=1

명령 줄에.


2

제외를 제외하고 도움이되는 것은 모듈 식 종속성입니다.

하나의 플랫 클래스 로딩 (독립형 앱) 또는 반 계층 (JBoss AS / EAP 5.x)에서는 이것이 문제였습니다.

그러나 OSGiJBoss Modules 와 같은 모듈 식 프레임 워크를 사용 하면 더 이상 큰 어려움이 없습니다. 라이브러리는 원하는 라이브러리를 독립적으로 사용할 수 있습니다.

물론 단일 구현 및 버전 만 사용하는 것이 가장 권장되지만 다른 방법이없는 경우 (더 많은 라이브러리의 추가 기능 사용) 모듈화를하면 절약 할 수 있습니다.

JBoss 모듈의 좋은 예는 JBoss AS 7 / EAP 6 / WildFly 8입니다. 입니다.

모듈 정의 예 :

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.msc">
    <main-class name="org.jboss.msc.Version"/>
    <properties>
        <property name="my.property" value="foo"/>
    </properties>
    <resources>
        <resource-root path="jboss-msc-1.0.1.GA.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.modules"/>
        <!-- Optional deps -->
        <module name="javax.inject.api" optional="true"/>
        <module name="org.jboss.threads" optional="true"/>
    </dependencies>
</module>

OSGi와 비교하여 JBoss 모듈은 더 간단하고 빠릅니다. 특정 기능이 누락되었지만 (대부분) 한 공급 업체가 제어하는 ​​대부분의 프로젝트에 충분하며 (병렬화 된 종속성 해결로 인해) 놀라운 빠른 부팅이 가능합니다.

참고가 있다는 걸 모듈화 노력은 자바 8 진행 JRE를 자체를 모듈화 주로하지만 AFAIK, 확실하지가 애플리케이션에 적용 할 수 있는지 여부.


jboss 모듈은 정적 모듈화에 관한 것입니다. OSGi가 제공해야하는 런타임 모듈화와는 거의 관련이 없습니다. 그래도 좋은 시스템입니다.
eis

* 칭찬 대신에 보완
Robert Mikes

2

분명히 xerces:xml-apis:1.4.01더 이상 maven central에 있지 않습니다.xerces:xercesImpl:2.11.0 참조입니다.

이것은 나를 위해 작동합니다 :

<dependency>
  <groupId>xerces</groupId>
  <artifactId>xercesImpl</artifactId>
  <version>2.11.0</version>
  <exclusions>
    <exclusion>
      <groupId>xerces</groupId>
      <artifactId>xml-apis</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>xml-apis</groupId>
  <artifactId>xml-apis</artifactId>
  <version>1.4.01</version>
</dependency>

1

내 친구는 매우 간단합니다. 여기 예가 있습니다.

<dependency>
    <groupId>xalan</groupId>
    <artifactId>xalan</artifactId>
    <version>2.7.2</version>
    <scope>${my-scope}</scope>
    <exclusions>
        <exclusion>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
    </exclusion>
</dependency>

그리고 터미널 (이 예제의 Windows 콘솔)에서 maven 트리에 문제가 없는지 확인하려면 다음을 수행하십시오.

mvn dependency:tree -Dverbose | grep --color=always '(.* conflict\|^' | less -r
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.