2121import java .util .HashMap ;
2222import java .util .Map ;
2323import java .util .Objects ;
24+ import java .util .WeakHashMap ;
2425import org .apache .logging .log4j .util .BiConsumer ;
2526import org .apache .logging .log4j .util .ReadOnlyStringMap ;
2627import org .apache .logging .log4j .util .StringMap ;
@@ -42,13 +43,16 @@ public class JdkMapAdapterStringMap implements StringMap {
4243 }
4344 return left .compareTo (right );
4445 };
46+ // Cache of known unmodifiable map implementations.
47+ // It is a cache, no need to synchronise it between threads.
48+ private static Map <Class <?>, Void > UNMODIFIABLE_MAPS_CACHE = new WeakHashMap <>();
4549
4650 private final Map <String , String > map ;
4751 private boolean immutable = false ;
4852 private transient String [] sortedKeys ;
4953
5054 public JdkMapAdapterStringMap () {
51- this (new HashMap <String , String >(), false );
55+ this (new HashMap <>(), false );
5256 }
5357
5458 /**
@@ -58,25 +62,41 @@ public JdkMapAdapterStringMap() {
5862 @ Deprecated
5963 public JdkMapAdapterStringMap (final Map <String , String > map ) {
6064 this .map = Objects .requireNonNull (map , "map" );
61- try {
62- map .replace (Strings .EMPTY , Strings .EMPTY , Strings .EMPTY );
63- } catch (final UnsupportedOperationException ignored ) {
65+ // Known immutable implementations
66+ if (UNMODIFIABLE_MAPS_CACHE .containsKey (map .getClass ())) {
6467 immutable = true ;
68+ } else {
69+ // Check with a NO-OP replacement
70+ try {
71+ map .replace (Strings .EMPTY , Strings .EMPTY , Strings .EMPTY );
72+ } catch (final UnsupportedOperationException ignored ) {
73+ final WeakHashMap <Class <?>, Void > cache = new WeakHashMap <>(UNMODIFIABLE_MAPS_CACHE );
74+ cache .put (map .getClass (), null );
75+ UNMODIFIABLE_MAPS_CACHE = cache ;
76+ immutable = true ;
77+ }
6578 }
6679 }
6780
6881 /**
82+ * Constructs a new {@link StringMap}, based on a JDK map.
83+ * <p>
84+ * The underlying map should not be modified after this call.
85+ * </p>
86+ * <p>
87+ * If the {@link Map} implementation does not allow modifications, {@code frozen} should be set to {@code true}.
88+ * </p>
6989 * @param map a JDK map,
70- * @param immutable must be {@code true} if the map is immutable or it should not be modified .
90+ * @param frozen if {@code true} this collection will be immutable .
7191 */
72- public JdkMapAdapterStringMap (final Map <String , String > map , final boolean immutable ) {
92+ public JdkMapAdapterStringMap (final Map <String , String > map , final boolean frozen ) {
7393 this .map = Objects .requireNonNull (map , "map" );
74- this .immutable = immutable ;
94+ this .immutable = frozen ;
7595 }
7696
7797 @ Override
7898 public Map <String , String > toMap () {
79- return map ;
99+ return new HashMap <>( map ) ;
80100 }
81101
82102 private void assertNotFrozen () {
0 commit comments