Di kantor saya, hanya menyebutkan kata Xerces sudah cukup untuk memicu kemarahan mematikan dari pengembang. Pandangan sekilas pada pertanyaan Xerces lainnya pada SO tampaknya menunjukkan bahwa hampir semua pengguna Maven "tersentuh" oleh masalah ini di beberapa titik. Sayangnya, memahami masalah ini membutuhkan sedikit pengetahuan tentang sejarah Xerces ...
Sejarah
Xerces adalah parser XML yang paling banyak digunakan di ekosistem Java. Hampir setiap pustaka atau framework yang ditulis dalam Java menggunakan Xerces dalam kapasitas tertentu (secara transitif, jika tidak secara langsung).
Guci Xerces yang termasuk dalam binari resmi , sampai hari ini, tidak diversi. Misalnya, topler implementasi Xerces 2.11.0 dinamai
xercesImpl.jar
dan tidakxercesImpl-2.11.0.jar
.Tim Xerces tidak menggunakan Maven , yang berarti mereka tidak mengunggah rilis resmi ke Maven Central .
Xerces dulu dirilis sebagai toples tunggal (
xerces.jar
), tetapi dibagi menjadi dua toples, satu berisi API (xml-apis.jar
) dan satu berisi implementasi API tersebut (xercesImpl.jar
). Banyak POM Maven yang lebih tua masih menyatakan ketergantunganxerces.jar
. Di beberapa titik di masa lalu, Xerces juga dirilis sebagaixmlParserAPIs.jar
, yang tergantung pada beberapa POM lama.Versi yang ditugaskan untuk guci xml-apis dan xercesImpl oleh mereka yang menggunakan guci mereka ke repositori Maven seringkali berbeda. Misalnya, xml-apis mungkin diberikan versi 1.3.03 dan xercesImpl mungkin diberikan versi 2.8.0, meskipun keduanya berasal dari Xerces 2.8.0. Ini karena orang sering menandai tabung xml-apis dengan versi spesifikasi yang diterapkannya. Ada gangguan yang sangat bagus, tetapi tidak lengkap di sini .
Untuk memperumit masalah, Xerces adalah parser XML yang digunakan dalam implementasi referensi API Java untuk Pemrosesan XML (JAXP), termasuk dalam JRE. Kelas implementasi dipaket ulang di bawah
com.sun.*
namespace, yang membuatnya berbahaya untuk mengaksesnya secara langsung, karena mereka mungkin tidak tersedia di beberapa JRE. Namun, tidak semua fungsionalitas Xerces diekspos melalui APIjava.*
danjavax.*
; misalnya, tidak ada API yang memaparkan serialisasi Xerces.Menambah kekacauan yang membingungkan, hampir semua kontainer servlet (JBoss, Jetty, Glassfish, Tomcat, dll.), Dikirim bersama Xerces di satu atau lebih
/lib
folder mereka .
Masalah
Resolusi konflik
Untuk beberapa - atau mungkin semua - alasan di atas, banyak organisasi mempublikasikan dan mengonsumsi build kustom Xerces di POM mereka. Ini tidak benar-benar masalah jika Anda memiliki aplikasi kecil dan hanya menggunakan Maven Central, tetapi dengan cepat menjadi masalah bagi perangkat lunak perusahaan di mana Artifactory atau Nexus mem-proxy beberapa repositori (JBoss, Hibernate, dll.):
Misalnya, organisasi A dapat menerbitkan xml-apis
sebagai:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Sementara itu, organisasi B mungkin menerbitkan yang sama jar
dengan:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Meskipun B jar
adalah versi yang lebih rendah dari A jar
, Maven tidak tahu bahwa mereka adalah artefak yang sama karena mereka memiliki groupId
s yang berbeda
. Dengan demikian, tidak dapat melakukan resolusi konflik dan keduanya
jar
akan dimasukkan sebagai dependensi yang diselesaikan:
Neraka Classloader
Seperti disebutkan di atas, JRE dikirimkan bersama Xerces di JAXP RI. Meskipun akan menyenangkan untuk menandai semua dependensi Xerces Maven sebagai <exclusion>
s atau sebagai<provided>
, kode pihak ketiga yang Anda andalkan mungkin atau mungkin tidak berfungsi dengan versi yang disediakan di JAXP JDK yang Anda gunakan. Selain itu, Anda memiliki botol-botol Xerces yang dikirimkan dalam wadah servlet untuk bersaing. Ini memberi Anda sejumlah pilihan: Apakah Anda menghapus versi servlet dan berharap bahwa wadah Anda berjalan pada versi JAXP? Apakah lebih baik meninggalkan versi servlet, dan berharap bahwa kerangka kerja aplikasi Anda berjalan pada versi servlet? Jika satu atau dua konflik yang tidak terselesaikan yang diuraikan di atas berhasil masuk ke produk Anda (mudah terjadi di organisasi besar), Anda dengan cepat menemukan diri Anda di neraka classloader, bertanya-tanya versi Xerces mana yang diambil classloader saat runtime dan apakah itu akan memilih tabung yang sama di Windows dan Linux (mungkin tidak).
Solusi?
Kami sudah mencoba menandai semua dependensi Xerces Maven sebagai <provided>
atau sebagai <exclusion>
, tapi ini sulit untuk menegakkan (terutama dengan tim besar) mengingat bahwa artefak memiliki begitu banyak alias ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, dll). Selain itu, libs / kerangka kerja pihak ketiga kami tidak dapat berjalan pada versi JAXP atau versi yang disediakan oleh wadah servlet.
Bagaimana kita bisa mengatasi masalah ini dengan Maven? Apakah kita harus melakukan kontrol yang halus atas ketergantungan kita, dan kemudian bergantung pada pemuatan kelas berjenjang? Apakah ada cara untuk secara global mengecualikan semua dependensi Xerces, dan memaksa semua kerangka / lib kita untuk menggunakan versi JAXP?
PEMBARUAN : Joshua Spiewak telah mengunggah versi tambalan Xerces build skrip ke XERCESJ-1454 yang memungkinkan untuk diunggah ke Maven Central. Pilih / tonton / berkontribusi untuk masalah ini dan mari kita selesaikan masalah ini untuk selamanya.