From ba5dc20ff0620e266ca1180f7612c33e109b05b3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Oct 2025 17:53:46 +0000
Subject: [PATCH 1/3] WIP: Migrating XdocGenerator to use Doxia Sink API -
basic structure in place
Co-authored-by: slachiewicz <6705942+slachiewicz@users.noreply.github.com>
---
modello-plugins/modello-plugin-xdoc/pom.xml | 10 +
.../modello/plugin/xdoc/XdocGenerator.java | 224 +++++++++---------
2 files changed, 122 insertions(+), 112 deletions(-)
diff --git a/modello-plugins/modello-plugin-xdoc/pom.xml b/modello-plugins/modello-plugin-xdoc/pom.xml
index 31cb085c0..8bc64e131 100644
--- a/modello-plugins/modello-plugin-xdoc/pom.xml
+++ b/modello-plugins/modello-plugin-xdoc/pom.xml
@@ -25,6 +25,16 @@
org.codehaus.plexus
plexus-utils
+
+ org.apache.maven.doxia
+ doxia-sink-api
+ 2.0.0
+
+
+ org.apache.maven.doxia
+ doxia-module-xdoc
+ 2.0.0
+
org.jsoup
jsoup
diff --git a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
index c9746bf43..8537ba1f2 100644
--- a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
+++ b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
@@ -25,8 +25,9 @@
import javax.inject.Named;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.Writer;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@@ -36,6 +37,9 @@
import com.github.chhorz.javadoc.OutputType;
import com.github.chhorz.javadoc.tags.BlockTag;
import com.github.chhorz.javadoc.tags.SinceTag;
+import org.apache.maven.doxia.module.xdoc.XdocSinkFactory;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.SinkFactory;
import org.codehaus.modello.ModelloException;
import org.codehaus.modello.ModelloParameterConstants;
import org.codehaus.modello.ModelloRuntimeException;
@@ -56,9 +60,6 @@
import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
import org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata;
import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.io.CachingWriter;
-import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
-import org.codehaus.plexus.util.xml.XMLWriter;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -115,50 +116,49 @@ private void generateXdoc(Map parameters) throws IOException {
f = new File(directory, xdocFileName);
}
- Writer writer = new CachingWriter(f, StandardCharsets.UTF_8);
+ OutputStream outputStream = new FileOutputStream(f);
+ SinkFactory sinkFactory = new XdocSinkFactory();
+ Sink sink = sinkFactory.createSink(outputStream, StandardCharsets.UTF_8.name());
- XMLWriter w = new PrettyPrintXMLWriter(writer);
-
- writer.write("\n");
-
- initHeader(w);
-
- w.startElement("document");
-
- w.startElement("properties");
-
- writeTextElement(w, "title", objectModel.getName());
-
- w.endElement();
+ // Start document
+ sink.head();
+ sink.title();
+ sink.text(objectModel.getName());
+ sink.title_();
+ sink.head_();
// Body
+ sink.body();
- w.startElement("body");
-
- w.startElement("section");
+ sink.section1();
+ sink.sectionTitle1();
+ sink.text(objectModel.getName());
+ sink.sectionTitle1_();
- w.addAttribute("name", objectModel.getName());
-
- writeMarkupElement(w, "p", getDescription(objectModel));
+ sink.paragraph();
+ writeMarkupViaSink(sink, getDescription(objectModel));
+ sink.paragraph_();
// XML representation of the model with links
ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
- writeMarkupElement(w, "source", "\n" + getModelXmlDescriptor(root));
+ sink.verbatim(null);
+ sink.rawText("\n" + getModelXmlDescriptor(root));
+ sink.verbatim_();
// Element descriptors
// Traverse from root so "abstract" models aren't included
- writeModelDescriptor(w, root);
-
- w.endElement();
+ writeModelDescriptor(sink, root);
- w.endElement();
+ sink.section1_();
- w.endElement();
+ sink.body_();
- writer.flush();
+ sink.flush();
+ sink.close();
- writer.close();
+ outputStream.flush();
+ outputStream.close();
}
/**
@@ -179,24 +179,24 @@ private String getAnchorName(String tagName, ModelClass modelClass) {
/**
* Write description of the whole model.
*
- * @param w the output writer
+ * @param sink the Doxia sink
* @param rootModelClass the root class of the model
*/
- private void writeModelDescriptor(XMLWriter w, ModelClass rootModelClass) {
- writeElementDescriptor(w, rootModelClass, null, new HashSet<>(), new HashMap<>());
+ private void writeModelDescriptor(Sink sink, ModelClass rootModelClass) {
+ writeElementDescriptor(sink, rootModelClass, null, new HashSet<>(), new HashMap<>());
}
/**
* Write description of an element of the XML representation of the model. This method is recursive.
*
- * @param w the output writer
+ * @param sink the Doxia sink
* @param modelClass the mode class to describe
* @param association the association we are coming from (can be null
)
* @param writtenIds set of data already written ids
* @param writtenAnchors map of already written anchors with corresponding ids
*/
private void writeElementDescriptor(
- XMLWriter w,
+ Sink sink,
ModelClass modelClass,
ModelAssociation association,
Set writtenIds,
@@ -219,17 +219,17 @@ private void writeElementDescriptor(
writtenAnchors.put(anchorName, id);
}
- w.startElement("a");
+ sink.anchor(anchorName);
+ sink.anchor_();
- w.addAttribute("name", anchorName);
+ sink.section2();
+ sink.sectionTitle2();
+ sink.text(tagName);
+ sink.sectionTitle2_();
- w.endElement();
-
- w.startElement("subsection");
-
- w.addAttribute("name", tagName);
-
- writeMarkupElement(w, "p", getDescription(modelClass));
+ sink.paragraph();
+ writeMarkupViaSink(sink, getDescription(modelClass));
+ sink.paragraph_();
List elementFields = getFieldsForXml(modelClass, getGeneratedVersion());
@@ -237,23 +237,22 @@ private void writeElementDescriptor(
if (contentField != null) {
// this model class has a Content field
- w.startElement("p");
-
- writeTextElement(w, "b", "Element Content: ");
-
- w.writeMarkup(getDescription(contentField));
-
- w.endElement();
+ sink.paragraph();
+ sink.bold();
+ sink.text("Element Content: ");
+ sink.bold_();
+ writeMarkupViaSink(sink, getDescription(contentField));
+ sink.paragraph_();
}
List attributeFields = getXmlAttributeFields(elementFields);
elementFields.removeAll(attributeFields);
- writeFieldsTable(w, attributeFields, false); // write attributes
- writeFieldsTable(w, elementFields, true); // write elements
+ writeFieldsTable(sink, attributeFields, false); // write attributes
+ writeFieldsTable(sink, elementFields, true); // write elements
- w.endElement();
+ sink.section2_();
// check every fields that are inner associations to write their element descriptor
for (ModelField f : elementFields) {
@@ -262,7 +261,7 @@ private void writeElementDescriptor(
ModelClass fieldModelClass = getModel().getClass(assoc.getTo(), getGeneratedVersion());
if (!writtenIds.contains(getId(resolveTagName(fieldModelClass, assoc), fieldModelClass))) {
- writeElementDescriptor(w, fieldModelClass, assoc, writtenIds, writtenAnchors);
+ writeElementDescriptor(sink, fieldModelClass, assoc, writtenIds, writtenAnchors);
}
}
}
@@ -275,11 +274,11 @@ private String getId(String tagName, ModelClass modelClass) {
/**
* Write a table containing model fields description.
*
- * @param w the output writer
+ * @param sink the Doxia sink
* @param fields the fields to add in the table
* @param elementFields true
if fields are elements, false
if fields are attributes
*/
- private void writeFieldsTable(XMLWriter w, List fields, boolean elementFields) {
+ private void writeFieldsTable(Sink sink, List fields, boolean elementFields) {
if (fields == null || fields.isEmpty()) {
// skip empty table
return;
@@ -290,23 +289,31 @@ private void writeFieldsTable(XMLWriter w, List fields, boolean elem
return;
}
- w.startElement("table");
+ sink.table();
- w.startElement("tr");
+ sink.tableRow();
- writeTextElement(w, "th", elementFields ? "Element" : "Attribute");
+ sink.tableHeaderCell();
+ sink.text(elementFields ? "Element" : "Attribute");
+ sink.tableHeaderCell_();
- writeTextElement(w, "th", "Type");
+ sink.tableHeaderCell();
+ sink.text("Type");
+ sink.tableHeaderCell_();
boolean showSinceColumn = version.greaterThan(firstVersion);
if (showSinceColumn) {
- writeTextElement(w, "th", "Since");
+ sink.tableHeaderCell();
+ sink.text("Since");
+ sink.tableHeaderCell_();
}
- writeTextElement(w, "th", "Description");
+ sink.tableHeaderCell();
+ sink.text("Description");
+ sink.tableHeaderCell_();
- w.endElement(); // tr
+ sink.tableRow_();
for (ModelField f : fields) {
XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) f.getMetadata(XmlFieldMetadata.ID);
@@ -315,15 +322,15 @@ private void writeFieldsTable(XMLWriter w, List fields, boolean elem
continue;
}
- w.startElement("tr");
+ sink.tableRow();
// Element/Attribute column
String tagName = resolveTagName(f, xmlFieldMetadata);
- w.startElement("td");
+ sink.tableCell();
- w.startElement("code");
+ sink.monospaced();
boolean manyAssociation = false;
@@ -338,101 +345,102 @@ private void writeFieldsTable(XMLWriter w, List fields, boolean elem
String itemTagName = manyAssociation ? resolveTagName(tagName, xmlAssociationMetadata) : tagName;
if (manyAssociation && xmlAssociationMetadata.isWrappedItems()) {
- w.writeText(tagName);
- w.writeMarkup("/");
+ sink.text(tagName);
+ sink.rawText("/");
}
if (isInnerAssociation(f)) {
- w.startElement("a");
- w.addAttribute("href", "#" + getAnchorName(itemTagName, assoc.getToClass()));
- w.writeText(itemTagName);
- w.endElement();
+ sink.link("#" + getAnchorName(itemTagName, assoc.getToClass()));
+ sink.text(itemTagName);
+ sink.link_();
} else if (ModelDefault.PROPERTIES.equals(f.getType())) {
if (xmlAssociationMetadata.isMapExplode()) {
- w.writeText("(key,value)");
+ sink.text("(key,value)");
} else {
- w.writeMarkup("key=value");
+ sink.rawText("key=value");
}
} else {
- w.writeText(itemTagName);
+ sink.text(itemTagName);
}
if (manyAssociation) {
- w.writeText("*");
+ sink.text("*");
}
} else {
- w.writeText(tagName);
+ sink.text(tagName);
}
- w.endElement(); // code
+ sink.monospaced_();
- w.endElement(); // td
+ sink.tableCell_();
// Type column
- w.startElement("td");
+ sink.tableCell();
- w.startElement("code");
+ sink.monospaced();
if (f instanceof ModelAssociation) {
ModelAssociation assoc = (ModelAssociation) f;
if (assoc.isOneMultiplicity()) {
- w.writeText(assoc.getTo());
+ sink.text(assoc.getTo());
} else {
- w.writeText(assoc.getType().substring("java.util.".length()));
+ sink.text(assoc.getType().substring("java.util.".length()));
if (assoc.isGenericType()) {
- w.writeText("<" + assoc.getTo() + ">");
+ sink.text("<" + assoc.getTo() + ">");
}
}
} else {
- w.writeText(f.getType());
+ sink.text(f.getType());
}
- w.endElement(); // code
+ sink.monospaced_();
- w.endElement(); // td
+ sink.tableCell_();
// Since column
if (showSinceColumn) {
- w.startElement("td");
+ sink.tableCell();
if (f.getVersionRange() != null) {
Version fromVersion = f.getVersionRange().getFromVersion();
if (fromVersion != null && fromVersion.greaterThan(firstVersion)) {
- w.writeMarkup(fromVersion.toString());
+ sink.rawText(fromVersion.toString());
}
}
- w.endElement();
+ sink.tableCell_();
}
// Description column
- w.startElement("td");
+ sink.tableCell();
if (manyAssociation) {
- w.writeMarkup("(Many) ");
+ sink.rawText("(Many) ");
}
- w.writeMarkup(getDescription(f));
+ writeMarkupViaSink(sink, getDescription(f));
// Write the default value, if it exists.
// But only for fields that are not a ModelAssociation
if (f.getDefaultValue() != null && !(f instanceof ModelAssociation)) {
- w.writeMarkup("Default value: ");
+ sink.rawText("
Default value: ");
- writeTextElement(w, "code", f.getDefaultValue());
+ sink.monospaced();
+ sink.text(f.getDefaultValue());
+ sink.monospaced_();
- w.writeMarkup("
");
+ sink.rawText("
");
}
- w.endElement(); // td
+ sink.tableCell_();
- w.endElement(); // tr
+ sink.tableRow_();
}
- w.endElement(); // table
+ sink.table_();
}
/**
@@ -669,16 +677,8 @@ private static String getDescription(BaseElement element) {
return (element.getDescription() == null) ? "No description." : rewrite(element.getDescription());
}
- private static void writeTextElement(XMLWriter w, String name, String text) {
- w.startElement(name);
- w.writeText(text);
- w.endElement();
- }
-
- private static void writeMarkupElement(XMLWriter w, String name, String markup) {
- w.startElement(name);
- w.writeMarkup(markup);
- w.endElement();
+ private static void writeMarkupViaSink(Sink sink, String markup) {
+ sink.rawText(markup);
}
/**
From be7a02ead036bd63c19e52fb23030ca289202358 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Oct 2025 17:57:23 +0000
Subject: [PATCH 2/3] Migrate XdocGenerator to use Doxia Sink API - tables need
debugging
Co-authored-by: slachiewicz <6705942+slachiewicz@users.noreply.github.com>
---
.../java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
index 8537ba1f2..e6bb1d11b 100644
--- a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
+++ b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
@@ -289,7 +289,7 @@ private void writeFieldsTable(Sink sink, List fields, boolean elemen
return;
}
- sink.table();
+ sink.table(null);
sink.tableRow();
From 0f3efdbe54ae30ba99f539617f8ad8d16b0ebb1e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Oct 2025 18:01:45 +0000
Subject: [PATCH 3/3] Successfully migrate XdocGenerator to Doxia Sink API with
XDOC 2.0 output
Co-authored-by: slachiewicz <6705942+slachiewicz@users.noreply.github.com>
---
.../modello/plugin/xdoc/XdocGenerator.java | 5 +-
.../plugin/xdoc/XdocGeneratorTest.java | 5 +-
.../src/test/resources/html4.expected.xml | 58 ++++++-------------
3 files changed, 24 insertions(+), 44 deletions(-)
diff --git a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
index e6bb1d11b..4a1e358c4 100644
--- a/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
+++ b/modello-plugins/modello-plugin-xdoc/src/main/java/org/codehaus/modello/plugin/xdoc/XdocGenerator.java
@@ -289,7 +289,8 @@ private void writeFieldsTable(Sink sink, List fields, boolean elemen
return;
}
- sink.table(null);
+ // Workaround: Doxia Sink's table() method doesn't seem to output tag
+ sink.rawText("");
sink.tableRow();
@@ -440,7 +441,7 @@ private void writeFieldsTable(Sink sink, List fields, boolean elemen
sink.tableRow_();
}
- sink.table_();
+ sink.rawText("
");
}
/**
diff --git a/modello-plugins/modello-plugin-xdoc/src/test/java/org/codehaus/modello/plugin/xdoc/XdocGeneratorTest.java b/modello-plugins/modello-plugin-xdoc/src/test/java/org/codehaus/modello/plugin/xdoc/XdocGeneratorTest.java
index da8ac6d5f..bbead7c55 100644
--- a/modello-plugins/modello-plugin-xdoc/src/test/java/org/codehaus/modello/plugin/xdoc/XdocGeneratorTest.java
+++ b/modello-plugins/modello-plugin-xdoc/src/test/java/org/codehaus/modello/plugin/xdoc/XdocGeneratorTest.java
@@ -180,12 +180,13 @@ private void checkInternalLinks(String filename) throws Exception {
Assert.assertTrue("should find some '