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

제 사무실에서 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에 업로드 할 수 있습니다. 이 문제에 투표 / 감시 / 기고하고이 문제를 한 번에 해결하겠습니다.



답변

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 버전이 될 수 없습니다 .


답변

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


답변

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

보다:


답변

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

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

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


답변

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

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

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

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

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

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

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

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


답변

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

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

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

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

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

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

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


답변

모든 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 수준의 솔루션으로 가져 오는 코드 수정이 필요합니다.