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 bundle 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();
...