Question

I have Java classes with the following structure (the class names do not imply anything, I was just making them up).

package test;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

@XmlRootElement
public class Test
{
    @XmlAccessorType(XmlAccessType.FIELD)
    static class Machine
    {
        @XmlElementWrapper(name="servers")
        @XmlElement(name="server")
        List<Server> servers = new ArrayList<Server>();
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    static class Server
    {
        Threshold t = new Threshold();
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    static class Threshold
    {
        RateThreshold load = new RateThreshold();
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    static class RateThreshold
    {
        @XmlAccessorType(XmlAccessType.FIELD)
        static class Rate
        {
            int count;
            Period period = new Period();
        }

        @XmlAccessorType(XmlAccessType.FIELD)
        private static class Period
        {
            @XmlAttribute
            private String type = "second";

            @XmlValue
            private float period;
        }

        Rate min = new Rate();
        Rate max = new Rate();
    }

    @XmlElementWrapper(name="machines")
    @XmlElement(name="machine")
    List<Machine> machines = new ArrayList<Machine>();

    public static void main(String[] args)
    {
        Machine m = new Machine();
        Server s = new Server();
        s.t.load.max.count = 10;
        s.t.load.min.count = 1;
        m.servers.add(s);

        Test t = new Test();
        t.machines.add(m);

        JAXBContext jaxbContext;
        Marshaller marshaller;
        try
        {
            jaxbContext = JAXBContext.newInstance(Test.class);
            marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(t, System.out);
        }
        catch (JAXBException e)
        {
            e.printStackTrace();
        }
    }
}

The problem I am having is with the XML output generated by JAXB when marshalling a Test instance. The XML output would always look like the following:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<test>
    <machines>
        <machine>
            <servers>
                <server>
                    <t>
                        <load>
                            <min>
<count>1</count>
<period type="second">0.0</period>
                            </min>
                            <max>
<count>10</count>
<period type="second">0.0</period>
                            </max>
                        </load>
                    </t>
                </server>
            </servers>
        </machine>
    </machines>
</test>

As you can see, some elements are not being indented properly (that is, the deepest elements, count and period). Why is that? Is there something wrong with the way I created the JAXB context? Or is there a maximum limit to how many elements that can be indented recursively by JAXB? How could I fix this? Note that I have also set JAXB_FORMATTED_OUTPUT to true, but still get the improper indentation.

Thanks.

Was it helpful?

Solution

Indenting occurs modulo 8, in

com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput

you find

int i = depth%8;

OTHER TIPS

One of the overloads of the marshal() method of the marshaler accepts an XMLStreamWriter, so you can bypass the brain-damaged formatting mechanism of the Reference Implementation of JAXB by writing your own formatting XML stream writer. You would end up doing something like this:

public static void SaveContainer( Container container, OutputStream stream ) throws ...
{
    XMLOutputFactory factory = XMLOutputFactory.newInstance();
    XMLStreamWriter writer = factory.createXMLStreamWriter( stream, "UTF-8" );
    writer = new MyAwesomeCoolFormattingXMLStreamWriter( writer );
    marshaller.marshal( container, writer );
}

I don't think there's a limit. I've seen very deep nesting, without any difficulties. Do you have any whitespace control in place? Also, you haven't provided the definition of the RateThreshold class, which is the one creating the unexpected output.

You need to set the line width - default is 72.

OutputFormat of = new OutputFormat();

of.setLineWidth(1000);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top