JAXP factories like DocumentBuilderFactory are Abstract Factories whose provider is pluggable. How does the runtime select the implementation, and what design forces does that pluggability serve?
answer
- Order: system property → jaxp.properties → ServiceLoader → JDK default
- First match wins; newInstance(name,...) bypasses lookup
- Abstract Factory + service-provider mechanism
- Serves vendor independence / Open-Closed / testability
- Ambient lookup risk → configure secure processing explicitly (XXE)
basics
~20 snewInstance() searches an ordered list — a system property, a jaxp.properties file, the service-loader (META-INF/services), then the built-in default — and uses the first provider it finds. This lets you swap XML libraries without changing code.
solid answer
~50 sDocumentBuilderFactory.newInstance() uses the JAXP ordered provider-lookup to pick the concrete factory: it checks the javax.xml.parsers.DocumentBuilderFactory system property, then a jaxp.properties file in the JDK's conf directory, then the ServiceLoader mechanism (META-INF/services entries on the classpath/modulepath), and finally the JDK's built-in default implementation; the first match wins. This realizes the Abstract Factory's intent — the client depends only on the abstract factory and abstract products — but extends it with runtime substitutability of the entire provider. The design forces it serves: vendor independence (swap Xerces for another parser by config, not code), testability and policy control (you can inject a hardened/secure parser), and decoupling that respects the Open/Closed Principle. It also means a misconfigured property or a stray jar on the classpath can silently change which parser you get, so in security-sensitive contexts you configure the factory explicitly (features, secure processing) rather than trusting the ambient lookup.
go deeper
Knows newInstance() picks an implementation for you and that you don't name the concrete parser class.
Can describe that the JDK selects the provider via a lookup (property/services/default) and that this keeps client code decoupled.
States the full ordered lookup, ties it to Abstract Factory + service-provider, and flags the security (XXE) and thread-safety consequences, configuring secure processing explicitly.
Reasons about deployment-level pluggability vs. supply-chain risk (ambient service entries), module-system provides/uses, hardening policy across services, and when to bypass the lookup with an explicit provider for determinism.
## Abstract Factory + the service-provider mechanism JAXP (Java API for XML Processing) is the canonical place where the **Abstract Factory** pattern meets Java's **service-provider** (pluggability) mechanism. Understanding both halves is what makes this a senior-level topic. ### The lookup order (for DocumentBuilderFactory.newInstance()) When you call `DocumentBuilderFactory.newInstance()`, the runtime resolves the concrete factory by trying sources **in order** and taking the first that yields a class name: 1. **System property** — `javax.xml.parsers.DocumentBuilderFactory`. If set (e.g. via `-D` or `System.setProperty`), its value is the factory class to load. 2. **`jaxp.properties`** — a properties file in the JDK's `conf` directory (historically `lib/jaxp.properties`) containing the same key. Read once if the property wasn't set. 3. **`ServiceLoader` / `META-INF/services`** — the standard service-provider mechanism: a jar can ship `META-INF/services/javax.xml.parsers.DocumentBuilderFactory` naming its implementation. In the module system this corresponds to a `provides ... with ...` directive. The first provider found on the path is used. 4. **Built-in default** — if none of the above match, the JDK's bundled implementation is used. The overloaded `newInstance(String factoryClassName, ClassLoader)` bypasses the lookup and loads the named class directly. ### Why this is still Abstract Factory The pattern's essence is unchanged: the client holds only `DocumentBuilderFactory` (abstract factory) and `DocumentBuilder`/DOM types (abstract products), and never names a concrete class. Pluggability is an *addition*: the concrete factory is chosen at runtime by the lookup instead of being passed in by a caller. So JAXP is Abstract Factory **plus** the service-provider idiom. ### Design forces the pluggability serves - **Vendor/library independence.** You can replace the XML parser implementation (different performance, standards support, or bug profile) by configuration alone, never editing client code. This is the Dependency Inversion / Open-Closed payoff at the deployment level. - **Layered defaults with override points.** Most apps use the JDK default; a deployment can override globally (property/file) or a library can override locally (its own service entry). Override granularity matches the operational need. - **Policy and hardening.** You can substitute a parser configured for secure processing, or one instrumented for a platform. - **Testability.** Tests can force a specific or fake provider. ### The risks a senior should flag - **Ambient configuration is fragile.** A stray jar on the classpath shipping a `META-INF/services` entry can silently change which parser your app uses — a classic 'works on my machine' / dependency-conflict bug. - **Security: XXE.** XML parsers default to features that can be dangerous (external entity resolution → XXE attacks, billion-laughs entity expansion). Because the *which-parser* decision is ambient, you should not rely on it for safety. Instead, **explicitly configure the factory** after obtaining it — e.g. enable `XMLConstants.FEATURE_SECURE_PROCESSING`, disable DOCTYPE/external general+parameter entities — regardless of which provider the lookup returned. The Abstract Factory gives you a configured *factory* object precisely so you can set these features in one place before creating products. - **Thread-safety.** Factory instances and the builders they create are generally **not** thread-safe; create per-use or pool carefully. This is an operational consequence of the pattern's object-per-family design. ### The senior framing Abstract Factory decouples client from concrete product; the JAXP service-provider lookup decouples *deployment* from concrete provider. Together they give pluggability — but pluggability via ambient lookup is a double-edged sword: great for vendor independence, dangerous if you assume the wrong provider/features. The mature stance is: let the lookup choose the implementation, but **explicitly configure security-relevant features on the factory yourself**.
- Why shouldn't you rely on the ambient provider lookup for security?Because which provider you get can be changed by a system property, a jaxp.properties file, or any jar shipping a META-INF/services entry — none of which you fully control at deploy time. XML security (XXE, entity-expansion) must be set explicitly on the factory you obtain (e.g. FEATURE_SECURE_PROCESSING, disabling DOCTYPE/external entities), independent of which implementation was selected.
- Are DocumentBuilderFactory and DocumentBuilder thread-safe?Generally no. A DocumentBuilder is not safe for concurrent use, and factories aren't guaranteed thread-safe either. Create or pool them per thread/per use rather than sharing one builder across threads.
saying these in an interview costs you the question
- Saying the provider is fixed/hardcoded — it's resolved by an ordered runtime lookup.
- Believing the default parser is safe out of the box — XXE/entity-expansion must be disabled explicitly.
- Assuming factories/builders are thread-safe and sharing one across threads.
- Ignoring that a classpath jar can silently override which provider is used.