Skip to content

Commit f0a43e5

Browse files
poutsmarstoyanchev
authored andcommitted
Drop JAF dependency from MediaTypeFactory
This commit drops the Java Activation Framework dependency from the MediaTypeFactory, in favor of parsing our own `mime.types` file, which was obtained from Apache HTTPD. Issue: SPR-14908
1 parent 6f075c9 commit f0a43e5

File tree

3 files changed

+1961
-33
lines changed

3 files changed

+1961
-33
lines changed
Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,62 +16,88 @@
1616

1717
package org.springframework.http;
1818

19+
import java.io.BufferedReader;
1920
import java.io.IOException;
2021
import java.io.InputStream;
21-
import javax.activation.FileTypeMap;
22-
import javax.activation.MimetypesFileTypeMap;
22+
import java.io.InputStreamReader;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.Collections;
25+
import java.util.List;
26+
import java.util.Locale;
27+
import java.util.Optional;
2328

24-
import org.springframework.core.io.ClassPathResource;
2529
import org.springframework.core.io.Resource;
30+
import org.springframework.util.LinkedMultiValueMap;
31+
import org.springframework.util.MultiValueMap;
2632
import org.springframework.util.StringUtils;
2733

2834
/**
2935
* A factory delegate for resolving {@link MediaType} objects
3036
* from {@link Resource} handles or filenames.
3137
*
32-
* <p>This implementation is based on the Java Activation Framework,
33-
* sharing the MIME type definitions with Spring's JavaMail support.
34-
* However, JAF is an implementation detail and not leaking out.
35-
*
3638
* @author Juergen Hoeller
39+
* @author Arjen Poutsma
3740
* @since 5.0
3841
*/
3942
public class MediaTypeFactory {
4043

41-
private static final FileTypeMap fileTypeMap;
44+
private static final String MIME_TYPES_FILE_NAME = "/org/springframework/http/mime.types";
45+
46+
private static final MultiValueMap<String, MediaType> fileExtensionToMediaTypes;
4247

4348
static {
44-
fileTypeMap = loadFileTypeMapFromContextSupportModule();
49+
fileExtensionToMediaTypes = parseMimeTypes();
4550
}
4651

52+
/**
53+
* Parse the {@code mime.types} file found in the resources. Format is:
54+
* <code>
55+
* # comments begin with a '#'<br>
56+
* # the format is &lt;mime type> &lt;space separated file extensions><br>
57+
* # for example:<br>
58+
* text/plain txt text<br>
59+
* # this would map file.txt and file.text to<br>
60+
* # the mime type "text/plain"<br>
61+
* </code>
62+
* @return a multi-value map, mapping media types to file extensions.
63+
*/
64+
private static MultiValueMap<String, MediaType> parseMimeTypes() {
65+
InputStream is = null;
66+
try {
67+
is = MediaTypeFactory.class.getResourceAsStream(MIME_TYPES_FILE_NAME);
68+
BufferedReader reader =
69+
new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII));
4770

48-
private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
49-
// See if we can find the extended mime.types from the context-support module...
50-
Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
51-
if (mappingLocation.exists()) {
52-
InputStream inputStream = null;
53-
try {
54-
inputStream = mappingLocation.getInputStream();
55-
return new MimetypesFileTypeMap(inputStream);
56-
}
57-
catch (IOException ex) {
58-
// ignore
71+
MultiValueMap<String, MediaType> result = new LinkedMultiValueMap<>();
72+
String line;
73+
while ((line = reader.readLine()) != null) {
74+
if (line.isEmpty() || line.charAt(0) == '#') {
75+
continue;
76+
}
77+
String[] tokens = StringUtils.tokenizeToStringArray(line, " \t\n\r\f");
78+
MediaType mediaType = MediaType.parseMediaType(tokens[0]);
79+
80+
for (int i = 1; i < tokens.length; i++) {
81+
String fileExtension = tokens[i].toLowerCase(Locale.ENGLISH);
82+
result.add(fileExtension, mediaType);
83+
}
5984
}
60-
finally {
61-
if (inputStream != null) {
62-
try {
63-
inputStream.close();
64-
}
65-
catch (IOException ex) {
66-
// ignore
67-
}
85+
return result;
86+
}
87+
catch (IOException ex) {
88+
throw new IllegalStateException("Could not load '" + MIME_TYPES_FILE_NAME + "'", ex);
89+
}
90+
finally {
91+
if (is != null) {
92+
try {
93+
is.close();
94+
}
95+
catch (IOException ignore) {
6896
}
6997
}
7098
}
71-
return FileTypeMap.getDefaultFileTypeMap();
7299
}
73100

74-
75101
/**
76102
* Determine a media type for the given resource, if possible.
77103
* @param resource the resource to introspect
@@ -88,8 +114,20 @@ public static MediaType getMediaType(Resource resource) {
88114
* @return the corresponding media type, or {@code null} if none found
89115
*/
90116
public static MediaType getMediaType(String filename) {
91-
String mediaType = fileTypeMap.getContentType(filename);
92-
return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
117+
List<MediaType> mediaTypes = getMediaTypes(filename);
118+
return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);
119+
}
120+
121+
/**
122+
* Determine the media types for the given file name, if possible.
123+
* @param filename the file name plus extension
124+
* @return the corresponding media types, or an empty list if none found
125+
*/
126+
public static List<MediaType> getMediaTypes(String filename) {
127+
return Optional.ofNullable(StringUtils.getFilenameExtension(filename))
128+
.map(s -> s.toLowerCase(Locale.ENGLISH))
129+
.map(fileExtensionToMediaTypes::get)
130+
.orElse(Collections.emptyList());
93131
}
94132

95133
}

0 commit comments

Comments
 (0)