Untuk menyatukan apa yang telah dinyatakan atau diisyaratkan oleh orang lain, aturan yang digunakan JAXB XJC untuk memutuskan apakah akan memberikan @XmlRootElement
anotasi pada kelas yang dihasilkan atau tidak adalah tidak sepele ( lihat artikel ini ).
@XmlRootElement
ada karena runtime JAXB memerlukan informasi tertentu untuk menyusun / menghapus objek yang diberikan, khususnya nama elemen XML dan namespace. Anda tidak bisa begitu saja menyerahkan benda lama ke Marshaller. @XmlRootElement
memberikan informasi ini.
Anotasi hanyalah kenyamanan, namun - JAXB tidak memerlukannya. Alternatif untuk menggunakan JAXBElement
objek pembungkus, yang memberikan informasi yang sama seperti @XmlRootElement
, tetapi dalam bentuk objek, bukan anotasi.
Namun, JAXBElement
objek canggung untuk dibangun, karena Anda perlu mengetahui nama elemen XML dan namespace, yang logika bisnis biasanya tidak.
Untungnya, ketika XJC menghasilkan model kelas, itu juga menghasilkan kelas yang disebut ObjectFactory
. Ini sebagian ada untuk kompatibilitas mundur dengan JAXB v1, tetapi juga ada sebagai tempat bagi XJC untuk menempatkan metode pabrik yang dihasilkan yang membuat JAXBElement
pembungkus di sekitar objek Anda sendiri. Ini menangani nama XML dan namespace untuk Anda, jadi Anda tidak perlu khawatir tentang hal itu. Anda hanya perlu melihat melalui ObjectFactory
metode (dan untuk skema besar, bisa ada ratusan dari mereka) untuk menemukan yang Anda butuhkan.
new ObjectFactory().createPositionReport(positionReport)
pengembalianJAXBElement<PositionReport>
JXBElement
? Dalam kasus saya, metode pabrik adalah 0-arity dan hanya mengembalikannew
objek. (Mengapa beberapa kelas diberikan pembungkus pembungkus JAXBElement dan yang lainnya tidak?) Saya kira dalam hal itu kita harus membuat pembungkus sendiri?Ini disebutkan di bagian bawah posting blog yang sudah ditautkan di atas tetapi ini berfungsi seperti hadiah untuk saya:
sumber
jc
di cuplikan di atas?Seperti yang diisyaratkan pada salah satu jawaban di atas, Anda tidak akan mendapatkan XMLRootElement pada elemen root Anda jika di XSD tipenya didefinisikan sebagai tipe yang dinamai, karena tipe yang dinamai itu dapat digunakan di tempat lain di XSD Anda. Coba pilih jenis anonim, yaitu alih-alih:
Anda akan memiliki:
sumber
@XmlRootElement tidak diperlukan untuk unmarshalling - jika seseorang menggunakan bentuk 2 parameter Unmarshaller # unmarshall.
Jadi, jika bukannya melakukan:
yang harus dilakukan:
Kode yang terakhir tidak akan memerlukan penjelasan @XmlRootElement di tingkat kelas UserType.
sumber
String pathname = "file.xml"; InputStream stream = new FileInputStream(pathname); JAXBContext jaxbContext = JAXBContext.newInstance(UserType.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader someSource = factory.createXMLEventReader(stream); JAXBElement<UserType> userElement = jaxbUnmarshaller.unmarshal(someSource, UserType.class); UserType user = userElement.getValue();
Jawaban Joe (Joe 26 Juni 2009 di 17:26) melakukannya untuk saya. Jawaban sederhananya adalah tidak adanya anotasi @XmlRootElement tidak menjadi masalah jika Anda membuat JAXBElement. Hal yang membingungkan saya adalah ObjectFactory yang dihasilkan memiliki 2 metode createMyRootElement - yang pertama tidak memerlukan parameter dan memberikan objek yang tidak terbungkus, yang kedua mengambil objek yang tidak terbungkus dan mengembalikannya dengan JAXBElement, dan menyatakan bahwa JAXBElement berfungsi dengan baik. Inilah kode dasar yang saya gunakan (saya baru dalam hal ini, jadi minta maaf jika kode tidak diformat dengan benar dalam balasan ini), sebagian besar diambil dari teks tautan :
sumber
Anda dapat memperbaiki masalah ini menggunakan pengikatan dari Cara menghasilkan @XmlRootElement Kelas untuk Jenis Basis di XSD? .
Berikut ini adalah contoh dengan Maven
Ini adalah
binding.xjb
konten filesumber
Seperti yang Anda tahu jawabannya adalah menggunakan ObjectFactory (). Berikut adalah contoh kode yang bekerja untuk saya :)
sumber
Itu tidak bekerja untuk kita juga. Tetapi kami memang menemukan artikel yang dikutip secara luas yang menambahkan BEBERAPA latar belakang ... Saya akan menautkannya di sini demi orang berikutnya: http://weblogs.java.net/blog/kohsuke/archive/2006/03 /why_does_jaxb_p.html
sumber
Setelah sruggling selama dua hari saya menemukan solusi untuk masalah ini. Anda dapat menggunakan kelas ObjectFactory untuk mencari solusi untuk kelas-kelas yang tidak memiliki @XmlRootElement . ObjectFactory memiliki metode kelebihan beban untuk membungkusnya di sekitar JAXBElement.
Metode: 1 melakukan penciptaan objek secara sederhana.
Metode: 2 akan membungkus objek dengan @JAXBElement .
Selalu gunakan Metode: 2 untuk menghindari javax.xml.bind.MarshalException - dengan pengecualian terkait kehilangan anotasi @XmlRootElement.
Silakan temukan kode sampel di bawah ini
Metode: 1 melakukan penciptaan objek secara sederhana
Metode: 2 akan membungkus objek dengan @JAXBElement .
Contoh kode kerja:
sumber
Seandainya pengalaman saya tentang masalah ini memberi seseorang Eureka! saat .. saya akan menambahkan berikut ini:
Saya juga mendapatkan masalah ini, ketika menggunakan file xsd yang saya hasilkan menggunakan opsi menu "Hasilkan xsd dari Instance dokumen" IntelliJ.
Ketika saya menerima semua default dari alat ini, itu menghasilkan file xsd yang ketika digunakan dengan jaxb, menghasilkan file java tanpa
@XmlRootElement
. Saat runtime ketika saya mencoba untuk marshal saya mendapat pengecualian yang sama seperti yang dibahas dalam pertanyaan ini.Saya kembali ke alat IntellJ, dan melihat opsi default di drop-down "Desgin Type" (yang tentu saja saya tidak mengerti .. dan masih tidak jika saya jujur) adalah:
Jenis Desgin:
Saya mengubah ini menjadi
, sekarang menghasilkan xsd (berbeda) yang berbeda, yang menghasilkan
@XmlRootElement
saat digunakan dengan jaxb. Tidak bisa mengatakan saya mengerti apa yang masuk dan keluar dari itu, tapi itu berhasil untuk saya.sumber
Dengan build Maven, Anda dapat menambahkan
@XmlRootElement
anotasidengan "
jaxb2-basics-annotate
" plug-in.Lihat informasi lebih lanjut: lihat
Konfigurasikan Maven untuk menghasilkan kelas dari Skema XML menggunakan JAXB
dan pembuatan kode JAXB XJC
sumber
Pembungkus JAXBElement berfungsi untuk kasus di mana tidak ada
@XmlRootElement
yang dihasilkan oleh JAXB. Pembungkus ini tersedia diObjectFactory
kelas yang dihasilkan olehmaven-jaxb2-plugin
. Untuk misalnya:sumber
Apakah Anda mencoba mengubah xsd Anda seperti ini?
sumber
Untuk menggunakannya, Anda harus mengkonfigurasi xml binding sebelum dikompilasi dengan wsimport, mengatur generateElementProperty sebagai false.
sumber
<jaxb:bindings> ... <jaxws:bindings> ... </jaxws:bindings> ... </jaxb:bindings>
Topiknya cukup lama tetapi masih relevan dalam konteks bisnis perusahaan. Saya mencoba untuk menghindari menyentuh xsds agar mudah memperbaruinya di masa depan. Inilah solusi saya ..
1. Sebagian besar
xjc:simple
sudah cukupSebagian besar akan membuat XmlRootElements untuk mengimpor definisi xsd.
2. Bagi
jaxb2-maven-plugin
eksekusi AndaSaya temui bahwa itu membuat perbedaan besar jika Anda mencoba untuk menghasilkan kelas dari beberapa definisi xsd daripada definisi eksekusi per xsd.
Jadi, jika Anda memiliki definisi dengan banyak
<source>
, daripada hanya mencoba untuk membaginya:Generator tidak akan menangkap fakta bahwa satu kelas mungkin cukup dan karenanya membuat kelas khusus per eksekusi. Dan itulah yang saya butuhkan;).
sumber