Tuesday, January 20, 2015

JAXP 1.6: Use of the Service Provider Loader Facility Is Required

In this article, we will first cover the pluggability layer supported in JAXP 1.5 (bundled with Java SE 7).[1] Then discuss new requirements in JAXP 1.6 (bundled with Java SE 8) for service providers.[2] Finally, we will touch upon Jigsaw project to understand JCP's decision to undertake such changes in JAXP 1.6, which aims to smooth the eventual transition to modules in Java 9.

Pluggability Layer


Designed to be flexible, JAXP allows you to use any XML-compliant processors from within your application. It does this with the factory APIs provided in jaxp-api.jar. High-level factory APIs will remain stable and are not subject to change. This jar contains:
  • javax.xml.datatype
  • javax.xml.namespace
  • javax.xml.parsers
  • javax.xml.stream
  • javax.xml.transform
  • javax.xml.validation
  • javax.xml.xpath
packages.

These packages contain the factory APIs that give applications a consistent way to obtain instances of XML processing implementations. Each factory class is an abstract class that has a static newInstance() method that enables you to obtain a concrete instance of the abstract factory class. This static method uses an ordered lookup procedure to determine which concrete implementation of the abstract factory class to load.

This procedure applies to all factory classes. For example, xmlparserv2.jar in Oracle XDK for Java has the following factory types supported:[4]
  • SAXParserFactory
  • DocumentBuilderFactory
  • TransformerFactory
Using SAXParserFactory as an example, the service provider mechanism works in JAXP 1.5 as follows:[7]
  1. Use system property
    • E.g. -Djavax.xml.parsers.SAXParserFactory=.
  2. Use the properties file "lib/jaxp.properties" in the JRE directory
    • This configuration file is in standard java.util.Properties format and contains the fully qualified name of the implementation class with the key being the system property defined above.
    • The jaxp.properties file is read only once by the JAXP implementation and it's values are then cached for future use. If the file does not exist when the first attempt is made to read from it, no further attempts are made to check for its existence. It is not possible to change the value of any property in jaxp.properties after it has been read for the first time.
  3. Use the Services API (as detailed in the JAR specification)
    • The Services API will look for a classname in the file META-INF/services/javax.xml.parsers.SAXParserFactory in jars available to the runtime.
  4. Use Platform default SAXParserFactory instance.
Once an application has obtained a reference to a SAXParserFactory it can use the factory to configure and obtain parser instances.

Transition to Modularization


As described in [3], the project Jigsaw[9] was postponed to Java 9. This project is to design and implement a standard module system for the Java SE Platform and to apply that system to the Platform itself, and to the JDK.

To smooth the transition to Java 9, JAXP 1.6 bundled in Java SE 8 has adopted JEP 162[5] recommended changes—one of which requires the use of the service provider loader facility defined by java.util.ServiceLoader[6] to load services from service configuration files.
  • The rationale for this is to allow for future modularization of the Java SE platform where service providers may be deployed by means other than JAR files and perhaps without the service configuration files.
  • Note that the JAXP has always specified the use of the 'Services API' without reference to a specific API or service provider loading facility.
There are several APIs in the JDK that have their own service provider mechanism rather than using java.util.ServiceLoader. The various FactoryFinders in pre-1.6 JAXP's are examples. These provider loading mechanisms are problematic for modules because they are non-standard. Therefore, JEP 162[5] has proposed to change these APIs to use java.util.ServiceLoader. So, the description of step 3 in the previous-stated "service provider mechanism" should be changed in JAXP 1.6 to:
3, Use the service-provider loading facilities

No comments: