XML Processing

When working with XML libraries like JAXP and JAXB, we can easily run into classloading issues. These libraries were not designed to run smoothly in an OSGi environment. Problems occur when a library is trying to load classes from the bootstrap or context classloaders, or when two different versions of a class is provided runtime. For details, see OSGi troubleshooting.

Injecting the built-in XML factories

To simplify development of components that need to process XML, the JDisc container provides the most commonly used XML factories as built-in components. These factories can be directly injected to your components, by adding them as constructor arguments. The container will provide a new factory instance for each component, so developers do not have to worry about sharing factories between different components.

Below is an example of injecting the DocumentBuilderFactory for working with DOM structures.

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class MyComponent {

    public final DocumentBuilderFactory factory;

    @Inject
    public MyComponent(DocumentBuilderFactory factory) {
        this.factory = factory;
    }

    public void parse(...) {
        DocumentBuilder builder = factory.newDocumentBuilder();
        ...

Below is a list of all available built-in factories, and the corresponding implementation class that will be provided by the JDisc Container:

Constructor argument type Implementation class that will be injected
javax.xml.datatype.DatatypeFactory com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl
javax.xml.parsers.DocumentBuilderFactory com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
javax.xml.stream.XMLEventFactory com.sun.xml.internal.stream.events.XMLEventFactoryImpl
javax.xml.stream.XMLInputFactory com.sun.xml.internal.stream.XMLInputFactoryImpl
javax.xml.stream.XMLOutputFactory com.sun.xml.internal.stream.XMLOutputFactoryImpl
javax.xml.transform.TransformerFactory com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
javax.xml.validation.SchemaFactory com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory
javax.xml.xpath.XPathFactory com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl

Note that all factories provided by the JDisc Container are the default implementations, provided in the Java SDK. If you need other implementations, you must include the relevant libraries to your bundle, and deal with the issues as they come.

JAXB

The observant eye will have noticed that the table above does not mention JAXBContext. JAXB needs knowledge to the context path, which is a list of java package names of the generated classes derived from the user defined xml schemas. Instead of injecting a JAXBContext directly, we have created a JAXBContextFactory that can be injected. This factory has a newInstance method that takes a varargs list of class objects. Call this method with one class from each package in the context path to get a valid JAXBContext object. Here is an example with two generated packages:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import com.yahoo.container.xml.bind.JAXBContextFactory;
import com.yahoo.test.jaxb.MyGeneratedType;
import com.yahoo.test.jaxb2.OtherGeneratedType;

public class JaxbComponent {
    public final JAXBContext jaxbContext;

    @Inject
    public JaxbComponent(JAXBContextFactory factory) {
        jaxbContext = factory.newInstance(MyGeneratedType.class, OtherGeneratedType.class);
    }

    public void unmarshal(...) {
        Unmarshaller u = jaxbContext.createUnmarshaller();
        ...