Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB location in file for unmarshalled objects

Tags:

java

jaxb

I have some objects being unmarshalled from an XML file by JAXB. Is it possible to have JAXB tell me or somehow find out where in the XML file (line and column) each object comes from?

This information is available at some point, because JAXB gives it to me during schema validation errors. But I would like to have it available for validated objects too.

like image 293
lexicalscope Avatar asked Aug 16 '11 14:08

lexicalscope


2 Answers

You could do this in JAXB by leveraging an XMLStreamReader and an Unmarshaller.Listener:

Demo

package forum383861;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Unmarshaller.Listener;
import javax.xml.stream.Location;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);


        XMLInputFactory xif = XMLInputFactory.newFactory();
        FileInputStream xml = new FileInputStream("src/forum383861/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        LocationListener ll = new LocationListener(xsr);
        unmarshaller.setListener(ll);

        Customer customer = (Customer) unmarshaller.unmarshal(xsr);
        System.out.println(ll.getLocation(customer));
        System.out.println(ll.getLocation(customer.getAddress()));
    }

    private static class LocationListener extends Listener {

        private XMLStreamReader xsr;
        private Map<Object, Location> locations;

        public LocationListener(XMLStreamReader xsr) {
            this.xsr = xsr;
            this.locations = new HashMap<Object, Location>();
        }

        @Override
        public void beforeUnmarshal(Object target, Object parent) {
            locations.put(target, xsr.getLocation());
        }

        public Location getLocation(Object o) {
            return locations.get(o);
        }

    }

}

input.xml

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <address/>
</customer>

Output

[row,col {unknown-source}]: [2,1]
[row,col {unknown-source}]: [3,5]

Customer

package forum383861;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}

Address

package forum383861;

public class Address {

}

For More Information

  • http://blog.bdoughan.com/2011/08/using-unmarshallerlistener-to-capture.html
like image 161
bdoughan Avatar answered Sep 28 '22 18:09

bdoughan


I'm afraid not. JAXB builds on top of a XML parser, this one will have built up a logical representation of your XML document forgetting the original string representation of your document.

The validation step is done while your string is still read in, so your parser is able to give you an error message telling you the position of the error. JAXB will only bypass that error message. But as soon as the XML is validated and parsed, only the logical representation will exist.

like image 36
craesh Avatar answered Sep 28 '22 19:09

craesh