1
1
/*
2
- * Copyright 2002-2018 the original author or authors.
2
+ * Copyright 2002-2019 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
package org .springframework .util ;
18
18
19
19
import java .io .Serializable ;
20
+ import java .util .AbstractCollection ;
21
+ import java .util .AbstractSet ;
20
22
import java .util .Collection ;
21
23
import java .util .HashMap ;
24
+ import java .util .Iterator ;
22
25
import java .util .LinkedHashMap ;
23
26
import java .util .Locale ;
24
27
import java .util .Map ;
25
28
import java .util .Set ;
29
+ import java .util .Spliterator ;
30
+ import java .util .function .Consumer ;
26
31
import java .util .function .Function ;
27
32
28
33
import org .springframework .lang .Nullable ;
37
42
* <p>Does <i>not</i> support {@code null} keys.
38
43
*
39
44
* @author Juergen Hoeller
45
+ * @author Phillip Webb
40
46
* @since 3.0
41
47
* @param <V> the value type
42
48
*/
@@ -49,6 +55,12 @@ public class LinkedCaseInsensitiveMap<V> implements Map<String, V>, Serializable
49
55
50
56
private final Locale locale ;
51
57
58
+ private transient Set <String > keySet ;
59
+
60
+ private transient Collection <V > values ;
61
+
62
+ private transient Set <Entry <String , V >> entrySet ;
63
+
52
64
53
65
/**
54
66
* Create a new LinkedCaseInsensitiveMap that stores case-insensitive keys
@@ -98,7 +110,7 @@ public boolean containsKey(Object key) {
98
110
protected boolean removeEldestEntry (Map .Entry <String , V > eldest ) {
99
111
boolean doRemove = LinkedCaseInsensitiveMap .this .removeEldestEntry (eldest );
100
112
if (doRemove ) {
101
- caseInsensitiveKeys . remove ( convertKey ( eldest .getKey () ));
113
+ removeCaseInsensitiveKey ( eldest .getKey ());
102
114
}
103
115
return doRemove ;
104
116
}
@@ -208,7 +220,7 @@ public V computeIfAbsent(String key, Function<? super String, ? extends V> mappi
208
220
@ Nullable
209
221
public V remove (Object key ) {
210
222
if (key instanceof String ) {
211
- String caseInsensitiveKey = this . caseInsensitiveKeys . remove ( convertKey (( String ) key ) );
223
+ String caseInsensitiveKey = removeCaseInsensitiveKey (( String ) key );
212
224
if (caseInsensitiveKey != null ) {
213
225
return this .targetMap .remove (caseInsensitiveKey );
214
226
}
@@ -224,17 +236,32 @@ public void clear() {
224
236
225
237
@ Override
226
238
public Set <String > keySet () {
227
- return this .targetMap .keySet ();
239
+ Set <String > keySet = this .keySet ;
240
+ if (keySet == null ) {
241
+ keySet = new KeySet (this .targetMap .keySet ());
242
+ this .keySet = keySet ;
243
+ }
244
+ return keySet ;
228
245
}
229
246
230
247
@ Override
231
248
public Collection <V > values () {
232
- return this .targetMap .values ();
249
+ Collection <V > values = this .values ;
250
+ if (values == null ) {
251
+ values = new Values (this .targetMap .values ());
252
+ this .values = values ;
253
+ }
254
+ return values ;
233
255
}
234
256
235
257
@ Override
236
258
public Set <Entry <String , V >> entrySet () {
237
- return this .targetMap .entrySet ();
259
+ Set <Entry <String , V >> entrySet = this .entrySet ;
260
+ if (entrySet == null ) {
261
+ entrySet = new EntrySet (this .targetMap .entrySet ());
262
+ this .entrySet = entrySet ;
263
+ }
264
+ return entrySet ;
238
265
}
239
266
240
267
@ Override
@@ -293,4 +320,216 @@ protected boolean removeEldestEntry(Map.Entry<String, V> eldest) {
293
320
return false ;
294
321
}
295
322
323
+ private String removeCaseInsensitiveKey (String key ) {
324
+ return this .caseInsensitiveKeys .remove (convertKey (key ));
325
+ }
326
+
327
+
328
+ private class KeySet extends AbstractSet <String > {
329
+
330
+ private final Set <String > delegate ;
331
+
332
+
333
+ KeySet (Set <String > delegate ) {
334
+ this .delegate = delegate ;
335
+ }
336
+
337
+
338
+ @ Override
339
+ public int size () {
340
+ return this .delegate .size ();
341
+ }
342
+
343
+ @ Override
344
+ public boolean contains (Object o ) {
345
+ return this .delegate .contains (o );
346
+ }
347
+
348
+ @ Override
349
+ public Iterator <String > iterator () {
350
+ return new KeySetIterator ();
351
+ }
352
+
353
+ @ Override
354
+ public boolean remove (Object o ) {
355
+ return LinkedCaseInsensitiveMap .this .remove (o ) != null ;
356
+ }
357
+
358
+ @ Override
359
+ public void clear () {
360
+ LinkedCaseInsensitiveMap .this .clear ();
361
+ }
362
+
363
+ @ Override
364
+ public Spliterator <String > spliterator () {
365
+ return this .delegate .spliterator ();
366
+ }
367
+
368
+ @ Override
369
+ public void forEach (Consumer <? super String > action ) {
370
+ this .delegate .forEach (action );
371
+ }
372
+
373
+ }
374
+
375
+
376
+ private class Values extends AbstractCollection <V > {
377
+
378
+ private final Collection <V > delegate ;
379
+
380
+
381
+ Values (Collection <V > delegate ) {
382
+ this .delegate = delegate ;
383
+ }
384
+
385
+
386
+ @ Override
387
+ public int size () {
388
+ return this .delegate .size ();
389
+ }
390
+
391
+ @ Override
392
+ public boolean contains (Object o ) {
393
+ return this .delegate .contains (o );
394
+ }
395
+
396
+ @ Override
397
+ public Iterator <V > iterator () {
398
+ return new ValuesIterator ();
399
+ }
400
+
401
+ @ Override
402
+ public void clear () {
403
+ LinkedCaseInsensitiveMap .this .clear ();
404
+ }
405
+
406
+ @ Override
407
+ public Spliterator <V > spliterator () {
408
+ return this .delegate .spliterator ();
409
+ }
410
+
411
+ @ Override
412
+ public void forEach (Consumer <? super V > action ) {
413
+ this .delegate .forEach (action );
414
+ }
415
+
416
+ }
417
+
418
+
419
+ private class EntrySet extends AbstractSet <Entry <String , V >> {
420
+
421
+ private final Set <Entry <String , V >> delegate ;
422
+
423
+
424
+ public EntrySet (Set <Entry <String , V >> delegate ) {
425
+ this .delegate = delegate ;
426
+ }
427
+
428
+
429
+ @ Override
430
+ public int size () {
431
+ return this .delegate .size ();
432
+ }
433
+
434
+ @ Override
435
+ public boolean contains (Object o ) {
436
+ return this .delegate .contains (o );
437
+ }
438
+
439
+ @ Override
440
+ public Iterator <Entry <String , V >> iterator () {
441
+ return new EntrySetIterator ();
442
+ }
443
+
444
+
445
+ @ Override
446
+ @ SuppressWarnings ("unchecked" )
447
+ public boolean remove (Object o ) {
448
+ if (this .delegate .remove (o )) {
449
+ removeCaseInsensitiveKey (((Map .Entry <String , V >) o ).getKey ());
450
+ return true ;
451
+ }
452
+ return false ;
453
+ }
454
+
455
+
456
+ @ Override
457
+ public void clear () {
458
+ this .delegate .clear ();
459
+ caseInsensitiveKeys .clear ();
460
+ }
461
+
462
+ @ Override
463
+ public Spliterator <Entry <String , V >> spliterator () {
464
+ return this .delegate .spliterator ();
465
+ }
466
+
467
+ @ Override
468
+ public void forEach (Consumer <? super Entry <String , V >> action ) {
469
+ this .delegate .forEach (action );
470
+ }
471
+
472
+ }
473
+
474
+
475
+ private class EntryIterator {
476
+
477
+ private final Iterator <Entry <String , V >> delegate ;
478
+
479
+ private Entry <String , V > last ;
480
+
481
+ public EntryIterator () {
482
+ this .delegate = targetMap .entrySet ().iterator ();
483
+ }
484
+
485
+ public Entry <String , V > nextEntry () {
486
+ Entry <String , V > entry = this .delegate .next ();
487
+ this .last = entry ;
488
+ return entry ;
489
+ }
490
+
491
+ public boolean hasNext () {
492
+ return this .delegate .hasNext ();
493
+ }
494
+
495
+ public void remove () {
496
+ this .delegate .remove ();
497
+ if (this .last != null ) {
498
+ removeCaseInsensitiveKey (this .last .getKey ());
499
+ this .last = null ;
500
+ }
501
+ }
502
+
503
+ }
504
+
505
+
506
+ private class KeySetIterator extends EntryIterator implements Iterator <String > {
507
+
508
+ @ Override
509
+ public String next () {
510
+ return nextEntry ().getKey ();
511
+ }
512
+
513
+ }
514
+
515
+
516
+ private class ValuesIterator extends EntryIterator implements Iterator <V > {
517
+
518
+ @ Override
519
+ public V next () {
520
+ return nextEntry ().getValue ();
521
+ }
522
+
523
+ }
524
+
525
+
526
+ private class EntrySetIterator extends EntryIterator implements Iterator <Entry <String , V >> {
527
+
528
+ @ Override
529
+ public Entry <String , V > next () {
530
+ return nextEntry ();
531
+ }
532
+
533
+ }
534
+
296
535
}
0 commit comments