diff --git a/xstream-distribution/src/content/changes.html b/xstream-distribution/src/content/changes.html
index 6e4a42c2f..1b9271141 100644
--- a/xstream-distribution/src/content/changes.html
+++ b/xstream-distribution/src/content/changes.html
@@ -38,6 +38,8 @@
Major changes
- Support for Record types (contributed by Julia Boes and Chris Hegarty, both of Oracle).
- Usage of Java generic types. Most code bases will still compile without change.
+ - GPR:#337: PrettyPrintWriter supports now characters of the Unicode Supplementary Multilingual Plane (by
+ Basil Crow).
- Support for fail-safe deserialization unless the parser is not directly involved (I/O or syntax error) as
combination of new method getLevel() of HierarchicalStreamReader and GHPR:#91.
- GHI:#120: Add Automatic-Module-Name entry to XStream's manifests.
diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java
index d5cb46374..8a5f19a69 100644
--- a/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java
+++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java
@@ -233,9 +233,7 @@ protected void writeText(final QuickWriter writer, final String text) {
}
private void writeText(final String text, final boolean isAttribute) {
- final int length = text.length();
- for (int i = 0; i < length; i++) {
- final char c = text.charAt(i);
+ text.codePoints().forEach(c -> {
switch (c) {
case '\0':
if (mode == XML_QUIRKS) {
@@ -267,7 +265,7 @@ private void writeText(final String text, final boolean isAttribute) {
case '\t':
case '\n':
if (!isAttribute) {
- writer.write(c);
+ writer.write(Character.toChars(c));
break;
}
//$FALL-THROUGH$
@@ -287,7 +285,7 @@ private void writeText(final String text, final boolean isAttribute) {
}
}
if (!replaced) {
- writer.write(c);
+ writer.write(Character.toChars(c));
}
} else {
boolean replaced = false;
@@ -326,7 +324,7 @@ private void writeText(final String text, final boolean isAttribute) {
}
}
}
- }
+ });
}
@Override
diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java
index c63cd602d..5264d41d8 100644
--- a/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java
+++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2013, 2018, 2023 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2013, 2018, 2023, 2024 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -397,6 +397,33 @@ public void testReplacesInvalidUnicodeCharactersInXml1_1ReplacementMode() {
assertXmlProducedIs("��\ue000\ufffd��");
}
+ public void testSupportsSupplementaryMultilingualPlaneInQuirks_Mode() {
+ writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_QUIRKS);
+ writer.startNode("tag");
+ writer.setValue("\uD83E\uDD8A");
+ writer.endNode();
+
+ assertXmlProducedIs("\uD83E\uDD8A");
+ }
+
+ public void testSupportsSupplementaryMultilingualPlaneInXml1_0Mode() {
+ writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0);
+ writer.startNode("tag");
+ writer.setValue("\uD83E\uDD8A");
+ writer.endNode();
+
+ assertXmlProducedIs("\uD83E\uDD8A");
+ }
+
+ public void testSupportsSupplementaryMultilingualPlaneInXml1_1Mode() {
+ writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1);
+ writer.startNode("tag");
+ writer.setValue("\uD83E\uDD8A");
+ writer.endNode();
+
+ assertXmlProducedIs("\uD83E\uDD8A");
+ }
+
private String replace(final String in, final char what, final String with) {
final int pos = in.indexOf(what);
if (pos == -1) {