Skip to content

Conversation

@lawrencewang49
Copy link

Purpose of this PR

This PR addresses an issue discovered during Nondex testing. Nondex is a tool that repeatedly runs JUnit tests with different thread schedules to detect nondeterministic behavior in concurrent or order-sensitive code. The original Project class did not specify a fixed order for JAXB-serialized fields, and so fields such as scenes, structure, application, transport, and arrangement were marshaled in an undefined order, which could vary between runs. Nondex detected that the DawProject.validate tests sometimes failed because XML validation against the schema depended on the order of elements, making the test non-deterministic.

Changes Made:

  • Added @XmlType(propOrder = {"scenes", "structure", "application", "transport", "arrangement"}) to the Project class.
  • This explicitly defines the JAXB serialization order, eliminating nondeterminism in the generated XML

Results:

  • Ensures consistent serialization for schema validation and other XML consumers
  • Eliminates nondeterministic test failures that for tests that validate project XML

Steps to reproduce

  1. Add the following to plugins in build.gradle: id 'edu.illinois.nondex' version '2.2.1'
  2. Add the following to the bottom of build.gradle: apply plugin: 'edu.illinois.nondex'
  3. Add the following above dependencies in build.gradle:
tasks.withType(Test) {
    testLogging {
        events "passed", "skipped", "failed" 
        exceptionFormat "full" 
        showExceptions true
        showCauses true
        showStackTraces true
    }
}
  1. Run ./gradlew nondexTest --tests "com.bitwig.dawproject.DawProjectTest.createAudioExample",
    ./gradlew nondexTest --tests "com.bitwig.dawproject.DawProjectTest.createMIDIAutomationInClipsExample",
    ./gradlew nondexTest --tests "com.bitwig.dawproject.DawProjectTest.validateComplexDawProject",
    and ./gradlew nondexTest --tests "com.bitwig.dawproject.DawProjectTest.validateDawProject",
    and you should see output similar to below:
DawProjectTest > createAudioExample FAILED
    java.io.IOException: jakarta.xml.bind.UnmarshalException
     - with linked exception:
    [org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 16; cvc-complex-type.2.4.a: Invalid content was found starting with element 'Transport'. One of '{Application}' is expected.]
        at com.bitwig.dawproject.DawProject.validate(DawProject.java:242)
        at com.bitwig.dawproject.DawProjectTest.saveTestProject(DawProjectTest.java:361)
        at com.bitwig.dawproject.DawProjectTest.createAudioExample(DawProjectTest.java:295)
        at com.bitwig.dawproject.DawProjectTest.createAudioExample(DawProjectTest.java:178)

        Caused by:
        jakarta.xml.bind.UnmarshalException
         - with linked exception:
        [org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 16; cvc-complex-type.2.4.a: Invalid content was found starting with element 'Transport'. One of '{Application}' is expected.]
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:296)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:539)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:224)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:152)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:205)
            at app//com.bitwig.dawproject.DawProject.validate(DawProject.java:240)

or

DawProjectTest > createAudioExample FAILED
    java.io.IOException: jakarta.xml.bind.UnmarshalException
     - with linked exception:
    [org.xml.sax.SAXParseException; lineNumber: 22; columnNumber: 14; cvc-complex-type.2.4.d: Invalid content was found starting with element 'Scenes'. No child element is expected at this point.]
        at com.bitwig.dawproject.DawProject.validate(DawProject.java:242)
        at com.bitwig.dawproject.DawProjectTest.saveTestProject(DawProjectTest.java:361)
        at com.bitwig.dawproject.DawProjectTest.createAudioExample(DawProjectTest.java:295)
        at com.bitwig.dawproject.DawProjectTest.createAudioExample(DawProjectTest.java:178)

        Caused by:
        jakarta.xml.bind.UnmarshalException
         - with linked exception:
        [org.xml.sax.SAXParseException; lineNumber: 22; columnNumber: 14; cvc-complex-type.2.4.d: Invalid content was found starting with element 'Scenes'. No child element is expected at this point.]
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:296)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:539)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:224)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:152)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:205)
            at app//com.bitwig.dawproject.DawProject.validate(DawProject.java:240)

or

DawProjectTest > createMIDIAutomationInClipsExample FAILED
    java.io.IOException: jakarta.xml.bind.UnmarshalException
     - with linked exception:
    [org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 14; cvc-complex-type.2.4.a: Invalid content was found starting with element 'Scenes'. One of '{Structure, Application}' is expected.]
        at com.bitwig.dawproject.DawProject.validate(DawProject.java:242)
        at com.bitwig.dawproject.DawProjectTest.saveTestProject(DawProjectTest.java:361)
        at com.bitwig.dawproject.DawProjectTest.createMIDIAutomationExample(DawProjectTest.java:348)
        at com.bitwig.dawproject.DawProjectTest.createMIDIAutomationInClipsExample(DawProjectTest.java:195)

        Caused by:
        jakarta.xml.bind.UnmarshalException
         - with linked exception:
        [org.xml.sax.SAXParseException; lineNumber: 19; columnNumber: 14; cvc-complex-type.2.4.a: Invalid content was found starting with element 'Scenes'. One of '{Structure, Application}' is expected.]
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:296)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:539)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:224)
            at app//org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:152)
            at app//jakarta.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:205)
            at app//com.bitwig.dawproject.DawProject.validate(DawProject.java:240)

@lawrencewang49 lawrencewang49 changed the title fix: enforce JAXB field order in Project with @XmlType(propOrder fix: enforce JAXB field order in Project with @XmlType(propOrder) Nov 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant