Skip to content

Commit

Permalink
Add WeakHashMapConverter.
Browse files Browse the repository at this point in the history
  • Loading branch information
joehni committed Oct 18, 2024
1 parent 29fdeb8 commit 4adc90f
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
14 changes: 14 additions & 0 deletions xstream-distribution/src/content/changes.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ <h1 id="upcoming-1.4.x">Upcoming 1.4.x maintenance release</h1>

<p>Not yet released.</p>

<h2>Major changes</h2>

<ul>
<li>Add a converter for the WeakHashMap which does not write any elements of the map. Avoids also access to the
ReentrantLock contained in the WeakHashMap since Java 19.</li>
</ul>

<h2>Minor changes</h2>

<ul>
Expand All @@ -125,6 +132,13 @@ <h2>API changes</h2>
<ul>
<li>Added constant c.t.x.io.xml.PrettyPrintWriter.XML_1_0_REPLACEMENT.</li>
<li>Added constant c.t.x.io.xml.PrettyPrintWriter.XML_1_1_REPLACEMENT.</li>
<li>Added c.t.x.converters.collections.WeakHashMapConverter.</li>
</ul>

<h2>Stream compatibility</h2>

<ul>
<li>The WeakHashMaps, that have been written with previous versions of XStream, can still be deserialized.</li>
</ul>

<h1 id="1.4.20">1.4.20</h1>
Expand Down
11 changes: 11 additions & 0 deletions xstream-distribution/src/content/converters.html
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@
If the Properties instance includes a set of default Properties, these are serialized in a nested <code>&lt;defaults&gt;</code> element.</td>
<td>normal</td>
</tr>
<tr>
<td><a href="javadoc/com/thoughtworks/xstream/converters/collections/WeakHashMapConverter.html">WeakHashMapConverter</a></td>
<td>java.util.WeakHashMap</td>
<td class="example">
&lt;weak-hash-map/&gt;
</td>
<td>A WeakHashMap is supposed to release its elements when they are no longer referenced. Therefore is at unmarshalling time no guarantee that
an entry is still available when it is referenced later in the stream. As consequence the converter will marshal no elements at all, it
will create an empty WeakHashMap at unmarshalling time.</td>
<td>normal</td>
</tr>
<tr>
<td><a href="javadoc/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.html">SingletonCollectionConverter</a></td>
<td>java.util.Collections.singletonList().getClass()<br/>java.util.Collections.singleton().getClass()</td>
Expand Down
6 changes: 5 additions & 1 deletion xstream/src/java/com/thoughtworks/xstream/XStream.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes.
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 XStream Committers.
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2024 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
Expand Down Expand Up @@ -104,6 +104,7 @@
import java.util.TreeSet;
import java.util.UUID;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -146,6 +147,7 @@
import com.thoughtworks.xstream.converters.collections.SingletonMapConverter;
import com.thoughtworks.xstream.converters.collections.TreeMapConverter;
import com.thoughtworks.xstream.converters.collections.TreeSetConverter;
import com.thoughtworks.xstream.converters.collections.WeakHashMapConverter;
import com.thoughtworks.xstream.converters.enums.EnumConverter;
import com.thoughtworks.xstream.converters.enums.EnumMapConverter;
import com.thoughtworks.xstream.converters.enums.EnumSetConverter;
Expand Down Expand Up @@ -843,6 +845,7 @@ protected void setupAliases() {
alias("hashtable", Hashtable.class);
alias("linked-hash-map", LinkedHashMap.class);
alias("linked-hash-set", LinkedHashSet.class);
alias("weak-hash-map", WeakHashMap.class);
alias("concurrent-hash-map", ConcurrentHashMap.class);
alias("atomic-boolean", AtomicBoolean.class);
alias("atomic-int", AtomicInteger.class);
Expand Down Expand Up @@ -1001,6 +1004,7 @@ protected void setupConverters() {
registerConverter(new EnumConverter(), PRIORITY_NORMAL);
registerConverter(new EnumSetConverter(mapper), PRIORITY_NORMAL);
registerConverter(new EnumMapConverter(mapper), PRIORITY_NORMAL);
registerConverter(new WeakHashMapConverter(), PRIORITY_NORMAL);

registerConverter(new FileConverter(), PRIORITY_NORMAL);
if (JVM.isSQLAvailable()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 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 19. October 2024 by Joerg Schaible
*/
package com.thoughtworks.xstream.converters.collections;

import java.util.WeakHashMap;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;


/**
* Converts a WeakHashMap. A WeakHashMap is supposed to release its elements when they are no longer referenced.
* Therefore is at unmarshalling time no guarantee that an entry is still available when it is referenced later in the
* stream. As consequence the converter will marshal no elements at all, it will create an empty WeakHashMap at
* unmarshalling time.
*
* @author Joerg Schaible
* @since upcoming
*/
public class WeakHashMapConverter implements Converter {

@Override
public boolean canConvert(final Class<?> type) {
return WeakHashMap.class == type;
}

@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
// do nothing
}

@Override
public WeakHashMap<?, ?> unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
@SuppressWarnings("rawtypes")
final WeakHashMap<?, ?> weakHashMap = new WeakHashMap();
return weakHashMap;
}
}
12 changes: 11 additions & 1 deletion xstream/src/test/com/thoughtworks/acceptance/MapTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003, 2004, 2005 Joe Walnes.
* Copyright (C) 2006, 2007, 2011, 2017, 2018, 2021 XStream Committers.
* Copyright (C) 2006, 2007, 2011, 2017, 2018, 2021, 2024 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
Expand All @@ -18,6 +18,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import com.thoughtworks.acceptance.objects.Hardware;
import com.thoughtworks.acceptance.objects.Software;
Expand Down Expand Up @@ -109,6 +110,15 @@ public void testSupportsOldHashtables() {
assertBothWays(hashtable, expected);
}

public void testSupportsWeakHashMap() {
final WeakHashMap<String, String> hashtable = new WeakHashMap<>();
hashtable.put("hello", "world");

final String expected = "<weak-hash-map/>";

assertBothWays(hashtable, expected);
}

static class ThingWithDifferentTypesOfMaps extends StandardObject {
private static final long serialVersionUID = 200403L;
final Map<?, ?> m1 = new HashMap<>();
Expand Down

0 comments on commit 4adc90f

Please sign in to comment.