diff --git a/xstream-distribution/src/content/changes.html b/xstream-distribution/src/content/changes.html
index b5e83bc8e..e868edb75 100644
--- a/xstream-distribution/src/content/changes.html
+++ b/xstream-distribution/src/content/changes.html
@@ -33,12 +33,31 @@
Upcoming 1.4.x maintenance release
Not yet released.
+ Major changes
+
+
+ GHI:#308: Add converter for AtomicBoolean of package java.util.concurrent.atomic.
+
+
Minor changes
GHPR:#287: Close stream opened from provided URL.
+ Stream compatibility
+
+
+ The atomic types with new converters of package java.util.concurrent.atomic, that have been written with
+ previous versions of XStream, can still be deserialized.
+
+
+ API changes
+
+
+ Added c.t.x.converters.extended.AtomicBooleanConverter.
+
+
1.4.19
Released January 29, 2022.
diff --git a/xstream-distribution/src/content/converters.html b/xstream-distribution/src/content/converters.html
index d88c2f736..708bf4546 100644
--- a/xstream-distribution/src/content/converters.html
+++ b/xstream-distribution/src/content/converters.html
@@ -1,7 +1,7 @@
+
+
+
+
+ Converter
+ Supported types
+ Example
+ Notes
+ Prio
+
+
+ AtomicBooleanConverter
+ java.util.concurrent.atomic.AtomicBoolean
+
+ <atomic-boolean>true</atomic-boolean>
+
+ Available with Java 1.5 or greater.
+ normal
+
+
diff --git a/xstream/pom.xml b/xstream/pom.xml
index 4dcfbd68e..9462c3523 100644
--- a/xstream/pom.xml
+++ b/xstream/pom.xml
@@ -329,6 +329,7 @@
**/enums/*
**/EnumMapper*
**/*15.java
+ **/Atomic*Converter.java
**/PathConverter.java
**/Base64*Codec.java
**/Types.java
@@ -591,6 +592,7 @@
**/core/util/Types*
**/reflection/*15*
**/extended/*15*
+ **/extended/Atomic*Converter.java
**/extended/PathConverter*
**/io/xml/JDom2*
diff --git a/xstream/src/java/com/thoughtworks/xstream/XStream.java b/xstream/src/java/com/thoughtworks/xstream/XStream.java
index 18cb47112..fe14d5640 100644
--- a/xstream/src/java/com/thoughtworks/xstream/XStream.java
+++ b/xstream/src/java/com/thoughtworks/xstream/XStream.java
@@ -682,6 +682,7 @@ protected void setupSecurity() {
types.add(URL.class);
types.add(URI.class);
types.add(JVM.loadClassForName("java.util.UUID"));
+ types.add(JVM.loadClassForName("java.util.concurrent.atomic.AtomicBoolean"));
if (JVM.isSQLAvailable()) {
types.add(JVM.loadClassForName("java.sql.Timestamp"));
types.add(JVM.loadClassForName("java.sql.Time"));
@@ -835,6 +836,7 @@ protected void setupAliases() {
alias("enum-map", JVM.loadClassForName("java.util.EnumMap"));
alias("string-builder", JVM.loadClassForName("java.lang.StringBuilder"));
alias("uuid", JVM.loadClassForName("java.util.UUID"));
+ alias("atomic-boolean", JVM.loadClassForName("java.util.concurrent.atomic.AtomicBoolean"));
}
if (JVM.isVersion(7)) {
@@ -992,6 +994,8 @@ protected void setupConverters() {
PRIORITY_NORMAL, null, null);
registerConverterDynamically("com.thoughtworks.xstream.converters.basic.UUIDConverter", PRIORITY_NORMAL,
null, null);
+ registerConverterDynamically("com.thoughtworks.xstream.converters.extended.AtomicBooleanConverter", PRIORITY_NORMAL,
+ null, null);
}
if (JVM.loadClassForName("javax.activation.ActivationDataFlavor") != null) {
registerConverterDynamically("com.thoughtworks.xstream.converters.extended.ActivationDataFlavorConverter",
diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java
new file mode 100644
index 000000000..ba9cc5523
--- /dev/null
+++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 XStream Committers.
+ * All rights reserved.
+ *
+ * The software in this package is published under the terms of the BSD
+ * style license a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ *
+ * Created on 26. November 2022 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.converters.extended;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.converters.basic.BooleanConverter;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+
+
+/**
+ * Converts an AtomicBoolean type.
+ *
+ * @author Jörg Schaible
+ */
+public class AtomicBooleanConverter extends BooleanConverter implements Converter {
+
+ /**
+ * Constructs an AtomicBooleanConverter. Initializes the converter with true and false as
+ * string representation.
+ */
+ public AtomicBooleanConverter() {
+ super();
+ }
+
+ public boolean canConvert(final Class type) {
+ return type != null && type == AtomicBoolean.class;
+ }
+
+ public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
+ writer.setValue(toString(source));
+ }
+
+ public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
+ final String data = reader.getValue(); // needs to be called before hasMoreChildren.
+ if (!reader.hasMoreChildren()) {
+ return fromString(data);
+ } else {
+ // backwards compatibility ... unmarshal nested element
+ reader.moveDown();
+ final AtomicBoolean atomicBoolean = new AtomicBoolean("1".equals(reader.getValue()));
+ reader.moveUp();
+ return atomicBoolean;
+ }
+ }
+
+ public String toString(final Object obj) {
+ return super.toString(((AtomicBoolean)obj).get() ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ public Object fromString(final String str) {
+ return new AtomicBoolean(((Boolean)super.fromString(str)).booleanValue());
+ }
+}
diff --git a/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java
index 9de4979a6..608a6ce63 100644
--- a/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java
+++ b/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2012, 2015, 2017, 2018 XStream Committers.
+ * Copyright (C) 2012, 2015, 2017, 2018, 2022 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
- *
+ *
* Created on 21. March 2012 by Joerg Schaible
*/
package com.thoughtworks.acceptance;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.core.JVM;
@@ -20,10 +21,10 @@
public class Concurrent15TypesTest extends AbstractAcceptanceTest {
public void testConcurrentHashMap() {
- ConcurrentHashMap map = new ConcurrentHashMap();
+ final ConcurrentHashMap map = new ConcurrentHashMap<>();
map.put("walnes", "joe");
- String xml = xstream.toXML(map);
- String expected = ""
+ final String xml = xstream.toXML(map);
+ final String expected = ""
+ "\n"
+ " \n"
+ " walnes \n"
@@ -32,7 +33,7 @@ public void testConcurrentHashMap() {
+ " ";
assertEquals(xml, expected);
@SuppressWarnings("unchecked")
- ConcurrentHashMap out = (ConcurrentHashMap)xstream.fromXML(xml);
+ final ConcurrentHashMap out = (ConcurrentHashMap)xstream.fromXML(xml);
assertEquals("{walnes=joe}", out.toString());
}
@@ -45,10 +46,10 @@ public void testDerivedConcurrentHashMap() {
xstream.alias("derived-map", DerivedConcurrentHashMap.class);
xstream.registerConverter(new MapConverter(xstream.getMapper(), DerivedConcurrentHashMap.class));
- Map map = new DerivedConcurrentHashMap();
+ final Map map = new DerivedConcurrentHashMap();
map.put("test", "JUnit");
- String xml = ""
+ final String xml = ""
+ "\n"
+ " \n"
+ " test \n"
@@ -59,4 +60,16 @@ public void testDerivedConcurrentHashMap() {
assertBothWays(map, xml);
}
}
+
+ public void testAtomicBoolean() {
+ final AtomicBoolean atomicBoolean = new AtomicBoolean();
+ assertBothWays(atomicBoolean, "" + atomicBoolean + " ");
+ }
+
+ public void testAtomicBooleanWithOldFormat() {
+ assertEquals(new AtomicBoolean(true).toString(), xstream.fromXML("" //
+ + "\n" //
+ + " 1 \n" //
+ + " ").toString());
+ }
}