Search code examples
jaxblocationmoxy

JAXB/MOXy: @XmlLocation Locator doesn't work


I have a JAXB class with

@XmlTransient
@XmlLocation Locator location;
public Locator getLocation() { return location; }

But after unmarshalling (from XML), the value is null. Using MOXy 2.5.0, JDK 1.7.21.

What can be wrong?


Solution

  • EclipseLink JAXB (MOXy)'s @XmlLocation does work, but if you are unmarshalling from a DOM Node then it will not capture any location information. I will demonstrate below with an example.

    JAVA MODEL

    Below is the Java model that we will use for this example.

    Foo

    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Foo {
    
        Bar bar;
    
    }
    

    Bar

    We will use the @XmlLocation annotation on the Bar class to store the location. MOXy supports the @XmlLocation annotation from the JAXB reference implementation (including the one repackaged in the internal package) as well as its own version.

    // import com.sun.xml.bind.annotation.XmlLocation;
    // import com.sun.xml.internal.bind.annotation.XmlLocation;
    import javax.xml.bind.annotation.*;
    import org.eclipse.persistence.oxm.annotations.XmlLocation;
    import org.xml.sax.Locator;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Bar {
    
        @XmlTransient
        @XmlLocation
        Locator location;
    
    }
    

    XML INPUT (input.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <foo>
        <bar/>
    </foo>
    

    DEMO CODE

    Below is some demo code that will unmarshal different types of input and then outputs the location.

    import java.io.File;
    import javax.xml.bind.*;
    import javax.xml.parsers.*;
    import javax.xml.stream.*;
    import javax.xml.transform.Source;
    import javax.xml.transform.stream.StreamSource;
    import org.w3c.dom.Document;
    import org.xml.sax.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Foo.class);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
    
            File file = new File("src/forum17288002/input.xml");
            Foo foo1 = (Foo) unmarshaller.unmarshal(file);
            outputLocation(file, foo1);
    
            InputSource inputSource = new InputSource("src/forum17288002/input.xml");
            Foo foo2 = (Foo) unmarshaller.unmarshal(inputSource);
            outputLocation(inputSource, foo2);
    
            Source source = new StreamSource("src/forum17288002/input.xml");
            XMLInputFactory xif = XMLInputFactory.newFactory();
    
            XMLStreamReader xmlStreamReader = xif.createXMLStreamReader(source);
            Foo foo3 = (Foo) unmarshaller.unmarshal(xmlStreamReader);
            outputLocation(xmlStreamReader, foo3);;
    
            XMLEventReader xmlEventReader = xif.createXMLEventReader(source);
            Foo foo4 = (Foo) unmarshaller.unmarshal(xmlEventReader);
            outputLocation(xmlEventReader, foo4);
    
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.parse("src/forum17288002/input.xml");
            Foo foo5 = (Foo) unmarshaller.unmarshal(document);
            outputLocation(document, foo5);
        }
    
        private static void outputLocation(Object input, Foo foo) {
            Locator locator = foo.bar.location;
            System.out.print(locator.getLineNumber());
            System.out.print(" ");
            System.out.print(locator.getColumnNumber());
            System.out.print(" ");
            System.out.println(input.getClass());
        }
    
    }
    

    OUTPUT

    Below is the output from running the demo code. The only input that did not result in a location was the DOM input. This makes sense as DOM nodes don't hold onto any location information that MOXy could access.

    3 11 class java.io.File
    3 11 class org.xml.sax.InputSource
    3 11 class com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl
    3 11 class com.sun.xml.internal.stream.XMLEventReaderImpl
    0 0 class com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl