Search code examples
javaxmljaxb

JAXB returns null for list of nested elements


I'm using xml with one element which contains all other elements, all described with attributes like this:

<produktyLecznicze stanNaDzien="2023-05-26" xmlns="http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0">
    <produktLeczniczy nazwaProduktu="Zoledronic acid Fresenius Kabi" rodzajPreparatu="ludzki" nazwaPowszechnieStosowana="Acidum zoledronicum" moc="4 mg/5 ml" postac="Koncentrat do sporządzania roztworu do infuzji" podmiotOdpowiedzialny="Fresenius Kabi Polska Sp. z o.o." typProcedury="DCP" numerPozwolenia="20708" waznoscPozwolenia="Bezterminowy" kodATC="M05BA08" id="100000014">
        <opakowania>
            <opakowanie wielkosc="1" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023652" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="2"/>
            <opakowanie wielkosc="4" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023669" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="3"/>
            <opakowanie wielkosc="10" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023676" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="4"/>
        </opakowania>
        <substancjeCzynne>
            <substancjaCzynna>Acidum zoledronicum</substancjaCzynna>
        </substancjeCzynne>
    </produktLeczniczy>
...
</produktyLecznicze>

Till now I've made classes for container element and subelement like this:

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "produktyLecznicze", namespace="http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0")
public class ProduktyLecznicze {

    @XmlAttribute(name = "stanNaDzien")
    private String stanNaDzien;

    @XmlElement(name = "produktLeczniczy")
    private List<ProduktLeczniczy> produktyLecznicze;

}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "produktLeczniczy", namespace = "http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0")
public class ProduktLeczniczy {

    @XmlAttribute(name ="nazwaProduktu")
    private String nazwaProduktu;
    @XmlAttribute(name ="rodzajPreparatu")
    private String rodzajPreparatu;
    @XmlAttribute(name ="nazwaPowszechnieStosowana")
    private String nazwaPowszechnieStosowana;
    @XmlAttribute(name ="moc")
    private String moc;
    @XmlAttribute(name ="postac")
    private String postac;
    @XmlAttribute(name ="podmiotOdpowiedzialny")
    private String podmiotOdpowiedzialny;
    @XmlAttribute(name ="typProcedury")
    private String typProcedury;
    @XmlAttribute(name ="numerPozwolenia")
    private String numerPozwolenia;
    @XmlAttribute(name ="waznoscPozwolenia")
    private String waznoscPozwolenia;
    @XmlAttribute(name ="kodATC")
    private String kodATC;
    @XmlAttribute(name ="id")
    private int id;
}

JAXB reads attribute of container element properly but returns null for list of nested elements. I want to find out why does it happen, and what to do in order to read this nested element properly.


Solution

  • Make the following changes:

    1. Add package-info.java to the package containing your classes:
    @jakarta.xml.bind.annotation.XmlSchema(
            namespace = "http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0",
            elementFormDefault = XmlNsForm.QUALIFIED
    )
    package YOUR_PACKAGE_NAME_HERE;
    
    import jakarta.xml.bind.annotation.XmlNsForm;
    
    1. Once you have done this, you can change the @XmlRootElement annotation on your ProduktyLecznicze class:
    ...
    @XmlRootElement
    public class ProduktyLecznicze {
        ...
    }
    

    You don't need the name or namespace attributes.

    1. Remove the @XmlRootElement annotation from the ProduktyLeczniczy class.

    Basically, let the package-info handle the namespace. And only use @XmlRootElement on the actual root class.

    Now, when you unmarshal the XML you will see the element values which are currently null.


    Probably don't need to add this, but: if you want to see the rest of the XML data (nested below <produktLeczniczy>), you will need to create those equivalent classes: Opakowania, Opakowanie, and SubstancjeCzynne.