5

I am using JAXB / Moxy to marshal a class into XML. When the root element only contains an attribute the output is as follows:

    <?xml version="1.0" encoding="UTF-8"?>
    <procedure xmlns="http://xml.test.com/api/request" name="TestProcedure"/>

The desired output contains the closing tag for procedure:

   <?xml version="1.0" encoding="UTF-8"?>
   <procedure xmlns="http://xml.test.com/api/request" name="TestProcedure"></procedure>

This is getting sent to a third party system. Even though both are well formed XML, it still needs the closing tag.

I saw this post: JAXB marshals XML differently to OutputStream vs. StringWriter but did not see a difference in output between the outputstream and strings when running locally.

This seems to deal only with elements and attributes, but not the root element: Represent null value as empty element in xml jaxb I still setup a DescriptorCustomizer and looked through the ClassDescriptor in the debugger, but didn't see any properties to set like the XMLDirectMapping.

My domain object looks like

   @XmlRootElement(name = "procedure")
   public class ProcRequest {
    protected String procName;
    protected String requestId;
    protected List<Param> parameter;

    @XmlAttribute
    public String getProcName() {
        return procName;
    }
    public void setProcName(String procName) {
        this.procName = procName;
    }
    @XmlAttribute
    public String getRequestId() {
        return requestId;
    }
    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }
    @XmlElement
    public List<Param> getParam() {
        if (this.param == null) {
            this.param = new ArrayList<Param>();
        } 

        return param;
    }
    public void setParam(List<Param> param) {
        this.param = param;
    }

   }

And my service contains:

   ProcRequest procRequest = new ProcRequest();
   procRequest.setProcName("TestProcedure");

   JAXBContext jaxbContext = JAXBContext.newInstance(ProcRequest.class);

   Marshaller moxyMarshaller = jaxbContext.createMarshaller();
   moxyMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

   moxyMarshaller.marshal(procRequest, System.out);

Are there any properties or attributes which can be set to force a closing tag at the end similar to Marshaller.JAXB_FORMATTED_OUTPUT? Or any other suggestions?

Community
  • 1
  • 1
BenjaminDWest
  • 105
  • 1
  • 6

2 Answers2

3

Since the two forms are semantically equivalent XML:

  1. the standard JAXB marshaler does not provide an option to control this detail; and
  2. any solution is going to have to be outside XML processing.

I believe you are stuck unless you can use a different JAXB or marshaler implementation that allows customization of empty tags. I think at one point Saxon had an option for this but haven't looked in years.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
0

Jim led me in the final direction with point number 2. I ended up processing it manually with an ugly hack on a Woodstox property. You can manually specify which properties can use the self-closing syntax. While debugging I accidentally gave it an empty Set of properties and all of the properties had a separate closing tag.

XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
Set<String> tags = new HashSet<String>();
// This specifies the procedure field should be allowed to use the self-closing syntax instead of having a separate end tag
//tags.add("procedure"); 
outputFactory.setProperty(WstxOutputProperties.P_OUTPUT_EMPTY_ELEMENT_HANDLER, new EmptyElementHandler.SetEmptyElementHandler(tags));  
StringWriter sw = new StringWriter();
XMLStreamWriter writer = outputFactory.createXMLStreamWriter(sw);

writer.writeStartDocument("1.0");
writer.writeStartElement("procedure");
writer.writeAttribute("name", procRequest.getName());
writer.writeAttribute("requestId", procRequest.getRequestId());
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
sw.flush();
BenjaminDWest
  • 105
  • 1
  • 6