diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java
index 2223f789ae..4bd6ef58e9 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -64,24 +64,24 @@ public final class ParserContext {
}
- public final XmlReaderContext getReaderContext() {
+ public XmlReaderContext getReaderContext() {
return this.readerContext;
}
- public final BeanDefinitionRegistry getRegistry() {
+ public BeanDefinitionRegistry getRegistry() {
return this.readerContext.getRegistry();
}
- public final BeanDefinitionParserDelegate getDelegate() {
+ public BeanDefinitionParserDelegate getDelegate() {
return this.delegate;
}
@Nullable
- public final BeanDefinition getContainingBeanDefinition() {
+ public BeanDefinition getContainingBeanDefinition() {
return this.containingBeanDefinition;
}
- public final boolean isNested() {
+ public boolean isNested() {
return (this.containingBeanDefinition != null);
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
index 5be6cb914b..b9b684ce74 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -16,6 +16,7 @@
package org.springframework.context.annotation;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
@@ -424,40 +425,38 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
- if (resource.isReadable()) {
- try {
- MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
- if (isCandidateComponent(metadataReader)) {
- ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
- sbd.setSource(resource);
- if (isCandidateComponent(sbd)) {
- if (debugEnabled) {
- logger.debug("Identified candidate component class: " + resource);
- }
- candidates.add(sbd);
- }
- else {
- if (debugEnabled) {
- logger.debug("Ignored because not a concrete top-level class: " + resource);
- }
+ try {
+ MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
+ if (isCandidateComponent(metadataReader)) {
+ ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
+ sbd.setSource(resource);
+ if (isCandidateComponent(sbd)) {
+ if (debugEnabled) {
+ logger.debug("Identified candidate component class: " + resource);
}
+ candidates.add(sbd);
}
else {
- if (traceEnabled) {
- logger.trace("Ignored because not matching any filter: " + resource);
+ if (debugEnabled) {
+ logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
- catch (Throwable ex) {
- throw new BeanDefinitionStoreException(
- "Failed to read candidate component class: " + resource, ex);
+ else {
+ if (traceEnabled) {
+ logger.trace("Ignored because not matching any filter: " + resource);
+ }
}
}
- else {
+ catch (FileNotFoundException ex) {
if (traceEnabled) {
- logger.trace("Ignored because not readable: " + resource);
+ logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
}
}
+ catch (Throwable ex) {
+ throw new BeanDefinitionStoreException(
+ "Failed to read candidate component class: " + resource, ex);
+ }
}
}
catch (IOException ex) {
diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
index 3af71481c2..6581cdd61f 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -105,11 +105,11 @@ public class CronTrigger implements Trigger {
}
}
else {
- date = new Date();
+ date = new Date(triggerContext.getClock().millis());
}
ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), this.zoneId);
ZonedDateTime next = this.expression.next(dateTime);
- return next != null ? Date.from(next.toInstant()) : null;
+ return (next != null ? Date.from(next.toInstant()) : null);
}
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 958b3babce..ac9ea29a5d 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-2018 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -88,7 +88,15 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
@Override
public boolean isReadable() {
try {
- URL url = getURL();
+ return checkReadable(getURL());
+ }
+ catch (IOException ex) {
+ return false;
+ }
+ }
+
+ boolean checkReadable(URL url) {
+ try {
if (ResourceUtils.isFileURL(url)) {
// Proceed with file system resolution
File file = getFile();
diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java
index 6374f2768b..f99adce06c 100644
--- a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java
@@ -142,6 +142,18 @@ public class ClassPathResource extends AbstractFileResolvingResource {
return (resolveURL() != null);
}
+ /**
+ * This implementation checks for the resolution of a resource URL upfront,
+ * then proceeding with {@link AbstractFileResolvingResource}'s length check.
+ * @see java.lang.ClassLoader#getResource(String)
+ * @see java.lang.Class#getResource(String)
+ */
+ @Override
+ public boolean isReadable() {
+ URL url = resolveURL();
+ return (url != null && checkReadable(url));
+ }
+
/**
* Resolves a URL for the underlying class path resource.
* @return the resolved URL, or {@code null} if not resolvable
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 b769895ece..8d72c9cd8b 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-2017 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -48,8 +48,9 @@ public interface InputStreamSource {
* creating mail attachments. For such a use case, it is required
* that each {@code getInputStream()} call returns a fresh stream.
* @return the input stream for the underlying resource (must not be {@code null})
- * @throws java.io.FileNotFoundException if the underlying resource doesn't exist
+ * @throws java.io.FileNotFoundException if the underlying resource does not exist
* @throws IOException if the content stream could not be opened
+ * @see Resource#isReadable()
*/
InputStream getInputStream() throws IOException;
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java
index 0ddf08bb86..e2346f1088 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java
@@ -16,6 +16,7 @@
package org.springframework.orm.hibernate5;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -319,7 +320,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
- if (resource.isReadable()) {
+ try {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (matchesEntityTypeFilter(reader, readerFactory)) {
@@ -332,6 +333,9 @@ public class LocalSessionFactoryBuilder extends Configuration {
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
}
}
+ catch (FileNotFoundException ex) {
+ // Ignore non-readable resource
+ }
}
}
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java
index 7d51f1bfa2..af39d7ea12 100644
--- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java
+++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java
@@ -16,6 +16,7 @@
package org.springframework.orm.jpa.persistenceunit;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
@@ -583,7 +584,7 @@ public class DefaultPersistenceUnitManager
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
- if (resource.isReadable()) {
+ try {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (matchesFilter(reader, readerFactory)) {
@@ -600,6 +601,9 @@ public class DefaultPersistenceUnitManager
className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
}
}
+ catch (FileNotFoundException ex) {
+ // Ignore non-readable resource
+ }
}
}
catch (IOException ex) {
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java
index e17cca7906..60caf7c19e 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -72,7 +72,7 @@ class PathResourceLookupFunction implements Function resolvers = handler.getResourceResolvers();
@@ -241,15 +244,10 @@ public class ResourceHandlerRegistryTests {
}
@Test
- void lastModifiedDisabled() {
+ public void lastModifiedDisabled() {
this.registration.setUseLastModified(false);
ResourceHttpRequestHandler handler = getHandler("/resources/**");
assertThat(handler.isUseLastModified()).isFalse();
}
- private ResourceHttpRequestHandler getHandler(String pathPattern) {
- SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
- return (ResourceHttpRequestHandler) hm.getUrlMap().get(pathPattern);
- }
-
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
index 76c19d77a0..04895cfcc8 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
@@ -289,7 +289,6 @@ public class ResourceHttpRequestHandlerTests {
@Test // SPR-14368
public void getResourceWithMediaTypeResolvedThroughServletContext() throws Exception {
-
MockServletContext servletContext = new MockServletContext() {
@Override
public String getMimeType(String filePath) {
@@ -311,7 +310,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(this.response.getContentAsString()).isEqualTo("h1 { color:red; }");
}
- @Test // gh-27538
+ @Test // gh-27538
public void filterNonExistingLocations() throws Exception {
List inputLocations = Arrays.asList(
new ClassPathResource("test/", getClass()),
@@ -331,7 +330,6 @@ public class ResourceHttpRequestHandlerTests {
@Test
public void testInvalidPath() throws Exception {
-
// Use mock ResourceResolver: i.e. we're only testing upfront validations...
Resource resource = mock(Resource.class);
@@ -677,7 +675,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(ranges[11]).isEqualTo("t.");
}
- @Test // gh-25976
+ @Test // gh-25976
public void partialContentByteRangeWithEncodedResource(GzipSupport.GzippedFiles gzippedFiles) throws Exception {
String path = "js/foo.js";
gzippedFiles.create(path);
@@ -706,7 +704,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(this.response.getHeaderValues("Vary")).containsExactly("Accept-Encoding");
}
- @Test // gh-25976
+ @Test // gh-25976
public void partialContentWithHttpHead() throws Exception {
this.request.setMethod("HEAD");
this.request.addHeader("Range", "bytes=0-1");