Resource.isFile() and JAF MediaTypeFactory
Issue: SPR-14484
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,6 +38,20 @@ import org.springframework.util.ResourceUtils;
|
||||
*/
|
||||
public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
try {
|
||||
URL url = getURL();
|
||||
if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
|
||||
return VfsResourceDelegate.getResource(url).isFile();
|
||||
}
|
||||
return ResourceUtils.URL_PROTOCOL_FILE.equals(url.getProtocol());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a File reference for the underlying class path
|
||||
* resource, provided that it refers to a file in the file system.
|
||||
@@ -72,7 +86,25 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a File reference for the underlying class path
|
||||
* This implementation returns a File reference for the given URI-identified
|
||||
* resource, provided that it refers to a file in the file system.
|
||||
* @since 5.0
|
||||
* @see #getFile(URI)
|
||||
*/
|
||||
protected boolean isFile(URI uri) {
|
||||
try {
|
||||
if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
|
||||
return VfsResourceDelegate.getResource(uri).isFile();
|
||||
}
|
||||
return ResourceUtils.URL_PROTOCOL_FILE.equals(uri.getScheme());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a File reference for the given URI-identified
|
||||
* resource, provided that it refers to a file in the file system.
|
||||
* @see org.springframework.util.ResourceUtils#getFile(java.net.URI, String)
|
||||
*/
|
||||
|
||||
@@ -81,6 +81,14 @@ public abstract class AbstractResource implements Resource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation always returns {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation throws a FileNotFoundException, assuming
|
||||
* that the resource cannot be resolved to a URL.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -85,7 +85,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation returns whether the underlying file exists.
|
||||
* @see java.io.File#exists()
|
||||
@@ -153,6 +152,14 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
return this.file.toURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation always indicates a file.
|
||||
*/
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the underlying File reference.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,7 +49,6 @@ public interface InputStreamSource {
|
||||
* that each {@code getInputStream()} call returns a fresh stream.
|
||||
* @return the input stream for the underlying resource (must not be {@code null})
|
||||
* @throws IOException if the stream could not be opened
|
||||
* @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource)
|
||||
*/
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
|
||||
@@ -171,6 +171,14 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
return this.path.toUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation always indicates a file.
|
||||
*/
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the underlying File reference.
|
||||
*/
|
||||
@@ -180,8 +188,8 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
return this.path.toFile();
|
||||
}
|
||||
catch (UnsupportedOperationException ex) {
|
||||
// only Paths on the default file system can be converted to a File
|
||||
// do exception translation for cases where conversion is not possible
|
||||
// Only paths on the default file system can be converted to a File:
|
||||
// Do exception translation for cases where conversion is not possible.
|
||||
throw new FileNotFoundException(this.path + " cannot be resolved to " + "absolute file path");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ import java.net.URL;
|
||||
public interface Resource extends InputStreamSource {
|
||||
|
||||
/**
|
||||
* Return whether this resource actually exists in physical form.
|
||||
* Determine whether this resource actually exists in physical form.
|
||||
* <p>This method performs a definitive existence check, whereas the
|
||||
* existence of a {@code Resource} handle only guarantees a
|
||||
* valid descriptor handle.
|
||||
@@ -55,23 +55,39 @@ public interface Resource extends InputStreamSource {
|
||||
boolean exists();
|
||||
|
||||
/**
|
||||
* Return whether the contents of this resource can be read,
|
||||
* e.g. via {@link #getInputStream()} or {@link #getFile()}.
|
||||
* Indicate whether the contents of this resource can be read via
|
||||
* {@link #getInputStream()}.
|
||||
* <p>Will be {@code true} for typical resource descriptors;
|
||||
* note that actual content reading may still fail when attempted.
|
||||
* However, a value of {@code false} is a definitive indication
|
||||
* that the resource content cannot be read.
|
||||
* @see #getInputStream()
|
||||
*/
|
||||
boolean isReadable();
|
||||
default boolean isReadable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this resource represents a handle with an open
|
||||
* stream. If true, the InputStream cannot be read multiple times,
|
||||
* Indicate whether this resource represents a handle with an open stream.
|
||||
* If {@code true}, the InputStream cannot be read multiple times,
|
||||
* and must be read and closed to avoid resource leaks.
|
||||
* <p>Will be {@code false} for typical resource descriptors.
|
||||
*/
|
||||
boolean isOpen();
|
||||
default boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this resource represents a file in a file system.
|
||||
* A value of {@code true} strongly suggests (but does not guarantee)
|
||||
* that a {@link #getFile()} call will succeed.
|
||||
* <p>This is conservatively {@code false} by default.
|
||||
* @since 5.0
|
||||
* @see #getFile()
|
||||
*/
|
||||
default boolean isFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a URL handle for this resource.
|
||||
@@ -84,6 +100,7 @@ public interface Resource extends InputStreamSource {
|
||||
* Return a URI handle for this resource.
|
||||
* @throws IOException if the resource cannot be resolved as URI,
|
||||
* i.e. if the resource is not available as descriptor
|
||||
* @since 2.5
|
||||
*/
|
||||
URI getURI() throws IOException;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,6 +61,7 @@ public class UrlResource extends AbstractFileResolvingResource {
|
||||
* Create a new {@code UrlResource} based on the given URI object.
|
||||
* @param uri a URI
|
||||
* @throws MalformedURLException if the given URL path is not valid
|
||||
* @since 2.5
|
||||
*/
|
||||
public UrlResource(URI uri) throws MalformedURLException {
|
||||
Assert.notNull(uri, "URI must not be null");
|
||||
@@ -198,6 +199,16 @@ public class UrlResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
if (this.uri != null) {
|
||||
return super.isFile(this.uri);
|
||||
}
|
||||
else {
|
||||
return super.isFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a File reference for the underlying URL/URI,
|
||||
* provided that it refers to a file in the file system.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,8 +30,8 @@ import java.io.OutputStream;
|
||||
public interface WritableResource extends Resource {
|
||||
|
||||
/**
|
||||
* Return whether the contents of this resource can be modified,
|
||||
* e.g. via {@link #getOutputStream()} or {@link #getFile()}.
|
||||
* Indicate whether the contents of this resource can be written
|
||||
* via {@link #getOutputStream()}.
|
||||
* <p>Will be {@code true} for typical resource descriptors;
|
||||
* note that actual content writing may still fail when attempted.
|
||||
* However, a value of {@code false} is a definitive indication
|
||||
@@ -39,7 +39,9 @@ public interface WritableResource extends Resource {
|
||||
* @see #getOutputStream()
|
||||
* @see #isReadable()
|
||||
*/
|
||||
boolean isWritable();
|
||||
default boolean isWritable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an {@link OutputStream} for the underlying resource,
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
@@ -28,13 +26,8 @@ import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.MimeType.SpecificityComparator;
|
||||
|
||||
/**
|
||||
@@ -56,12 +49,6 @@ public abstract class MimeTypeUtils {
|
||||
|
||||
private static Charset US_ASCII = Charset.forName("US-ASCII");
|
||||
|
||||
private static final FileTypeMap fileTypeMap;
|
||||
|
||||
static {
|
||||
fileTypeMap = initFileTypeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constant mime type that includes all media ranges (i.e. "*/*").
|
||||
*/
|
||||
@@ -220,31 +207,6 @@ public abstract class MimeTypeUtils {
|
||||
TEXT_XML = MimeType.valueOf(TEXT_XML_VALUE);
|
||||
}
|
||||
|
||||
private static FileTypeMap initFileTypeMap() {
|
||||
// See if we can find the extended mime.types from the context-support module...
|
||||
Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
|
||||
if (mappingLocation.exists()) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = mappingLocation.getInputStream();
|
||||
return new MimetypesFileTypeMap(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FileTypeMap.getDefaultFileTypeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given String into a single {@code MimeType}.
|
||||
@@ -322,23 +284,6 @@ public abstract class MimeTypeUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code MimeType} of the given file name, using the Java Activation
|
||||
* Framework.
|
||||
* @param filename the filename whose mime type is to be found
|
||||
* @return the mime type, if any
|
||||
* @since 5.0
|
||||
*/
|
||||
public static Optional<MimeType> getMimeType(String filename) {
|
||||
if (filename != null) {
|
||||
String mimeType = fileTypeMap.getContentType(filename);
|
||||
if (StringUtils.hasText(mimeType)) {
|
||||
return Optional.of(parseMimeType(mimeType));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the given list of {@code MimeType} objects.
|
||||
* @param mimeTypes the string to parse
|
||||
|
||||
@@ -18,18 +18,12 @@ package org.springframework.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.DescriptiveResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Utility methods for resolving resource locations to files in the
|
||||
* file system. Mainly for internal use within the framework.
|
||||
@@ -235,6 +229,7 @@ public abstract class ResourceUtils {
|
||||
* @return a corresponding File object
|
||||
* @throws FileNotFoundException if the URL cannot be resolved to
|
||||
* a file in the file system
|
||||
* @since 2.5
|
||||
*/
|
||||
public static File getFile(URI resourceUri) throws FileNotFoundException {
|
||||
return getFile(resourceUri, "URI");
|
||||
@@ -249,6 +244,7 @@ public abstract class ResourceUtils {
|
||||
* @return a corresponding File object
|
||||
* @throws FileNotFoundException if the URL cannot be resolved to
|
||||
* a file in the file system
|
||||
* @since 2.5
|
||||
*/
|
||||
public static File getFile(URI resourceUri, String description) throws FileNotFoundException {
|
||||
Assert.notNull(resourceUri, "Resource URI must not be null");
|
||||
@@ -296,32 +292,6 @@ public abstract class ResourceUtils {
|
||||
url.getPath().toLowerCase().endsWith(JAR_FILE_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the given resource has a file, so that {@link
|
||||
* Resource#getFile()}
|
||||
* can be called without an {@link java.io.IOException}.
|
||||
* @param resource the resource to check
|
||||
* @return {@code true} if the given resource has a file; {@code false} otherwise
|
||||
* @since 5.0
|
||||
*/
|
||||
public static boolean hasFile(Resource resource) {
|
||||
Assert.notNull(resource, "'resource' must not be null");
|
||||
|
||||
// the following Resource implementations do not support getURI/getFile
|
||||
if (resource instanceof ByteArrayResource ||
|
||||
resource instanceof DescriptiveResource ||
|
||||
resource instanceof InputStreamResource) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
URI resourceUri = resource.getURI();
|
||||
return URL_PROTOCOL_FILE.equals(resourceUri.getScheme());
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the URL for the actual jar file from the given URL
|
||||
* (which may point to a resource in a jar file or to a jar file itself).
|
||||
|
||||
@@ -75,10 +75,10 @@ public class CollectionToCollectionConverterTests {
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> result = (List<String>) conversionService.convert(list, sourceType, targetType);
|
||||
List<Integer> result = (List<Integer>) conversionService.convert(list, sourceType, targetType);
|
||||
assertFalse(list.equals(result));
|
||||
assertEquals(9, result.get(0));
|
||||
assertEquals(37, result.get(1));
|
||||
assertEquals(9, result.get(0).intValue());
|
||||
assertEquals(37, result.get(1).intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -303,6 +303,11 @@ public class CollectionToCollectionConverterTests {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getURL() throws IOException {
|
||||
return null;
|
||||
|
||||
@@ -18,13 +18,11 @@ package org.springframework.web.reactive.accept;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
@@ -94,8 +92,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
|
||||
@Override
|
||||
protected MediaType handleNoMatch(String key) throws NotAcceptableStatusException {
|
||||
if (this.useJaf) {
|
||||
Optional<MimeType> mimeType = MimeTypeUtils.getMimeType("file." + key);
|
||||
MediaType mediaType = mimeType.map(MediaType::toMediaType).orElse(null);
|
||||
MediaType mediaType = MediaTypeFactory.getMediaType("file." + key);
|
||||
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
|
||||
return mediaType;
|
||||
}
|
||||
@@ -111,10 +108,10 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
|
||||
* determine the media type for a given {@link Resource}. First it checks
|
||||
* the explicitly registered mappings and then falls back on JAF.
|
||||
* @param resource the resource
|
||||
* @return the MediaType for the extension or {@code null}.
|
||||
* @return the MediaType for the extension, or {@code null} if none determined
|
||||
*/
|
||||
public MediaType resolveMediaTypeForResource(Resource resource) {
|
||||
Assert.notNull(resource);
|
||||
Assert.notNull(resource, "Resource must not be null");
|
||||
MediaType mediaType = null;
|
||||
String filename = resource.getFilename();
|
||||
String extension = StringUtils.getFilenameExtension(filename);
|
||||
@@ -122,7 +119,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
|
||||
mediaType = getMediaType(extension);
|
||||
}
|
||||
if (mediaType == null) {
|
||||
mediaType = MimeTypeUtils.getMimeType(filename).map(MediaType::toMediaType).orElse(null);
|
||||
mediaType = MediaTypeFactory.getMediaType(filename);
|
||||
}
|
||||
if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
|
||||
mediaType = null;
|
||||
|
||||
@@ -43,8 +43,7 @@ import org.springframework.util.comparator.CompoundComparator;
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 3.0
|
||||
* @see <a href="http://tools.ietf.org/html/rfc7231#section-3.1.1.1">HTTP 1.1: Semantics
|
||||
* and Content, section 3.1.1.1</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc7231#section-3.1.1.1">HTTP 1.1: Semantics and Content, section 3.1.1.1</a>
|
||||
*/
|
||||
public class MediaType extends MimeType implements Serializable {
|
||||
|
||||
@@ -450,15 +449,18 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* Re-create the given mime types as media types.
|
||||
* @since 5.0
|
||||
*/
|
||||
public static List<MediaType> toMediaTypes(List<MimeType> mimeTypes) {
|
||||
return mimeTypes.stream().map(MediaType::toMediaType).collect(Collectors.toList());
|
||||
public static List<MediaType> asMediaTypes(List<MimeType> mimeTypes) {
|
||||
return mimeTypes.stream().map(MediaType::asMediaType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-create the given mime type as a media type.
|
||||
* @since 5.0
|
||||
*/
|
||||
public static MediaType toMediaType(MimeType mimeType) {
|
||||
public static MediaType asMediaType(MimeType mimeType) {
|
||||
if (mimeType instanceof MediaType) {
|
||||
return (MediaType) mimeType;
|
||||
}
|
||||
return new MediaType(mimeType.getType(), mimeType.getSubtype(), mimeType.getParameters());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A factory delegate for resolving {@link MediaType} objects
|
||||
* from {@link Resource} handles or filenames.
|
||||
*
|
||||
* <p>This implementation is based on the Java Activation Framework,
|
||||
* sharing the MIME type definitions with Spring's JavaMail support.
|
||||
* However, JAF is an implementation detail and not leaking out.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.0
|
||||
*/
|
||||
public class MediaTypeFactory {
|
||||
|
||||
private static final FileTypeMap fileTypeMap;
|
||||
|
||||
static {
|
||||
fileTypeMap = loadFileTypeMapFromContextSupportModule();
|
||||
}
|
||||
|
||||
|
||||
private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
|
||||
// See if we can find the extended mime.types from the context-support module...
|
||||
Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
|
||||
if (mappingLocation.exists()) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = mappingLocation.getInputStream();
|
||||
return new MimetypesFileTypeMap(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FileTypeMap.getDefaultFileTypeMap();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine a media type for the given resource, if possible.
|
||||
* @param resource the resource to introspect
|
||||
* @return the corresponding media type, or {@code null} if none found
|
||||
*/
|
||||
public static MediaType getMediaType(Resource resource) {
|
||||
String filename = resource.getFilename();
|
||||
return (filename != null ? getMediaType(filename) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a media type for the given file name, if possible.
|
||||
* @param filename the file name plus extension
|
||||
* @return the corresponding media type, or {@code null} if none found
|
||||
*/
|
||||
public static MediaType getMediaType(String filename) {
|
||||
String mediaType = fileTypeMap.getContentType(filename);
|
||||
return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,19 +19,16 @@ package org.springframework.http.converter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link HttpMessageConverter} that can read and write {@link Resource Resources}
|
||||
@@ -82,7 +79,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
|
||||
@Override
|
||||
protected MediaType getDefaultContentType(Resource resource) {
|
||||
if (jafPresent) {
|
||||
return ActivationMediaTypeFactory.getMediaType(resource);
|
||||
return MediaTypeFactory.getMediaType(resource);
|
||||
}
|
||||
else {
|
||||
return MediaType.APPLICATION_OCTET_STREAM;
|
||||
@@ -131,54 +128,4 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard-coded JAF dependency.
|
||||
*/
|
||||
private static class ActivationMediaTypeFactory {
|
||||
|
||||
private static final FileTypeMap fileTypeMap;
|
||||
|
||||
static {
|
||||
fileTypeMap = loadFileTypeMapFromContextSupportModule();
|
||||
}
|
||||
|
||||
private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
|
||||
// See if we can find the extended mime.types from the context-support module...
|
||||
Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
|
||||
if (mappingLocation.exists()) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = mappingLocation.getInputStream();
|
||||
return new MimetypesFileTypeMap(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FileTypeMap.getDefaultFileTypeMap();
|
||||
}
|
||||
|
||||
public static MediaType getMediaType(Resource resource) {
|
||||
String filename = resource.getFilename();
|
||||
if (filename != null) {
|
||||
String mediaType = fileTypeMap.getContentType(filename);
|
||||
if (StringUtils.hasText(mediaType)) {
|
||||
return MediaType.parseMediaType(mediaType);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpInputMessage;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link HttpMessageReader} interface that delegates to
|
||||
* a {@link Decoder}.
|
||||
* Implementation of the {@link HttpMessageReader} interface that delegates
|
||||
* to a {@link Decoder}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
@@ -49,9 +49,8 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
*/
|
||||
public DecoderHttpMessageReader(Decoder<T> decoder) {
|
||||
this.decoder = decoder;
|
||||
this.readableMediaTypes = decoder != null ?
|
||||
MediaType.toMediaTypes(decoder.getDecodableMimeTypes()) :
|
||||
Collections.emptyList();
|
||||
this.readableMediaTypes = (decoder != null ?
|
||||
MediaType.asMediaTypes(decoder.getDecodableMimeTypes()) : Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link HttpMessageWriter} interface that delegates to
|
||||
* an {@link Encoder}.
|
||||
* Implementation of the {@link HttpMessageWriter} interface that delegates
|
||||
* to an {@link Encoder}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
@@ -53,9 +53,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
*/
|
||||
public EncoderHttpMessageWriter(Encoder<T> encoder) {
|
||||
this.encoder = encoder;
|
||||
this.writableMediaTypes = encoder != null ?
|
||||
MediaType.toMediaTypes(encoder.getEncodableMimeTypes()) :
|
||||
Collections.emptyList();
|
||||
this.writableMediaTypes = (encoder != null ?
|
||||
MediaType.asMediaTypes(encoder.getEncodableMimeTypes()) : Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,10 +31,9 @@ import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.ZeroCopyHttpOutputMessage;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link HttpMessageWriter} that can write
|
||||
@@ -67,8 +66,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
|
||||
concatMap(resource -> {
|
||||
HttpHeaders headers = outputMessage.getHeaders();
|
||||
addHeaders(headers, resource, contentType);
|
||||
|
||||
return writeContent(resource, type, contentType, outputMessage);
|
||||
return writeContent(resource, type, outputMessage);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -76,8 +74,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
|
||||
if (headers.getContentType() == null) {
|
||||
if (contentType == null || !contentType.isConcrete() ||
|
||||
MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
|
||||
contentType = MimeTypeUtils.getMimeType(resource.getFilename()).
|
||||
map(MediaType::toMediaType).
|
||||
contentType = Optional.ofNullable(MediaTypeFactory.getMediaType(resource)).
|
||||
orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
headers.setContentType(contentType);
|
||||
@@ -87,9 +84,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<Void> writeContent(Resource resource, ResolvableType type,
|
||||
MediaType contentType, ReactiveHttpOutputMessage outputMessage) {
|
||||
|
||||
private Mono<Void> writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage) {
|
||||
if (outputMessage instanceof ZeroCopyHttpOutputMessage) {
|
||||
Optional<File> file = getFile(resource);
|
||||
if (file.isPresent()) {
|
||||
@@ -119,11 +114,11 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
|
||||
}
|
||||
|
||||
private static Optional<File> getFile(Resource resource) {
|
||||
if (ResourceUtils.hasFile(resource)) {
|
||||
if (resource.isFile()) {
|
||||
try {
|
||||
return Optional.of(resource.getFile());
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
catch (IOException ex) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,16 @@
|
||||
|
||||
package org.springframework.web.accept;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -128,7 +124,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
if (this.useJaf && JAF_PRESENT) {
|
||||
MediaType mediaType = JafMediaTypeFactory.getMediaType("file." + extension);
|
||||
MediaType mediaType = MediaTypeFactory.getMediaType("file." + extension);
|
||||
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
|
||||
return mediaType;
|
||||
}
|
||||
@@ -157,7 +153,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
mediaType = lookupMediaType(extension);
|
||||
}
|
||||
if (mediaType == null && JAF_PRESENT) {
|
||||
mediaType = JafMediaTypeFactory.getMediaType(filename);
|
||||
mediaType = MediaTypeFactory.getMediaType(filename);
|
||||
}
|
||||
if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
|
||||
mediaType = null;
|
||||
@@ -165,56 +161,4 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard-coded dependency on JAF.
|
||||
*/
|
||||
private static class JafMediaTypeFactory {
|
||||
|
||||
private static final FileTypeMap fileTypeMap;
|
||||
|
||||
static {
|
||||
fileTypeMap = initFileTypeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find extended mime.types from the spring-context-support module.
|
||||
*/
|
||||
private static FileTypeMap initFileTypeMap() {
|
||||
Resource resource = new ClassPathResource("org/springframework/mail/javamail/mime.types");
|
||||
if (resource.exists()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loading JAF FileTypeMap from " + resource);
|
||||
}
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = resource.getInputStream();
|
||||
return new MimetypesFileTypeMap(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loading default Java Activation Framework FileTypeMap");
|
||||
}
|
||||
return FileTypeMap.getDefaultFileTypeMap();
|
||||
}
|
||||
|
||||
public static MediaType getMediaType(String filename) {
|
||||
String mediaType = fileTypeMap.getContentType(filename);
|
||||
return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -77,6 +77,7 @@ public class ServletContextResource extends AbstractFileResolvingResource implem
|
||||
this.path = pathToUse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the ServletContext for this resource.
|
||||
*/
|
||||
@@ -91,7 +92,6 @@ public class ServletContextResource extends AbstractFileResolvingResource implem
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation checks {@code ServletContext.getResource}.
|
||||
* @see javax.servlet.ServletContext#getResource(String)
|
||||
@@ -129,6 +129,22 @@ public class ServletContextResource extends AbstractFileResolvingResource implem
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
try {
|
||||
URL url = this.servletContext.getResource(this.path);
|
||||
if (url != null && ResourceUtils.isFileURL(url)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return (this.servletContext.getRealPath(this.path) != null);
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to {@code ServletContext.getResourceAsStream},
|
||||
* but throws a FileNotFoundException if no resource found.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,6 +103,11 @@ public class GzipResourceResolver extends AbstractResourceResolver {
|
||||
return this.gzipped.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return this.gzipped.isFile();
|
||||
}
|
||||
|
||||
public URL getURL() throws IOException {
|
||||
return this.gzipped.getURL();
|
||||
}
|
||||
|
||||
@@ -264,6 +264,11 @@ public class VersionResourceResolver extends AbstractResourceResolver {
|
||||
return this.original.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return this.original.isFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getURL() throws IOException {
|
||||
return this.original.getURL();
|
||||
|
||||
Reference in New Issue
Block a user