36
36
import java .util .stream .Collectors ;
37
37
38
38
import org .springframework .lang .Nullable ;
39
- import org .springframework .util .MimeType .SpecificityComparator ;
40
39
41
40
/**
42
41
* Miscellaneous {@link MimeType} utility methods.
@@ -55,13 +54,10 @@ public abstract class MimeTypeUtils {
55
54
'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' ,
56
55
'V' , 'W' , 'X' , 'Y' , 'Z' };
57
56
58
- private static final ConcurrentLRUCache <String , MimeType > CACHED_MIMETYPES =
59
- new ConcurrentLRUCache <>(32 , MimeTypeUtils ::parseMimeTypeInternal );
60
-
61
57
/**
62
58
* Comparator used by {@link #sortBySpecificity(List)}.
63
59
*/
64
- public static final Comparator <MimeType > SPECIFICITY_COMPARATOR = new SpecificityComparator <>();
60
+ public static final Comparator <MimeType > SPECIFICITY_COMPARATOR = new MimeType . SpecificityComparator <>();
65
61
66
62
/**
67
63
* Public constant mime type that includes all media ranges (i.e. "*/*").
@@ -163,6 +159,10 @@ public abstract class MimeTypeUtils {
163
159
*/
164
160
public static final String TEXT_XML_VALUE = "text/xml" ;
165
161
162
+
163
+ private static final ConcurrentLruCache <String , MimeType > cachedMimeTypes =
164
+ new ConcurrentLruCache <>(32 , MimeTypeUtils ::parseMimeTypeInternal );
165
+
166
166
@ Nullable
167
167
private static volatile Random random ;
168
168
@@ -179,6 +179,7 @@ public abstract class MimeTypeUtils {
179
179
TEXT_XML = new MimeType ("text" , "xml" );
180
180
}
181
181
182
+
182
183
/**
183
184
* Parse the given String into a single {@code MimeType}.
184
185
* Recently parsed {@code MimeType} are cached for further retrieval.
@@ -187,7 +188,7 @@ public abstract class MimeTypeUtils {
187
188
* @throws InvalidMimeTypeException if the string cannot be parsed
188
189
*/
189
190
public static MimeType parseMimeType (String mimeType ) {
190
- return CACHED_MIMETYPES .get (mimeType );
191
+ return cachedMimeTypes .get (mimeType );
191
192
}
192
193
193
194
private static MimeType parseMimeTypeInternal (String mimeType ) {
@@ -275,6 +276,7 @@ public static List<MimeType> parseMimeTypes(String mimeTypes) {
275
276
.map (MimeTypeUtils ::parseMimeType ).collect (Collectors .toList ());
276
277
}
277
278
279
+
278
280
/**
279
281
* Tokenize the given comma-separated string of {@code MimeType} objects
280
282
* into a {@code List<String>}. Unlike simple tokenization by ",", this
@@ -330,7 +332,6 @@ public static String toString(Collection<? extends MimeType> mimeTypes) {
330
332
return builder .toString ();
331
333
}
332
334
333
-
334
335
/**
335
336
* Sorts the given list of {@code MimeType} objects by specificity.
336
337
* <p>Given two mime types:
@@ -399,17 +400,17 @@ public static String generateMultipartBoundaryString() {
399
400
return new String (generateMultipartBoundary (), StandardCharsets .US_ASCII );
400
401
}
401
402
403
+
402
404
/**
403
405
* Simple Least Recently Used cache, bounded by the maximum size given
404
406
* to the class constructor.
405
- * This implementation is backed by a {@code ConcurrentHashMap} for storing
406
- * the cached values and a {@code ConcurrentLinkedQueue} for ordering
407
- * the keys and choosing the least recently used key when the cache is at
408
- * full capacity.
409
- * @param <K> the type of the key used for caching
407
+ * <p>This implementation is backed by a {@code ConcurrentHashMap} for storing
408
+ * the cached values and a {@code ConcurrentLinkedQueue} for ordering the keys
409
+ * and choosing the least recently used key when the cache is at full capacity.
410
+ * @param <K> the type of the key used for caching
410
411
* @param <V> the type of the cached values
411
412
*/
412
- static class ConcurrentLRUCache <K , V > {
413
+ private static class ConcurrentLruCache <K , V > {
413
414
414
415
private final int maxSize ;
415
416
@@ -421,14 +422,14 @@ static class ConcurrentLRUCache<K, V> {
421
422
422
423
private final Function <K , V > generator ;
423
424
424
- ConcurrentLRUCache (int maxSize , Function <K , V > generator ) {
425
+ public ConcurrentLruCache (int maxSize , Function <K , V > generator ) {
425
426
Assert .isTrue (maxSize > 0 , "LRU max size should be positive" );
426
427
Assert .notNull (generator , "Generator function should not be null" );
427
428
this .maxSize = maxSize ;
428
429
this .generator = generator ;
429
430
}
430
431
431
- V get (K key ) {
432
+ public V get (K key ) {
432
433
this .lock .readLock ().lock ();
433
434
try {
434
435
if (this .queue .remove (key )) {
@@ -443,7 +444,9 @@ V get(K key) {
443
444
try {
444
445
if (this .queue .size () == this .maxSize ) {
445
446
K leastUsed = this .queue .poll ();
446
- this .cache .remove (leastUsed );
447
+ if (leastUsed != null ) {
448
+ this .cache .remove (leastUsed );
449
+ }
447
450
}
448
451
V value = this .generator .apply (key );
449
452
this .queue .add (key );
@@ -454,7 +457,6 @@ V get(K key) {
454
457
this .lock .writeLock ().unlock ();
455
458
}
456
459
}
457
-
458
460
}
459
461
460
462
}
0 commit comments