apache / apache/maven-doxia

Remove the javax.swing dependency from doxia-sink-api and doxia-core

Open
#1,092 1 comment 0 reactions 0 assignees View on GitHub
breaking enhancement
Dominant language
Java
Stars
34
Forks
54
Avg merge
1d 12h
Merged PRs (30d)
16

Description

### New feature, improvement proposal

`doxia-sink-api` and `doxia-core` pull in `java.desktop` for four types from
`javax.swing.text`. None of them is used for anything Swing does. All four serve as
constant tables or as a `String`-to-`Object` map.

| Type | Main sources | What Doxia uses it for |
| --- | --- | --- |
| `javax.swing.text.html.HTML.Attribute` | 6 | A table of attribute-name strings |
| `javax.swing.text.html.HTML.Tag` | 6 | A table of tag-name strings, plus `isBlock()` |
| `javax.swing.text.MutableAttributeSet` | 8 | The supertype of `SinkEventAttributes` |
| `javax.swing.text.AttributeSet` | 4 | Parameter and return types around the above |

#### `HTML.Attribute` is a string table

38 references in main sources; 33 are `Attribute.X.toString()`. The other five pass the
constant itself as the key: `XdocSink:389` and `Xhtml5Sink:169,174,190,191`. Those are
harmless only because `SinkEventAttributeSet.addAttribute` calls `name.toString()` on the
key, while `getAttribute`, `isDefined` and `removeAttribute` do not — so a set written
with one of those keys can only be read back with a `String`. `SinkEventAttributes`
already declares `CLASS`, `ID`, `HREF`, `SRC`, `STYLE`, `NAME`, `BORDER`, `LANG`, `VALUE`
and `REL` as `String` constants; of the names in use only `CONTENT` is missing.

#### `HTML.Tag` is a name holder whose one behaviour is already wrong here

`HtmlMarkup` declares 117 tags. 56 of them are already anonymous subclasses that override
nothing but `toString()`, because HTML5 has tags Swing's HTML 4 table never had. The only
inherited behaviour any Doxia code reads is `isBlock()`, at `AbstractXmlSink:113`, which
decides whether to write a newline before a start tag.

That answer is arbitrary for this codebase today. Every one of the 56 hand-rolled tags
inherits `isBlock() == false`, so `section`, `article`, `figure`, `main`, `nav`, `aside`,
`header`, `footer`, `thead` and `tbody` are all treated as inline. From the other
direction Swing reports `address`, `caption`, `form`, `hr` and `html` as non-block, and
`menu` and `title` as block.

#### `AttributeSet` carries machinery nothing uses

`SinkEventAttributes extends MutableAttributeSet`, and the implementation is a
`LinkedHashMap` plus a `resolveParent`. No production code in Doxia calls
`setResolveParent`; only `SinkEventAttributeSetTest` does. #1075 is a consequence of that
otherwise unused machinery. `entrySet()`, added in 2.1.0, is already a Doxia-owned
replacement for the `Enumeration getAttributeNames()` iteration.

### Why bother

Worth being plain about the size of the win. On a full JDK this costs nothing at runtime,
and Doxia never touches `HTMLEditorKit`, so no AWT is initialised. What it buys is a
smaller jlink image and jdeps graph, one less obstacle for GraalVM native-image, a future
`module-info` that need not `requires java.desktop`, and an attribute API with `String`
keys instead of `Object` ones.

The blast radius outside Doxia is small. Across a checkout of the Maven repositories only
three main sources name a Swing type at all: `DependenciesRenderer` in
maven-project-info-reports-plugin and `CpdReportRenderer` in maven-pmd-plugin, both only
`Attribute.X.toString()`, and `GeneratorUtils` in maven-plugin-tools-generators, which
uses `HTMLEditorKit` for its own HTML parsing and has nothing to do with the Sink API.

### Plan

**1. Drop `HTML.Attribute`. No API change, can go into 2.x.** Done in #1095.

Replace every `Attribute.X.toString()` with the `SinkEventAttributes` constant, adding
`CONTENT`. Fix the five call sites that pass an `Attribute` as a key. This removes one of
the four types on its own.

**2. Stop iterating attribute sets through Swing, as far as the types allow. No API change, 2.x.**
Done in #1095.

Only code that already holds a `SinkEventAttributes` can move to the `entrySet()` added in 2.1.0:
`Xhtml5BaseSink.escapeAttributeValues` and `SinkEventAttributeSet.toString()`.

This step originally also listed `SinkUtils.getAttributeString`, `asCssString` and
`filterAttributes`. That was wrong. All three take `javax.swing.text.AttributeSet`, which has no
`entrySet()`, and widening those parameters to `SinkEventAttributes` is a binary break. The same
applies to `Xhtml5BaseSink.writeStartTag(Tag, MutableAttributeSet, boolean)` and to the
`SinkEventAttributeSet` methods that implement the Swing interface. All of them wait for step 4.

**3. Introduce a Doxia tag type, additively, in 2.x.**

Add `org.apache.maven.doxia.markup.HtmlTag` carrying a name and an explicit `isBlock`,
with parallel `writeStartTag(HtmlTag, ...)` overloads on `AbstractXmlSink` and the
`Tag`-typed ones deprecated. Copy the current `isBlock` values verbatim so no generated
site's whitespace moves; correcting the block table is a separate, deliberate change with
its own before-and-after site diff.

**4. Cut the Swing supertype, next major.**

`SinkEventAttributes` declares its own `String`-keyed methods and stops extending
`MutableAttributeSet`; the `HtmlMarkup` constants retype to `HtmlTag`; the public
`AttributeSet` parameters on `SinkUtils` retype to `SinkEventAttributes`; the deprecated
overloads go. A one-method adapter can hand a `javax.swing.text.AttributeSet` view to
anyone who genuinely wanted one.

### Compatibility

Steps 1 and 2 are internal. Step 3 is additive.

Step 4 is why this is a major-version item, on two counts. Retyping the `HtmlMarkup`
constants changes their field descriptors, which no amount of deprecation can stage. And
dropping a superinterface is a japicmp break by definition, although a mild one in
practice: if `SinkEventAttributes` re-declares the same method names, an existing
`invokeinterface SinkEventAttributes.getAttribute` still resolves, and the only code that
actually breaks is code that hands a `SinkEventAttributes` to a parameter typed
`AttributeSet`. The survey above found no such call site in the Maven repositories.

### Related

#1072 / #1073 moved `SinkEventAttributeSet` into `doxia-sink-api`, which puts the
interface and its only implementation in the same module — where steps 2 and 4 have to
happen. #1074 retypes the protected parser hooks to `SinkEventAttributes`, which is the
same major-version window as step 4. #1075 is the `resolveParent` symptom.

*This issue was created with AI assistance.*

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the plan and inspect HtmlMarkup, AbstractXmlSink, SinkEventAttributes, SinkEventAttributeSet, and SinkUtils, along with the current tests and the completed work described for #1095. Trace the remaining javax.swing.text types and compatibility-sensitive signatures; done means the planned HtmlTag and attribute API changes are implemented with the required overload and API checks, without unintended generated-site whitespace changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend-api-design, developer-experience
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.