Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
75 changes: 57 additions & 18 deletions src/main/java/tools/jackson/dataformat/xml/ser/ToXmlGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<StreamWriteCapability> streamWriteCapabilities() {
return DEFAULT_TEXTUAL_WRITE_CAPABILITIES;
}

/*
Expand Down Expand Up @@ -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
Expand All @@ -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<StreamWriteCapability> streamWriteCapabilities() {
return DEFAULT_TEXTUAL_WRITE_CAPABILITIES;
}

public boolean inRoot() {
return _streamWriteContext.inRoot();
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -312,4 +313,52 @@ public void testRawCharArratAttribute() throws Exception
xml = removeSjsxpNamespace(xml);
assertEquals("<root attr=\"value\"/>", 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("<root><!--a comment--><elem>value</elem></root>", 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("<root>\n<elem>value</elem></root>", xml);
}
}