title: Dealing with "Xerces hell" in Java/Maven?
body: <p>In my office, the mere mention of the word Xerces is enough to incite murderous rage from developers. A cursory glance at the other Xerces questions on SO seem to indicate that almost all Maven users are &quot;touched&quot; by this problem at some point.  Unfortunately, understanding the problem requires a bit of knowledge about the history of Xerces...</p>
  <h1>History</h1>
  <ul>
  <li><p>Xerces is the most widely used XML parser in the Java ecosystem.  Almost every library or framework written in Java uses Xerces in some capacity (transitively, if not directly).</p>
  </li>
  <li><p>The Xerces jars included in the <a href="http://xerces.apache.org/mirrors.cgi#binary" rel="noreferrer">official binaries</a> are, to this day, not versioned.  For example, the Xerces 2.11.0 implementation jar is named <code>xercesImpl.jar</code> and not <code>xercesImpl-2.11.0.jar</code>.</p>
  </li>
  <li><p>The Xerces team <a href="https://issues.apache.org/jira/browse/XERCESJ-1454?focusedCommentId=12881865&amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12881865" rel="noreferrer">does not use Maven</a>, which means they do not
  upload an official release to <a href="http://search.maven.org/" rel="noreferrer">Maven Central</a>.</p>
  </li>
  <li><p>Xerces used to be <a href="http://xerces.apache.org/xerces2-j/faq-general.html#faq-3" rel="noreferrer">released as a single jar</a> (<code>xerces.jar</code>), but was split into two jars, one containing the API (<code>xml-apis.jar</code>) and one containing the implementations of those APIs (<code>xercesImpl.jar</code>).  Many older Maven POMs still declare a dependency on <code>xerces.jar</code>.  At some point in the past, Xerces was also released as <code>xmlParserAPIs.jar</code>, which some older POMs also depend on.</p>
  </li>
  <li><p>The versions assigned to the xml-apis and xercesImpl jars by those who deploy their jars to Maven repositories are often different.  For example, xml-apis might be given version 1.3.03 and xercesImpl might be given version 2.8.0, even though both are from Xerces 2.8.0.  This is because people often tag the xml-apis jar with the version of the specifications that it implements.  There is a very nice, but incomplete breakdown of this <a href="http://web.archive.org/web/20140113103608/http://swordsystems.com/2011/06/29/xerces-and-xml-api-dependency-hell/" rel="noreferrer">here</a>.</p>
  </li>
  <li><p>To complicate matters, Xerces is the XML parser used in the reference implementation of the Java API for XML Processing (JAXP), included in the JRE. The implementation classes are repackaged under the <code>com.sun.*</code> namespace, which makes it dangerous to access them directly, as they may not be available in some JREs.  However, not all of the Xerces functionality is exposed via the <code>java.*</code> and <code>javax.*</code> APIs; for example, there is no API that exposes Xerces serialization.</p>
  </li>
  <li><p>Adding to the confusing mess, almost all servlet containers (JBoss, Jetty, Glassfish, Tomcat, etc.), ship with Xerces in one or more of their <code>/lib</code> folders.</p>
  </li>
  </ul>
  <h1>Problems</h1>
  <h3>Conflict Resolution</h3>
  <p>For some -- or perhaps all -- of the reasons above, many
  organizations publish and consume custom builds of Xerces in their
  POMs.  This is not really a problem if you have a small application and are only using Maven Central, but it quickly becomes an issue for enterprise software where Artifactory or Nexus is proxying multiple repositories (JBoss, Hibernate, etc.):</p>
  <p><img src="https://i.stack.imgur.com/Fe9Xa.png" alt="xml-apis proxied by Artifactory" /></p>
  <p>For example, organization A might publish <code>xml-apis</code> as:</p>
  <pre><code>&lt;groupId&gt;org.apache.xerces&lt;/groupId&gt;
  &lt;artifactId&gt;xml-apis&lt;/artifactId&gt;
  &lt;version&gt;2.9.1&lt;/version&gt;
  </code></pre>
  <p>Meanwhile, organization B might publish the same <code>jar</code> as:</p>
  <pre><code>&lt;groupId&gt;xml-apis&lt;/groupId&gt;
  &lt;artifactId&gt;xml-apis&lt;/artifactId&gt;
  &lt;version&gt;1.3.04&lt;/version&gt;
  </code></pre>
  <p>Although B's <code>jar</code> is a lower version than A's <code>jar</code>, Maven does not know
  that they are the same artifact because they have different
  <code>groupId</code>s. Thus, it cannot perform conflict resolution and both
  <code>jar</code>s will be included as resolved dependencies:</p>
  <p><img src="https://i.stack.imgur.com/4X1ts.png" alt="resolved dependencies with multiple xml-apis" /></p>
  <h3>Classloader Hell</h3>
  <p>As mentioned above, the JRE ships with Xerces in the JAXP RI.  While it would be nice to mark all Xerces Maven dependencies as <code>&lt;exclusion&gt;</code>s or as <code>&lt;provided&gt;</code>, the third-party code you depend on may or may not work with the version provided in JAXP of the JDK you're using.  In addition, you have the Xerces jars shipped in your servlet container to contend with. This leaves you with a number of choices: Do you delete the servlet version and hope that your container runs on the JAXP version? Is it better to leave the servlet version, and hope that your application frameworks run on the servlet version? If one or two of the unresolved conflicts outlined above manage to slip into your product (easy to happen in a large organization), you quickly find yourself in classloader hell, wondering which version of Xerces the classloader is picking at runtime and whether or not it will pick the same jar in Windows and Linux (probably not).</p>
  <h1>Solutions?</h1>
  <p>We've tried marking all Xerces Maven dependencies as <code>&lt;provided&gt;</code> or as an <code>&lt;exclusion&gt;</code>, but this is difficult to enforce (especially with a large team) given that the artifacts have so many aliases (<code>xml-apis</code>, <code>xerces</code>, <code>xercesImpl</code>, <code>xmlParserAPIs</code>, etc.).  Additionally, our third party libs/frameworks may not run on the JAXP version or the version provided by a servlet container.</p>
  <p><strong>How can we best address this problem with Maven?  Do we have to exercise such fine-grained control over our dependencies, and then rely on tiered classloading?  Is there some way to globally exclude all Xerces dependencies, and force all of our frameworks/libs to use the JAXP version?</strong></p>
  <hr />
  <p><strong>UPDATE</strong>: Joshua Spiewak has uploaded a patched version of the Xerces build scripts to <a href="https://issues.apache.org/jira/browse/XERCESJ-1454" rel="noreferrer">XERCESJ-1454</a> that allows for upload to Maven Central.  Vote/watch/contribute to this issue and let's fix this problem once and for all.</p>