javadatejaxbmarshalling

JAXBException: Property appears in @XmlType.propOrder, but no such property exists


I have a save command that does simple marshalling:

//save command
...
        try {
            JAXBContext context = JAXBContext.newInstance(CollectionManager.class);            
            Marshaller marshaller = context.createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(collectionManager, new File("out.xml"));
        } catch (JAXBException e) {
            e.printStackTrace();
        }
...

here is collectionManager with PrioriyQueue storing MusicBands

@XmlRootElement(name = "Collection")
@XmlAccessorType(XmlAccessType.FIELD)
public class CollectionManager {

...

    @XmlElement(name = "MusicBand")
    private  PriorityQueue<MusicBand> musicBandsQueue;

...

here are MusicBand class fields:

@XmlType(propOrder = {"id","name","coordinates", "numberOfParticipants", "creationDate", "albumsCount", "establishmentDate", "genre", "label"})
public class MusicBand implements Comparable<MusicBand> {
    private long id;
    private String name;
    private Coordinates coordinates; 
    private java.util.Date creationDate; 
    private int numberOfParticipants; 
    private Long albumsCount;
    private java.time.ZonedDateTime establishmentDate;
    private MusicGenre genre;
    private Label label;

...

So, when I exclude "creationDate" from propOrder, I almost get the desired xml file except the "establishmentDate" field. idk what happens to it.

here's how it looks.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Collection>
    <MusicBand>
        <id>1</id>
        <name>asd</name>
        <coordinates>
            <x>1</x>
            <y>1</y>
        </coordinates>
        <numberOfParticipants>1</numberOfParticipants>
        <albumsCount>1</albumsCount>
        <establishmentDate/>
        <genre>SOUL</genre>
        <label>
            <bands>2</bands>
            <name>asd</name>
        </label>
    </MusicBand>
    <previousIds>1</previousIds>
</Collection>

But after if I include "creationDate" in propOrder, I get an exception. Here is the stack trace:

org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Property creationDate appears in @XmlType.propOrder, but no such property exists. Maybe you meant coordinates? 
        this problem is related to the following location:
                at ru.itmo.prog.lab5.collection.MusicBand.MusicBand
                at private java.util.PriorityQueue ru.itmo.prog.lab5.CLI.Managers.CollectionManager.musicBandsQueue
                at ru.itmo.prog.lab5.CLI.Managers.CollectionManager

        at org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:83)
        at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:421)      
        at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:255)
        at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1115)
        at org.glassfish.jaxb.runtime.v2.ContextFactory.createContext(ContextFactory.java:144)
        at org.glassfish.jaxb.runtime.v2.JAXBContextFactory.createContext(JAXBContextFactory.java:44)
        at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:373)
        at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:605)
        at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:546)
        at ru.itmo.prog.lab5.CLI.Commands.Save.execute(Save.java:22)
        at ru.itmo.prog.lab5.CLI.Managers.CommandManager.executeCommand(CommandManager.java:58)
        at ru.itmo.prog.lab5.Main.main(Main.java:19)

Don't have any ideas as to why that could be a problem. date marshalling works fine in baeldung's jaxb guide. Any help would be appreciated.


Solution

  • In order to solve the problem, i reached out to the next problems on StackOverflow (it's worth reading all of them if you have similar issue to me): first, second. So in one of the comments i found an open-source library threeten-jaxb, which helps with @JavaTypeAdapter annotations. In my case, i needed a class for ZonedDateTime field, which i found there, it's called ZonedDateTimeXmlAdapter. As for the java.util.Date field, i just created my personal DateAdapter class as described in the first problem i mentioned above.

    Important note: i had to put annotations above getters, not the actual fields, otherwise i would get an exception that there are 2 or more properties named the same way. Didn't actually figure out as to why it is so, but rather just tried different ways of putting annotations in different places...

    The only little drawback that's left because of a custom DateAdapter class is that I lose a town in date tag in xml, but in my case it's not so important. Here's what i have in collection: created: Thu Mar 14 12:35:50 MSK 2024 and here's what i get in xml:<creationDate>2024-03-14 12:35:50</creationDate> Didn't find a proper class in threeten library to fix this.

    upd: managed to fix the annotations problem (turned out i had a lack of jaxb package knowledge) so, in order to work properly, i put annotations like this in two classes, my collection:

    @XmlType(propOrder = { "id", "name", "coordinates", "numberOfParticipants", "creationDate", "albumsCount",
            "establishmentDate", "genre", "label" })
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class MusicBand implements Comparable<MusicBand> {
        @XmlAttribute
        private long id; 
        @XmlElement(required = true)
        private String name;
        @XmlElement(required = true)
        private Coordinates coordinates;
        @XmlElement(required = true)
        private java.util.Date creationDate;
        @XmlElement(required = true)
        private int numberOfParticipants;
        @XmlElement
        private Long albumsCount;
        @XmlElement
        @XmlJavaTypeAdapter(ZonedDateTimeXmlAdapter.class)
        private java.time.ZonedDateTime establishmentDate;
        @XmlElement(required = true)
        private MusicGenre genre;
        @XmlElement(required = true)
        private Label label;
    //setters getters etc
    

    my collection manager:

    @XmlRootElement(name = "MusicBandCollection")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class CollectionManager {
        @XmlElement(name = "musicBand")
        @XmlElementWrapper(name = "musicBands")
        private PriorityQueue<MusicBand> musicBandsQueue;
        private final static LocalDateTime InitilizationDate = LocalDateTime.now();
        @XmlTransient
        private ArrayList<Long> previousIds = new ArrayList<Long>();
    //setters getters etc