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.
sumber
Jawaban:
Ada 2.11.0 JAR (dan sumber JAR!) Dari Xerces di Maven Central sejak 20 Februari 2013! Lihat Xerces di Maven Central . Saya bertanya-tanya mengapa mereka belum menyelesaikan https://issues.apache.org/jira/browse/XERCESJ-1454 ...
Saya telah menggunakan:
dan semua dependensi telah diselesaikan dengan baik - bahkan layak
xml-apis-1.4.01
!Dan apa yang paling penting (dan apa yang tidak jelas di masa lalu) - JAR di Maven Central adalah JAR yang sama dengan
Xerces-J-bin.2.11.0.zip
distribusi resmi .Namun saya tidak dapat menemukan
xml-schema-1.1-beta
versi - itu tidak bisa menjadiclassifier
versi Maven karena ketergantungan tambahan.sumber
xml-apis:xml-apis:1.4.01
adalah lebih baru daripadaxml-apis:xml-apis:2.0.2
?? lihat search.maven.org/...Terus terang, hampir semua yang kami temui berfungsi dengan baik dengan versi JAXP, jadi kami selalu mengecualikan
xml-apis
danxercesImpl
.sumber
java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
saat runtime.Anda bisa menggunakan plugin penegak pakar dengan aturan ketergantungan yang dilarang. Ini akan memungkinkan Anda untuk melarang semua alias yang tidak Anda inginkan dan hanya mengizinkan yang Anda inginkan. Aturan-aturan ini akan gagal membangun proyek Anda ketika dilanggar. Selain itu, jika aturan ini berlaku untuk semua proyek di perusahaan Anda bisa meletakkan konfigurasi plugin di pom induk perusahaan.
Lihat:
sumber
Saya tahu ini tidak menjawab pertanyaan dengan tepat, tetapi untuk ppl datang dari google yang kebetulan menggunakan Gradle untuk manajemen ketergantungan mereka:
Saya berhasil menyingkirkan semua masalah xerces / Java8 dengan Gradle seperti ini:
sumber
Saya kira ada satu pertanyaan yang perlu Anda jawab:
Apakah ada xerces * .jar bahwa semua yang ada di aplikasi Anda dapat hidup?
Jika tidak, Anda pada dasarnya kacau dan harus menggunakan sesuatu seperti OSGI, yang memungkinkan Anda untuk memiliki versi pustaka yang berbeda dimuat secara bersamaan. Berhati-hatilah karena itu pada dasarnya menggantikan masalah versi jar dengan masalah classloader ...
Jika ada versi seperti itu, Anda bisa membuat repositori mengembalikan versi itu untuk semua jenis dependensi. Ini adalah hack yang jelek dan akan berakhir dengan implementasi xerces yang sama di classpath Anda beberapa kali tetapi lebih baik daripada memiliki beberapa versi xerces yang berbeda.
Anda bisa mengecualikan setiap ketergantungan pada xerces dan menambahkan satu ke versi yang ingin Anda gunakan.
Saya ingin tahu apakah Anda dapat menulis semacam strategi resolusi versi sebagai plugin untuk pakar. Ini mungkin solusi terbaik, tetapi jika memungkinkan, perlu dilakukan penelitian dan pengkodean.
Untuk versi yang terdapat dalam lingkungan runtime Anda, Anda harus memastikan itu dihapus dari classpath aplikasi atau guci aplikasi dipertimbangkan terlebih dahulu untuk classloading sebelum folder lib server dipertimbangkan.
Jadi untuk menyelesaikannya: Ini berantakan dan itu tidak akan berubah.
sumber
Ada opsi lain yang belum dieksplorasi di sini: menyatakan dependensi Xerces di Maven sebagai opsional :
Pada dasarnya apa yang dilakukan adalah untuk memaksa semua tanggungan untuk menyatakan mereka versi Xerces atau proyek mereka tidak akan dikompilasi. Jika mereka ingin mengesampingkan ketergantungan ini, mereka dipersilakan untuk melakukannya, tetapi kemudian mereka akan memiliki masalah potensial.
Ini menciptakan insentif yang kuat untuk proyek-proyek hilir untuk:
Tidak semua pengembang melacak dependensi yang baru diperkenalkan (misalnya dengan
mvn dependency:tree
). Pendekatan ini akan segera membawa masalah ini menjadi perhatian mereka.Ini bekerja dengan sangat baik di organisasi kami. Sebelum diperkenalkan, kami dulu hidup di neraka yang sama seperti yang digambarkan OP.
sumber
Setiap proyek pakar harus berhenti tergantung pada xerces, mereka mungkin tidak benar-benar. XML API dan Impl telah menjadi bagian dari Java sejak 1.4. Tidak perlu bergantung pada xerces atau XML API, seperti mengatakan Anda bergantung pada Java atau Swing. Ini implisit.
Jika saya adalah bos dari repo pakar, saya akan menulis skrip untuk menghapus dependensi xerces secara rekursif dan menulis membaca saya yang mengatakan repo ini membutuhkan Java 1.4.
Apa pun yang benar-benar rusak karena mereferensikan Xerces langsung melalui org.apache import memerlukan perbaikan kode untuk membawanya ke level Java 1.4 (dan telah dilakukan sejak tahun 2002) atau solusi pada level JVM melalui lib yang didukung, bukan pada pakar.
sumber
Anda harus men-debug terlebih dahulu, untuk membantu mengidentifikasi tingkat neraka XML Anda. Menurut pendapat saya, langkah pertama adalah menambahkan
ke baris perintah. Jika itu berhasil, maka mulailah mengecualikan perpustakaan. Jika tidak, tambahkan
ke baris perintah.
sumber
Apa yang akan membantu, kecuali untuk tidak termasuk, adalah dependensi modular.
Dengan satu flat classloading (aplikasi mandiri), atau semi-hierarkis (JBoss AS / EAP 5.x) ini merupakan masalah.
Tetapi dengan kerangka kerja modular seperti Modul OSGi dan JBoss , ini tidak begitu menyakitkan lagi. Perpustakaan dapat menggunakan perpustakaan mana pun yang mereka inginkan, secara mandiri.
Tentu saja, masih paling direkomendasikan untuk tetap menggunakan hanya satu implementasi dan versi, tetapi jika tidak ada cara lain (menggunakan fitur tambahan dari lebih banyak lib), maka modularisasi mungkin menyelamatkan Anda.
Contoh yang baik dari Modul JBoss yang sedang beraksi adalah, secara alami, JBoss AS 7 / EAP 6 / WildFly 8 , yang terutama dikembangkan.
Definisi modul contoh:
Dibandingkan dengan OSGi, Modul JBoss lebih sederhana dan lebih cepat. Meskipun kehilangan fitur-fitur tertentu, itu cukup untuk sebagian besar proyek yang (sebagian besar) di bawah kendali satu vendor, dan memungkinkan boot cepat yang menakjubkan (karena penyelesaian dependensi paralel).
Perhatikan bahwa ada upaya modularisasi yang sedang berjalan untuk Java 8 , tetapi AFAIK yang terutama untuk memodulasi JRE itu sendiri, tidak yakin apakah itu akan berlaku untuk aplikasi.
sumber
Rupanya
xerces:xml-apis:1.4.01
tidak lagi di pakar pusat, yang bagaimanapunxerces:xercesImpl:2.11.0
referensi.Ini bekerja untuk saya:
sumber
Teman saya itu sangat sederhana, berikut sebuah contoh:
Dan jika Anda ingin memeriksa di terminal (konsol windows untuk contoh ini) bahwa pohon pakar Anda tidak memiliki masalah:
sumber