11

I'm using the JAXB_FRAGMENT property for my marshaller to marshal at the WorkSet level. The problem is that when I marshal it's giving the WorkSet element the xmlns attribute everytime. Is there a way to marshal so that it doesn't attach the xmlns attribute? Here's what my XML looks like.

    <Import>
        <WorkSets>
            <WorkSet xmlns="http://www.namespace.com">
                <Work>
                <Work>
                ...
                ..
                ...
            </WorkSet>
            <WorkSet xmlns="http://www.namespace.com">
                <Work>
                <Work>
                ...
            </WorkSet>
        </WorkSets>
    </Import>

Here's the code I'm using the create the above:

FileOutputStream fos = new FileOutputStream("import.xml");
XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(fos);

JAXBContext jc = JAXBContext.newInstance(WorkSet.class);
Marshaller m = jc.createMarshaler();
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

writer.writeStartDocument();
writer.writeStartElement("Import");
writer.writeAttribute("xmlns","http://www.namespace.com");
writer.writeStartElement("WorkSets");

while(hasWorkSet){
m.marshal(workSet, writer)
}
writer.writeEndDocument();
writer.close();
TyC
  • 792
  • 6
  • 11
  • 23
  • You want to have the namespace declaration higher up in the document, or you don't want a namespace declared at all? – bdoughan Feb 15 '12 at 19:02
  • @BlaiseDoughan I'm writing the Import and WorkSets tags manually through an XMLStreamWriter so I set their attributes manually as well. I'm using JAXB to to marshal a collection of WorkSet instances, which is working fine, I just don't want the xmlns attribute attached to each. It didn't put the xmlns attributes on WorkSet when I used JAXB to marshal the entire XML instance together (Import,Worksets,WorkSet,Work..). It only started when I switched JAXB_FRAGMENT on to marshal only WorkSet. – TyC Feb 15 '12 at 19:29
  • @BlaiseDoughan I've been looking through the JAXB API and still can't see what's causing the namespace to be put on the WorkSet element. – TyC Feb 16 '12 at 14:04
  • 1
    It puts the namespace in if it isn't aware of the NS being declared earlier. If you marshal to a stream with fragment enabled, it will always put namespaces where needed. – Daniel Moses Feb 16 '12 at 16:18
  • 1
    I have added an answer: http://stackoverflow.com/a/9314867/383861 – bdoughan Feb 16 '12 at 16:21
  • Alternative, a bit hacky solutions is [here](http://stackoverflow.com/a/5597035/267197). – dma_k Feb 16 '12 at 21:51

3 Answers3

9

Assuming you want the default namespace for your document to be http://www.namespace.com, you could do the following:

Demo

The XMLStreamWriter.setDefaultNamespace(String) and XMLStreamWriter.writeNamespace(String, String) methods will be used to set and write the default namespace for the XML document.

package forum9297872;

import javax.xml.bind.*;
import javax.xml.stream.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(System.out);
        writer.setDefaultNamespace("http://www.namespace.com");

        JAXBContext jc = JAXBContext.newInstance(WorkSet.class);
        Marshaller m = jc.createMarshaller();
        m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

        writer.writeStartDocument();
        writer.writeStartElement("http://www.namespace.com", "Import");
        writer.writeNamespace("", "http://www.namespace.com");
        writer.writeStartElement("WorkSets");

        m.marshal(new WorkSet(), writer);
        m.marshal(new WorkSet(), writer);

        writer.writeEndDocument();
        writer.close();
    }

}

WorkSet

My assumption is that you have specified namespace information in your JAXB model.

package forum9297872;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="WorkSet", namespace="http://www.namespace.com")
public class WorkSet {

}

Output

Below is the output from running the demo code:

<?xml version="1.0" ?><Import xmlns="http://www.namespace.com"><WorkSets><WorkSet></WorkSet><WorkSet></WorkSet></WorkSets></Import>
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • This worked, yet I have no idea why. There was no name specified in the WorkSet class. Here's the XmlRootElement tag attached to the class. @XmlRootElement(name = "WorkSet"). – TyC Feb 16 '12 at 20:31
  • Is there a `package-info` class in the same package as the `WorkSet` class? – bdoughan Feb 16 '12 at 20:42
  • Yes. It contains the following: @javax.xml.bind.annotation.XmlSchema(namespace = "http://www.itron.com/nVanta", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) – TyC Feb 16 '12 at 21:00
  • Also, is there a way to get formatted output? I'm already using the formatted output property on the marshaller, but I don't think it's working because I'm using the fragmeted property as well. Or perhaps because I'm using a FileOutputStream. – TyC Feb 16 '12 at 21:03
  • The `package-info` class is where the namespace is coming from: http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html. You just need to set `marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);` to get formatted output: http://blog.bdoughan.com/2011/08/jaxb-and-java-io-files-streams-readers.html – bdoughan Feb 16 '12 at 21:06
  • I have the Marshaller.JAXB_FORMATTED_OUTPUT property set. The WorkSet element is still not coming out formatted. – TyC Feb 16 '12 at 21:26
  • Sorry, it is because your `FileOutputStream` is wrapped in an `XmlStreamWriter` that is why your output is not being formatted. – bdoughan Feb 16 '12 at 21:28
  • 1
    @TyC: See [indentation for XMLStreamWriter](http://stackoverflow.com/a/6723007/267197). – dma_k Feb 16 '12 at 21:50
  • Add a `public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException { if (!"nil".equals(localName)) {` to also strip the `nil` attribute. – Stephane Feb 12 '16 at 15:29
1

There are three workarounds for this.

1) Create JAXB annotated objects for the container of your workersets. Add the workersets to that object and then marshal the whole thing.

2) Follow the first example in 101 ways to marshal objects with JAXB and use DocumentBuilderFactory with namespace aware.

3) Assuming that the jaxb object is in a package that should never have qualified namespaces you can add the following to the package annotation: (note: it's been a while since i've done this and I havn't tested this code)

@XmlSchema(namespace = "", elementFormDefault = XmlNsForm.UNQUALIFIED) 
package example;
reevesy
  • 3,452
  • 1
  • 26
  • 23
Daniel Moses
  • 5,872
  • 26
  • 39
  • Could you please help me on https://stackoverflow.com/questions/68031311/java-lang-illegalstateexception-marshaller-must-support-the-class-of-the-marsha – truekiller Jun 21 '21 at 09:26
0

Just another example:

    try {
        JAXBContext customerInformationRequestContext = JAXBContext.newInstance(CustomerInformationRequest.class);
        Unmarshaller unmarshaller = customerInformationRequestContext.createUnmarshaller();
        StringReader stringReader = new StringReader(requestPayload);
        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(stringReader);
        XMLStreamReaderWrapper reader = new XMLStreamReaderWrapper(xsr);
        CustomerInformationRequest customerInformationRequest = (CustomerInformationRequest) unmarshaller.unmarshal(reader);
        CustomerInformationResponse customerInformationResponse = customerLookup(customerInformationRequest, sessionTransaction);
        JAXBContext customerInformationResponseContext = JAXBContext.newInstance(CustomerInformationResponse.class);
        Marshaller marshaller = customerInformationResponseContext.createMarshaller();
        StringWriter stringWriter = new StringWriter();
        XMLOutputFactory xof = XMLOutputFactory.newFactory();
        XMLStreamWriter xsw = xof.createXMLStreamWriter(stringWriter);
        xsw = new XMLStreamWriterWrapper(xsw);
        marshaller.marshal(customerInformationResponse, xsw);
        String responsePayload = stringWriter.toString();
        return responsePayload;
    } catch (Exception e) {
        log.debug("The payload could not be unmarshalled.", e);
        return null;
    }
Stephane
  • 11,836
  • 25
  • 112
  • 175
  • Could you please help me on https://stackoverflow.com/questions/68031311/java-lang-illegalstateexception-marshaller-must-support-the-class-of-the-marsha – truekiller Jun 21 '21 at 09:27
  • Sorry I have not touched that framework in a long time now and could not help you with my limited understanding as of today. – Stephane Jun 21 '21 at 18:20