diff --git a/release-notes/VERSION b/release-notes/VERSION index 2e6e5a04..8598a801 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -114,6 +114,8 @@ Version: 3.x (for earlier see VERSION-2.x) #802: Serialization with Polymorphisme and `EXTERNAL_PROPERTY` = duplicate property (reported by @ Adrien-dev25 ) (fix by @cowtowncoder, w/ Claude code) +#845: Implement `JsonGenerator` methods `writeComment()` and `canWriteComments()` + (implemented by @cowtowncoder, w/ Claude code) 3.1.1 (27-Mar-2026) diff --git a/src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java b/src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java index 666054ad..3e48b0f8 100644 --- a/src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java +++ b/src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java @@ -253,21 +253,30 @@ public void initGenerator() throws JacksonException /* /********************************************************************** - /* Overridden output state handling methods + /* Overrides: capability introspection /********************************************************************** */ - - @Override - public final TokenStreamContext streamWriteContext() { return _streamWriteContext; } + + @Override // @since 3.2 + public boolean canWriteComments() { return true; } + + // Base class impl fine: + //@Override public boolean canWriteObjectId() { return false; } + + // Base class impl fine: + //@Override public boolean canOmitProperties() { return true; } + + // Base class impl fine: + //@Override public boolean canWriteTypeId() { return false; } @Override - public final Object currentValue() { - return _streamWriteContext.currentValue(); + public boolean has(StreamWriteCapability capability) { + return DEFAULT_TEXTUAL_WRITE_CAPABILITIES.isEnabled(capability); } @Override - public final void assignCurrentValue(Object v) { - _streamWriteContext.assignCurrentValue(v); + public JacksonFeatureSet streamWriteCapabilities() { + return DEFAULT_TEXTUAL_WRITE_CAPABILITIES; } /* @@ -297,6 +306,25 @@ public int streamWriteOutputBuffered() { return -1; } + /* + /********************************************************************** + /* Overridden output state handling methods + /********************************************************************** + */ + + @Override + public final TokenStreamContext streamWriteContext() { return _streamWriteContext; } + + @Override + public final Object currentValue() { + return _streamWriteContext.currentValue(); + } + + @Override + public final void assignCurrentValue(Object v) { + _streamWriteContext.assignCurrentValue(v); + } + /* /********************************************************************** /* Extended API, configuration @@ -316,16 +344,6 @@ public ToXmlGenerator configure(XmlWriteFeature f, boolean state) { return this; } - @Override - public boolean has(StreamWriteCapability capability) { - return DEFAULT_TEXTUAL_WRITE_CAPABILITIES.isEnabled(capability); - } - - @Override - public JacksonFeatureSet streamWriteCapabilities() { - return DEFAULT_TEXTUAL_WRITE_CAPABILITIES; - } - public boolean inRoot() { return _streamWriteContext.inRoot(); } @@ -906,6 +924,27 @@ public JsonGenerator writeRaw(char c) throws JacksonException return writeRaw(String.valueOf(c)); } + /* + /********************************************************************** + /* Output method implementations, comments + /********************************************************************** + */ + + @Override // @since 3.2 + public JsonGenerator writeComment(String comment) throws JacksonException + { + try { + if (comment != null) { + _xmlWriter.writeComment(comment); + } else { + _xmlWriter.writeSpace("\n"); + } + } catch (XMLStreamException e) { + StaxUtil.throwAsWriteException(e, this); + } + return this; + } + /* /********************************************************************** /* Output method implementations, base64-encoded binary diff --git a/src/test/java/tools/jackson/dataformat/xml/stream/XmlGeneratorTest.java b/src/test/java/tools/jackson/dataformat/xml/stream/XmlGeneratorTest.java index feb14152..e6a8c114 100644 --- a/src/test/java/tools/jackson/dataformat/xml/stream/XmlGeneratorTest.java +++ b/src/test/java/tools/jackson/dataformat/xml/stream/XmlGeneratorTest.java @@ -12,6 +12,7 @@ import tools.jackson.dataformat.xml.ser.ToXmlGenerator; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class XmlGeneratorTest extends XmlTestUtil { @@ -312,4 +313,52 @@ public void testRawCharArratAttribute() throws Exception xml = removeSjsxpNamespace(xml); assertEquals("", xml); } + + // [dataformat-xml#845] + @Test + public void testCanWriteComments() throws Exception + { + StringWriter out = new StringWriter(); + ToXmlGenerator gen = (ToXmlGenerator) MAPPER.createGenerator(out); + assertTrue(gen.canWriteComments()); + // Need to write something to avoid empty document error on close + gen.setNextName(new QName("root")); + gen.writeStartObject(); + gen.writeEndObject(); + gen.close(); + } + + // [dataformat-xml#845] + @Test + public void testWriteCommentInObject() throws Exception + { + StringWriter out = new StringWriter(); + ToXmlGenerator gen = (ToXmlGenerator) MAPPER.createGenerator(out); + gen.setNextName(new QName("root")); + gen.writeStartObject(); + gen.writeComment("a comment"); + gen.writeName("elem"); + gen.writeString("value"); + gen.writeEndObject(); + gen.close(); + String xml = removeSjsxpNamespace(out.toString()); + assertEquals("value", xml); + } + + // [dataformat-xml#845] + @Test + public void testWriteCommentNullWritesEmptyLine() throws Exception + { + StringWriter out = new StringWriter(); + ToXmlGenerator gen = (ToXmlGenerator) MAPPER.createGenerator(out); + gen.setNextName(new QName("root")); + gen.writeStartObject(); + gen.writeComment(null); + gen.writeName("elem"); + gen.writeString("value"); + gen.writeEndObject(); + gen.close(); + String xml = removeSjsxpNamespace(out.toString()); + assertEquals("\nvalue", xml); + } }