diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index a81f6c3818e..b811e1ab613 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -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) */ diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java index 1bc9e1b934e..627704e49fd 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java @@ -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. diff --git a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java index 294a3e3726b..f634724625f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java @@ -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. */ diff --git a/spring-core/src/main/java/org/springframework/core/io/InputStreamSource.java b/spring-core/src/main/java/org/springframework/core/io/InputStreamSource.java index f31e6ef9a25..282ebb1eca7 100644 --- a/spring-core/src/main/java/org/springframework/core/io/InputStreamSource.java +++ b/spring-core/src/main/java/org/springframework/core/io/InputStreamSource.java @@ -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; diff --git a/spring-core/src/main/java/org/springframework/core/io/PathResource.java b/spring-core/src/main/java/org/springframework/core/io/PathResource.java index 649cf5f7c47..1246e177c84 100644 --- a/spring-core/src/main/java/org/springframework/core/io/PathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/PathResource.java @@ -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"); } } diff --git a/spring-core/src/main/java/org/springframework/core/io/Resource.java b/spring-core/src/main/java/org/springframework/core/io/Resource.java index e3fc2a4e59d..2b6a2bf580a 100644 --- a/spring-core/src/main/java/org/springframework/core/io/Resource.java +++ b/spring-core/src/main/java/org/springframework/core/io/Resource.java @@ -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. *

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()}. *

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. *

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. + *

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; diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java index 41aa4a03b48..19b33282ac2 100644 --- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java @@ -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. diff --git a/spring-core/src/main/java/org/springframework/core/io/WritableResource.java b/spring-core/src/main/java/org/springframework/core/io/WritableResource.java index 72d4fe34ed3..780a419d0a2 100644 --- a/spring-core/src/main/java/org/springframework/core/io/WritableResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/WritableResource.java @@ -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()}. *

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, diff --git a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java index c32096882f3..e5be1cd49f7 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java @@ -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 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 diff --git a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java index 082fade93ad..0f37194c056 100644 --- a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java @@ -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). diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java index 6a3ec5b780a..e731edb319b 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java @@ -75,10 +75,10 @@ public class CollectionToCollectionConverterTests { conversionService.addConverterFactory(new StringToNumberConverterFactory()); assertTrue(conversionService.canConvert(sourceType, targetType)); @SuppressWarnings("unchecked") - List result = (List) conversionService.convert(list, sourceType, targetType); + List result = (List) 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; diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java index 6f668bda022..09c1465d097 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/PathExtensionContentTypeResolver.java @@ -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 = 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; diff --git a/spring-web/src/main/java/org/springframework/http/MediaType.java b/spring-web/src/main/java/org/springframework/http/MediaType.java index e243a5eb759..02dd7bc9029 100644 --- a/spring-web/src/main/java/org/springframework/http/MediaType.java +++ b/spring-web/src/main/java/org/springframework/http/MediaType.java @@ -43,8 +43,7 @@ import org.springframework.util.comparator.CompoundComparator; * @author Rossen Stoyanchev * @author Sebastien Deleuze * @since 3.0 - * @see HTTP 1.1: Semantics - * and Content, section 3.1.1.1 + * @see HTTP 1.1: Semantics and Content, section 3.1.1.1 */ 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 toMediaTypes(List mimeTypes) { - return mimeTypes.stream().map(MediaType::toMediaType).collect(Collectors.toList()); + public static List asMediaTypes(List 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()); } diff --git a/spring-web/src/main/java/org/springframework/http/MediaTypeFactory.java b/spring-web/src/main/java/org/springframework/http/MediaTypeFactory.java new file mode 100644 index 00000000000..d7752948ffa --- /dev/null +++ b/spring-web/src/main/java/org/springframework/http/MediaTypeFactory.java @@ -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. + * + *

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); + } + +} diff --git a/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java index 93bd3a3a2aa..5e7a321d8b9 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java @@ -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 implements HttpMessageReader { */ public DecoderHttpMessageReader(Decoder decoder) { this.decoder = decoder; - this.readableMediaTypes = decoder != null ? - MediaType.toMediaTypes(decoder.getDecodableMimeTypes()) : - Collections.emptyList(); + this.readableMediaTypes = (decoder != null ? + MediaType.asMediaTypes(decoder.getDecodableMimeTypes()) : Collections.emptyList()); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/reactive/EncoderHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/converter/reactive/EncoderHttpMessageWriter.java index 5b2213dbf51..77762843fea 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/reactive/EncoderHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/reactive/EncoderHttpMessageWriter.java @@ -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 implements HttpMessageWriter { */ public EncoderHttpMessageWriter(Encoder encoder) { this.encoder = encoder; - this.writableMediaTypes = encoder != null ? - MediaType.toMediaTypes(encoder.getEncodableMimeTypes()) : - Collections.emptyList(); + this.writableMediaTypes = (encoder != null ? + MediaType.asMediaTypes(encoder.getEncodableMimeTypes()) : Collections.emptyList()); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/reactive/ResourceHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/converter/reactive/ResourceHttpMessageWriter.java index 0ff9a62bc2e..f1b9db49ad0 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/reactive/ResourceHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/reactive/ResourceHttpMessageWriter.java @@ -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 { 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 writeContent(Resource resource, ResolvableType type, - MediaType contentType, ReactiveHttpOutputMessage outputMessage) { - + private Mono writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage) { if (outputMessage instanceof ZeroCopyHttpOutputMessage) { Optional file = getFile(resource); if (file.isPresent()) { @@ -119,11 +114,11 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter 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 } } diff --git a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java index 0a042f4384a..81d3fd1e5e2 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java @@ -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); - } - } - } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResource.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResource.java index a05b782f8cc..916a4c11949 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResource.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResource.java @@ -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. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/GzipResourceResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/GzipResourceResolver.java index 4c457db2a89..4187758514c 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/GzipResourceResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/GzipResourceResolver.java @@ -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(); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java index c3c6557c347..5f897f7f9d4 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java @@ -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();