Card 05/ 08

ExampleDifficulty: Intermediate2 min

Abstract Factory in the Wild: Java's DocumentBuilderFactory

The XML parser you get depends on the factory the platform supplies, not on your code.

The JDK's XML parsing API, in javax.xml.parsers, is built on Abstract Factory. Your code asks the abstract class DocumentBuilderFactory for a factory, the factory creates a parser, and the parser creates documents, and at no point does your code name an implementation class. This card shows which classes actually come back, and where the JDK bends the textbook form.

java
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class AfXmlFactory {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(new ByteArrayInputStream(
            "<order id=\"A-1042\"/>".getBytes(StandardCharsets.UTF_8)));

        System.out.println("factory:  " + factory.getClass().getName());
        System.out.println("builder:  " + builder.getClass().getName());
        System.out.println("document: " + document.getClass().getName());
        System.out.println("order id: " + document.getDocumentElement().getAttribute("id"));
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
factory:  com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
builder:  com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl
document: com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl
order id: A-1042
The code names only abstract types; the printout shows the classes behind them.

Every class printed belongs to one family, the copy of Apache Xerces built into the JDK, under com.sun.org.apache.xerces.internal. The code above was written against DocumentBuilderFactory, DocumentBuilder and the Document interface only. If a different XML library were installed, the same code would receive that library's factory, parser and document, a matching set from another family.

The XML API in the pattern's roles
ParticipantIn javax.xml.parsers
AbstractFactoryDocumentBuilderFactory
ConcreteFactoryDocumentBuilderFactoryImpl, Xerces's implementation
AbstractProductDocumentBuilder, and the Document it produces
ConcreteProductDocumentBuilderImpl and DeferredDocumentImpl
ClientYour code

The JDK bends the textbook form in two ways. First, DocumentBuilderFactory creates only one kind of product directly, the builder, and the builder creates the document, so the family is a chain rather than a row of sibling methods. Second, the client does not receive a factory as a parameter. newInstance() finds one: it checks the javax.xml.parsers.DocumentBuilderFactory system property, then any library on the classpath that declares an implementation, and only then falls back to the built-in Xerces. A factory that finds a factory is common in platform APIs.

What this case shares with the cloud example is the shape: the client holds a factory through an abstract type, asks it for products, and gets a consistent family without naming a class. The class names here are those of OpenJDK 21 and are internal, which is exactly why your code is not allowed to depend on them.