This article discusses extending final implementation classes through the
use of Proxy InvocationHandlers and
Default Interface Methods introduced in Java 8.  The specific use case
described here is to add fluent methods to Document Object Model (DOM) to
enable Javadoc implementations to provide snippets of well-formed
HTML/XML.
The various fluent add() methods implemented in FluentNode
(the “facade”):
    default FluentNode add(Stream<Node> stream) {
        return add(stream.toArray(Node[]::new));
    }
    default FluentNode add(Iterable<Node> iterable) {
        return add(toArray(iterable));
    }
    default FluentNode add(Node... nodes) {
        for (Node node : nodes) {
            switch (node.getNodeType()) {
            case ATTRIBUTE_NODE:
                getAttributes().setNamedItem(node);
                break;
            default:
                appendChild(node);
                break;
            }
        }
        return this;
    }
which allows the creation of fluent methods to create Elements:
    default FluentNode element(String name, Stream<Node> stream) {
        return element(name, stream.toArray(Node[]::new));
    }
    default FluentNode element(String name, Iterable<Node> iterable) {
        return element(name, toArray(iterable));
    }
    default FluentNode element(String name, Node... nodes) {
        return ((FluentNode) owner().createElement(name)).add(nodes);
    }
that can be built up in to templates (e.g.,
HTMLTemplates):
    default FluentNode pre(String content) {
        return element("pre").content(content);
    }
Allowing the creation of methods to be trivially invoked to return XML snippets:
        return a(href, text)
                   .add(map.entrySet()
                        .stream()
                        .map(t -> attr(t.getKey(), t.getValue())));
to produce something like
<a href="https://www.rfc-editor.org/rfc/rfc2045.txt" target="newtab">RFC2045</a>
Complete javadoc is provided.
Theory of Operation
An application can add a facade to a class hierarchy by extending
FacadeProxyInvocationHandler1
and implementing
getProxyClassFor(Object)
where the
invoke(Object,Method,Object[])
“enhances” any eligible return types.  Conceptually:
    public Object enhance(Object in) {
        Object out = null;
        Class<?> type = getProxyClassFor(in);
        if (type != null) {
            try {
                out =
                    type.getConstructor(InvocationHandler.class)
                    .newInstance(this);
            } catch (RuntimeException exception) {
                throw exception;
            } catch (Exception exception) {
                throw new IllegalStateException(exception);
            }
        }
        return (out != null) ? out : in;
    }
    protected abstract Class<?> getProxyClassFor(Object object);
    @Override
    public Object invoke(Object proxy, Method method, Object[] argv) throws Throwable {
        Object result = super.invoke(proxy, method, argv);
        return enhance(result);
    }
There are additional details that are discussed in the next section.  The
implementor must return a interface Class to Proxy
from getProxyClassFor(Object) for any Class to be enhanced.
Implementation
Node will be enhanced by FluentNode and
Document will be enhanced by
FluentDocument.  Note: A Node does not necessarily
have to implement the sub-interface that corresponds to
Node.getNodeType() so both the Object’s
class hierarchy and node type are analyzed and the results are cached in the
getProxyClassFor(Object) implementation.
        private final HashMap<List<Class<?>>,Class<?>> map = new HashMap<>();
        ...
        @Override
        protected Class<?> getProxyClassFor(Object object) {
            Class<?> type = null;
            if (object instanceof Node && (! (object instanceof FluentNode))) {
                Node node = (Node) object;
                List<Class<?>> key =
                    Arrays.asList(NODE_TYPE_MAP.getOrDefault(node.getNodeType(), Node.class),
                                  node.getClass());
                type = map.computeIfAbsent(key, k -> compute(k));
            }
            return type;
        }
        private Class<?> compute(List<Class<?>> key) {
            LinkedHashSet<Class<?>> implemented =
                key.stream()
                .flatMap(t -> getImplementedInterfacesOf(t).stream())
                .filter(t -> Node.class.isAssignableFrom(t))
                .filter(t -> Node.class.getPackage().equals(t.getPackage()))
                .collect(Collectors.toCollection(LinkedHashSet::new));
            LinkedHashSet<Class<?>> interfaces =
                implemented.stream()
                .map(t -> fluent(t))
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
            interfaces.addAll(implemented);
            new ArrayList<>(interfaces)
                .stream()
                .forEach(t -> interfaces.removeAll(Arrays.asList(t.getInterfaces())));
            return getProxyClass(interfaces.toArray(new Class<?>[] { }));
        }
The corresponding “fluent” interface is found through reflection:
        private Class<?> fluent(Class<?> type) {
            Class<?> fluent = null;
            if (Node.class.isAssignableFrom(type) && Node.class.getPackage().equals(type.getPackage())) {
                try {
                    String name =
                        String.format("%s.Fluent%s",
                                      FluentNode.class.getPackage().getName(),
                                      type.getSimpleName());
                    fluent = Class.forName(name).asSubclass(FluentNode.class);
                } catch (Exception exception) {
                }
            }
            return fluent;
        }
The DocumentBuilderFactory,
FluentDocumentBuilderFactory, and
DocumentBuilder,
FluentDocument.Builder, implementations are both
straightforward.  The two DocumentBuilder
methods
that create new Documents are implemented by creating a new
FluentNode.InvocationHandler:
        @Override
        public FluentDocument newDocument() {
            Document document = builder.newDocument();
            return (FluentDocument) new FluentNode.InvocationHandler().enhance(document);
        }
        @Override
        public Document parse(InputSource in) throws SAXException, IOException {
            Document document = builder.parse(in);
            return (FluentDocument) new FluentNode.InvocationHandler().enhance(document);
        }
Creating a new FluentDocument is as simple as:
            document =
                FluentDocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .newDocument();
Unfortunately, the implementation as described so far will fail with an error similar to:
...
[ERROR] Caused by: org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
[ERROR] 	at com.sun.org.apache.xerces.internal.dom.AttributeMap.setNamedItem(AttributeMap.java:86)
[ERROR] 	at ball.xml.FluentNode.add(FluentNode.java:180)
...
[ERROR] 	... 35 more
...
The com.sun.org.apache.xerces.internal.dom implementation classes expect
to have package access to other package classes.  This requires adjusting
the
invoke(Object,Method,Object[])
implementation to choose the wider of the Proxy facade or the
reverse depending on the required context:
    @Override
    public Object invoke(Object proxy, Method method, Object[] argv) throws Throwable {
        Object result = null;
        Class<?> declarer = method.getDeclaringClass();
        Object that = map.reverse.get(proxy);
        if (declarer.isAssignableFrom(Object.class)) {
            result = method.invoke(that, argv);
        } else {
            argv = reverseFor(method.getParameterTypes(), argv);
            if (declarer.isAssignableFrom(that.getClass())) {
                result = method.invoke(that, argv);
            } else {
                result = super.invoke(proxy, method, argv);
            }
        }
        return enhance(result);
    }
This requires keeping an IdentityHashMap of enhanced
Object to Proxy and reverse:
    private final ProxyMap map = new ProxyMap();
    public Object enhance(Object in) {
        Object out = null;
        if (! hasFacade(in)) {
            Class<?> type = getProxyClassFor(in);
            if (type != null) {
                out = map.computeIfAbsent(in, k -> compute(type));
            }
        }
        return (out != null) ? out : in;
    }
    private <T> T compute(Class<T> type) {
        T proxy = null;
        try {
            proxy =
                type.getConstructor(InvocationHandler.class)
                .newInstance(this);
        } catch (RuntimeException exception) {
            throw exception;
        } catch (Exception exception) {
            throw new IllegalStateException(exception);
        }
        return proxy;
    }
    private class ProxyMap extends IdentityHashMap<Object,Object> {
        private final IdentityHashMap<Object,Object> reverse = new IdentityHashMap<>();
        public IdentityHashMap<Object,Object> reverse() { return reverse; }
        @Override
        public Object put(Object key, Object value) {
            reverse().put(value, key);
            return super.put(key, value);
        }
    }
and providing the necessary “reverse” methods contained in the source.
Integration
AbstractTaglet demonstrates the integration.  The class
must implement XMLServices and provide an implementation of
document().
    private final FluentDocument document;
    ...
    protected AbstractTaglet(boolean isInlineTag, boolean inPackage,
                             boolean inOverview, boolean inField,
                             boolean inConstructor, boolean inMethod,
                             boolean inType) {
        ...
        try {
            ...
            document =
                FluentDocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .newDocument();
            document
                .add(element("html",
                             element("head",
                                     element("meta",
                                             attr("charset", "utf-8"))),
                             element("body")));
        } catch (Exception exception) {
            throw new ExceptionInInitializerError(exception);
        }
    }
    ...
    @Override
    public FluentDocument document() { return document; }
AbstractTaglet also implements
HTMLTemplates which provides default methods for HTML
elements/nodes.  HTMLTemplates is further extended by
JavadocHTMLTemplates to provide common HTML/XML
fragments required to generate Javadoc.
Summary
The FacadeProxyInvocationHandler combined
with specialized interfaces implementing default methods provides a
mechanism for extending an otherwise final class hierarchy.
[1]
FacadeProxyInvocationHandler is a subclass
of DefaultInvocationHandler whose
invoke(Object,Method,Object[])
implementation is discussed in
“Adding Support to Java InvocationHandler Implementations for Interface
Default Methods”).
↩