Search code examples
javajaxbxjc

Changing the method name of a XJC generated class


I am attempting to write a monitoring system that allows provides status of external system states... Through pinging servers, reviewing log elements, querying databases, hitting web services, etc. Since each application has unique behaviors, the monitoring system needs to be flexible, to allow the monitor to best fit these behaviors.

So here is part of XSD that is used to create the "Test" class which allows the user to build a monitor:

<xs:element name="Test">
    <xs:complexType>
        <xs:sequence maxOccurs="unbounded" >
            <xs:element ref="Ping"/>
            <xs:element ref="CheckWebService"/>
            <xs:element ref="CheckDB"/>
            <xs:element ref="ExecuteScript"/>
            <xs:element ref="CheckJMS"/>
            <xs:element ref="CheckLog" />
        </xs:sequence>
        <xs:attribute name="testTitle"/>
    </xs:complexType>
</xs:element>

Which running through XJC (through the Maven JAXB plugin) produces:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "pingsAndCheckLogsAndCheckJMs"
})
@XmlRootElement(name = "Test")
public class Test
    implements Serializable
{

    private final static long serialVersionUID = 1L;
    @XmlElements({
        @XmlElement(name = "Ping", required = true, type = Ping.class),
        @XmlElement(name = "CheckLog", required = true, type = CheckLog.class),
        @XmlElement(name = "CheckJMS", required = true, type = CheckJMS.class),
        @XmlElement(name = "ExecuteScript", required = true, type = ExecuteScript.class),
        @XmlElement(name = "CheckDB", required = true, type = CheckDB.class),
        @XmlElement(name = "CheckWebService", required = true, type = CheckWebService.class)
    })
    protected List<Serializable> pingsAndCheckLogsAndCheckJMs;
    @XmlAttribute(name = "testTitle")
    @XmlSchemaType(name = "anySimpleType")
    protected String testTitle;

    public List<Serializable> getPingsAndCheckLogsAndCheckJMs() {
        if (pingsAndCheckLogsAndCheckJMs == null) {
            pingsAndCheckLogsAndCheckJMs = new ArrayList<Serializable>();
        }
        return this.pingsAndCheckLogsAndCheckJMs;
    }

    public String getTestTitle() {
        return testTitle;
    }

    public void setTestTitle(String value) {
        this.testTitle = value;
    }
}

My question is, how could I rename the pingsAndCheckLogsAndCheckJMs method, since every time I add a new test type (Ping/CherckDB/CheckLog...) this method name changes, as well as the XML tag when I marshal the object is ugly too.


Solution

  • You need to specify a binding to explicitly name the property.

    Here is example of how to do it inline. See Customizing JAXB Bindings for more information.

    Summary: You need to add 2 attributes to <xs:schema> element:

    <xs:schema ...
               xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
               jxb:version="1.0">
    

    and the following inside the <xs:sequence> element, of course naming the property what you deem appropriate:

    <xs:sequence maxOccurs="unbounded">
        <xs:annotation>
            <xs:appinfo>
                <jxb:property name="foo"/>
            </xs:appinfo>
        </xs:annotation>
        ...
    

    Full Minimal, Complete, and Verifiable example (MCVE) below:

    XSD file

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema version="1.0" targetNamespace="http://example.com/test"
               xmlns="http://example.com/test"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
               jxb:version="1.0">
        <xs:element name="Test">
            <xs:complexType>
                <xs:sequence maxOccurs="unbounded">
                    <xs:annotation>
                        <xs:appinfo>
                            <jxb:property name="foo"/>
                        </xs:appinfo>
                    </xs:annotation>
                    <xs:element ref="Ping"/>
                    <xs:element ref="CheckLog"/>
                </xs:sequence>
                <xs:attribute name="testTitle"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="Ping">
            <xs:complexType>
                <xs:sequence>
                </xs:sequence>
                <xs:attribute name="action" type="xs:string"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="CheckLog">
            <xs:complexType>
                <xs:sequence>
                </xs:sequence>
                <xs:attribute name="action" type="xs:string"/>
            </xs:complexType>
        </xs:element>
    </xs:schema>
    

    Test

    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;
    
    import com.example.test.CheckLog;
    import com.example.test.Ping;
    import com.example.test.Test;
    
    public class Test8 {
        public static void main(String[] args) throws Exception {
            Test root = new Test();
            root.setTestTitle("My title");
            root.getFoo().add(newPing("ping 1"));
            root.getFoo().add(newCheckLog("check log 1"));
            root.getFoo().add(newPing("ping 2"));
    
            JAXBContext jaxbContext = JAXBContext.newInstance(Test.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.marshal(root, System.out);
        }
        private static Ping newPing(String action) {
            Ping obj = new Ping();
            obj.setAction(action);
            return obj;
        }
        private static CheckLog newCheckLog(String action) {
            CheckLog obj = new CheckLog();
            obj.setAction(action);
            return obj;
        }
    }
    

    Output

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Test xmlns="http://example.com/test" testTitle="My title">
        <Ping action="ping 1"/>
        <CheckLog action="check log 1"/>
        <Ping action="ping 2"/>
    </Test>
    

    As you can see, the method is now named getFoo(), and there is no uglyness in the generated XML.

    The above was done using jdk1.8.0_151.