Flexible marshalling with JAXB

后端 未结 2 1997
一生所求
一生所求 2021-01-23 05:39

I\'m hoping to have a flexible way of marshalling objects. A verbose version for single objects and a less-verbose version for multiple object versions.

For example, co

相关标签:
2条回答
  • 2021-01-23 05:44

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

    Your question is tagged EclipseLink, if you are using EclipseLink JAXB (MOXy) you can take advantage of the external binding document to apply a second mapping to the Department class.


    ContextResolver

    In a JAX-RS environment you can leverage MOXy's external binding document through a ContextResolver:

    import java.io.*;
    import java.util.*;     
    import javax.ws.rs.Produces;
    import javax.ws.rs.ext.*;
    import javax.xml.bind.*;
    import org.eclipse.persistence.jaxb.JAXBContextFactory;
    
    @Provider
    @Produces({"application/xml", "application/json"})
    public class DepartmentContextResolver implements ContextResolver<JAXBContext> {
    
        private JAXBContext jc;
    
        public DepartmentContextResolver() {
            try {
                Map<String, Object> props = new HashMap<String, Object>(1);
                props.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "example/bindings.xml");
                jc = JAXBContext.newInstance(new Class[] {Department.class} , props);
            } catch(JAXBException e) {
                throw new RuntimeException(e);
            } 
        }
    
        public JAXBContext getContext(Class<?> clazz) {
            if(Department.class == clazz) {
                return jc;
            }
            return null;
        }
    
    
    } 
    

    For More Information

    • http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html
    • http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-35.html

    External Binding Document

    By default MOXy's external binding document is used to augment the annotated model, but if you set the xml-mapping-metadata-complete flag it will completely override the annotations allowing you to apply a completely different mapping:

    <xml-bindings
        xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
        package-name="example"
        xml-mapping-metadata-complete="true">
        ...
    </xml-bindings>
    

    For More Information

    • http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html
    • http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html

    UPDATE

    This update is to address a number of questions you asked in one of your comments:

    1 . Should/can each ContentResolver have its own binding file?

    Yes each ContextResolver should have its own binding file. The main reason for introducing a new ContextResolver is to represent a secondary mapping.

    2 . Can I have more than one for each ContentResolver (this would give me a number of renderings of the same class, creating a 'view' of sorts), perhaps specifying its location in the constructor?

    For a single ContextResolver you can express the metadata across multiple binding files, but they will be combined into a single set of mappings. This means that a single ContentResolver cannot have multiple views of a single class. A separate ContextResolver is used to represent a secondary mapping.

    3 . Where should the binding files reside?

    I recommend loading the metadata file from the class path.

    • http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html

    4 . I can see how the ContentResolver could be easily specified in a Resource's GET method, but how would this be done if the object is embedded in another (JPA) object? In the embedded object's getter/setter?

    Your JAX-RS implementation should pick up your ContextResolver because it is annotated with @Provider. The ContextResolver used for a class will depend on how you implement the getContext method:

    public JAXBContext getContext(Class<?> clazz) {
        if(Customer.class == clazz) {
            return jc;
        }
        return null;
    }
    
    0 讨论(0)
  • 2021-01-23 05:56

    Here comes another idea. Could be a bad idea but somewhat easy.

    class Department {
    
        @XmlElement(required = true)
        public Link getSelf() {
            return self;
        }
    
        @XmlElement(required = false) // default
        public Link getParent() {
            if (verbose) {
                return parent;
            }
            return null;
        }
    
        @XmlElement(required = false) // default
        public String getSpecialty() {
            if (verbose) {
                return specialty;
            }
            return null;
        }
    
        @XmlTransient
        private boolean verbose;
    }
    
    0 讨论(0)
提交回复
热议问题