Search code examples
springspring-bootjaxbspring-oxm

How to use spring to marshal and unmarshal xml?


I have a spring boot project. I have a few xsds in my project. I have generated the classes using maven-jaxb2-plugin. I have used this tutorial to get a sample spring boot application running.

import org.kaushik.xsds.XOBJECT;

@SpringBootApplication
public class JaxbExample2Application {

public static void main(String[] args) {
    //SpringApplication.run(JaxbExample2Application.class, args);
    XOBJECT xObject = new XOBJECT('a',1,2);

    try {
        JAXBContext jc = JAXBContext.newInstance(User.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(xObject, System.out);

    } catch (PropertyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JAXBException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
}

But my concern is that I need to have all the jaxb classes of the schema mapped. Also is there something in Spring that I can use to make my task easier. I have looked at the Spring OXM project but it had application context configured in xml. Does spring boot have anything that I can use out of the box. Any examples will be helpful.

Edit

I tried xerx593's answer and I ran a simple test using main method

    JaxbHelper jaxbHelper = new JaxbHelper();
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setClassesToBeBound(XOBJECT.class);
    jaxbHelper.setMarshaller(marshaller);
    XOBJECT xOBJECT= (PurchaseOrder)jaxbHelper.load(new StreamSource(new FileInputStream("src/main/resources/PurchaseOrder.xml")));
    System.out.println(xOBJECT.getShipTo().getName());

It ran perfectly fine. Now I just need to plug it in using spring boot.


Solution

  • OXM is definitely the right for you!

    A simple java configuration of a Jaxb2Marshaller would look like:

    //...
    import java.util.HashMap;
    import org.springframework.oxm.jaxb.Jaxb2Marshaller;
    //...
    
    @Configuration
    public class MyConfigClass {
        @Bean
        public Jaxb2Marshaller jaxb2Marshaller() {
            Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
            marshaller.setClassesToBeBound(new Class[]{
               //all the classes the context needs to know about
               org.kaushik.xsds.All.class,
               org.kaushik.xsds.Of.class,
               org.kaushik.xsds.Your.class,
               org.kaushik.xsds.Classes.class
            });
            // "alternative/additiona - ly":
              // marshaller.setContextPath(<jaxb.context-file>)
              // marshaller.setPackagesToScan({"com.foo", "com.baz", "com.bar"});
    
            marshaller.setMarshallerProperties(new HashMap<String, Object>() {{
              put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
              // set more properties here...
            }});
    
            return marshaller;
        }
    }
    

    In your Application/Service class you could approach like this:

    import java.io.InputStream;
    import java.io.StringWriter;
    import javax.xml.bind.JAXBException;
    import javax.xml.transform.Result;
    import javax.xml.transform.stream.StreamResult;
    import javax.xml.transform.stream.StreamSource;
    import org.springframework.oxm.jaxb.Jaxb2Marshaller;  
    
    @Component
    public class MyMarshallerWrapper {
       // you would rather:
       @Autowired
       private Jaxb2Marshaller  marshaller;
       // than:
       // JAXBContext jc = JAXBContext.newInstance(User.class);
       // Marshaller marshaller = jc.createMarshaller();
    
       // marshalls one object (of your bound classes) into a String.
       public <T> String marshallXml(final T obj) throws JAXBException {
          StringWriter sw = new StringWriter();
          Result result = new StreamResult(sw);
          marshaller.marshal(obj, result);
          return sw.toString();
       }
    
       // (tries to) unmarshall(s) an InputStream to the desired object.
       @SuppressWarnings("unchecked")
       public <T> T unmarshallXml(final InputStream xml) throws JAXBException {
          return (T) marshaller.unmarshal(new StreamSource(xml));
       }
    }
    

    See Jaxb2Marshaller-javadoc, and a related Answer