Java Code to XML/XSD without using Annotation

后端 未结 3 1179
一个人的身影
一个人的身影 2020-12-30 07:40

I need to marshall and unmarshall a Java class to XML. The class in not owned by me, that I cannot add anotations so that I can use JAXB.

Is there a good way to conv

相关标签:
3条回答
  • 2020-12-30 07:52

    Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

    DOMAIN MODEL

    I will use the following domain model for this answer. Note how there are no JAXB annotations on the model.

    Customer

    package forum11693552;
    
    import java.util.*;
    
    public class Customer {
    
        private String firstName;
        private String lastName;
        private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
    
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public List<PhoneNumber> getPhoneNumbers() {
            return phoneNumbers;
        }
    
        public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
            this.phoneNumbers = phoneNumbers;
        }
    
    }
    

    PhoneNumber

    package forum11693552;
    
    public class PhoneNumber {
    
        private String type;
        private String number;
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public String getNumber() {
            return number;
        }
    
        public void setNumber(String number) {
            this.number = number;
        }
    
    }
    

    OPTION #1 - Any JAXB (JSR-222) Implementation

    JAXB is configurartion by exception, this means you only need to add annotations where you want the mapping behaviour to differ from the default. Below is a link to an example demonstrating how to use any JAXB impl without annotations:

    Demo

    package forum11693552;
    
    import javax.xml.bind.*;
    import javax.xml.namespace.QName;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Customer.class);
    
            Customer customer = new Customer();
            customer.setFirstName("Jane");
            customer.setLastName("Doe");
    
            PhoneNumber workPhone = new PhoneNumber();
            workPhone.setType("work");
            workPhone.setNumber("555-1111");
            customer.getPhoneNumbers().add(workPhone);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
            marshaller.marshal(rootElement, System.out);
        }
    
    }
    

    Output

    <customer>
        <firstName>Jane</firstName>
        <lastName>Doe</lastName>
        <phoneNumbers>
            <number>555-1111</number>
            <type>work</type>
        </phoneNumbers>
    </customer>
    

    For More Information

    • http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/TheBasics

    OPTION #2 - EclipseLink JAXB (MOXy)'s External Mapping Document

    If you do want to customize the mappings, then you may be interested in MOXy's external mapping document extension. A sample mapping document looks like the following:

    oxm.xml

    <?xml version="1.0"?>
    <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
        package-name="forum11693552">
        <java-types>
            <java-type name="Customer">
                <xml-root-element />
                <java-attributes>
                    <xml-element java-attribute="firstName" name="first-name" />
                    <xml-element java-attribute="lastName" name="last-name" />
                    <xml-element java-attribute="phoneNumbers" name="phone-number" />
                </java-attributes>
            </java-type>
            <java-type name="PhoneNumber">
                <java-attributes>
                    <xml-attribute java-attribute="type" />
                    <xml-value java-attribute="number" />
                </java-attributes>
            </java-type>
        </java-types>
    </xml-bindings>
    

    jaxb.properties

    To enable MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):

    javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    

    Demo

    When using EclipseLink MOXy as your JAXB provider (see), you can leverage the external mapping document when you bootstrap your JAXBContext

    package forum11693552;
    
    import java.util.*;
    import javax.xml.bind.*;
    import javax.xml.namespace.QName;
    import org.eclipse.persistence.jaxb.JAXBContextFactory;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            Map<String, Object> properties = new HashMap<String,Object>(1);
            properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11693552/oxm.xml");
            JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);
    
            Customer customer = new Customer();
            customer.setFirstName("Jane");
            customer.setLastName("Doe");
    
            PhoneNumber workPhone = new PhoneNumber();
            workPhone.setType("work");
            workPhone.setNumber("555-1111");
            customer.getPhoneNumbers().add(workPhone);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
            marshaller.marshal(rootElement, System.out);
        }
    
    }
    

    Output

    <?xml version="1.0" encoding="UTF-8"?>
    <customer>
       <first-name>Jane</first-name>
       <last-name>Doe</last-name>
       <phone-number type="work">555-1111</phone-number>
    </customer>
    

    For More Information

    • http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
    • http://blog.bdoughan.com/2012/04/extending-jaxb-representing-metadata-as.html
    0 讨论(0)
  • 2020-12-30 07:55

    You could write a custom XmlAdapter and annotate fields of the constrained type with a XmlJavaTypeAdapter annotation. The basics would be something like this:

    public enum CannotBeAnnotated { value1, value2; }
    @XmlRootElement(name="client")
    public class ClientClass {
        @XmlJavaTypeAdapter(Bridge.class)
        public CannotBeAnnotated;
    }
    @XmlRootElement(name="representation")
    public class XmlType {
        @XmlValue
        public String value;
    }
    public class Bridge extends XmlAdapter<XmlType, CannotBeAnnotated>{
        public XmlType marshal(CannotBeAnnotated c) {
            XmlType x=new XmlType(); 
            x.value=c.name();
            return x;
        }
        public CannotBeAnnotated unmarshall(XmlType x) {
            return CannotBeAnnotated.valueOf(x.value);
        }
    }
    

    Of course for enums this would not be useful as JAXB knows how to deal with them. I just picked an enum for simplicity so you can see the idea:

    1. Design an XML representation that you do control
    2. Write an adapter converting that Java type into the desired type
    3. Annotate "client" code referencing the adapter for the desired type
    4. Profit.
    0 讨论(0)
  • 2020-12-30 08:07

    Have you looked at XStream ? It will deserialise/deserialise a standard POJO without annotations or XSDs. You can provide customisations to affect how elements appear in the XML and pretty much works out-of-the-box.

    0 讨论(0)
提交回复
热议问题