Merge branch '5.3.x'

This commit is contained in:
Juergen Hoeller 2021-10-12 15:19:40 +02:00
commit da457abd5b
12 changed files with 88 additions and 64 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; return this.readerContext;
} }
public final BeanDefinitionRegistry getRegistry() { public BeanDefinitionRegistry getRegistry() {
return this.readerContext.getRegistry(); return this.readerContext.getRegistry();
} }
public final BeanDefinitionParserDelegate getDelegate() { public BeanDefinitionParserDelegate getDelegate() {
return this.delegate; return this.delegate;
} }
@Nullable @Nullable
public final BeanDefinition getContainingBeanDefinition() { public BeanDefinition getContainingBeanDefinition() {
return this.containingBeanDefinition; return this.containingBeanDefinition;
} }
public final boolean isNested() { public boolean isNested() {
return (this.containingBeanDefinition != null); return (this.containingBeanDefinition != null);
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.context.annotation; package org.springframework.context.annotation;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.ArrayList; import java.util.ArrayList;
@ -424,40 +425,38 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
if (traceEnabled) { if (traceEnabled) {
logger.trace("Scanning " + resource); logger.trace("Scanning " + resource);
} }
if (resource.isReadable()) { try {
try { MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) {
if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource);
sbd.setSource(resource); if (isCandidateComponent(sbd)) {
if (isCandidateComponent(sbd)) { if (debugEnabled) {
if (debugEnabled) { logger.debug("Identified candidate component class: " + resource);
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
} }
candidates.add(sbd);
} }
else { else {
if (traceEnabled) { if (debugEnabled) {
logger.trace("Ignored because not matching any filter: " + resource); logger.debug("Ignored because not a concrete top-level class: " + resource);
} }
} }
} }
catch (Throwable ex) { else {
throw new BeanDefinitionStoreException( if (traceEnabled) {
"Failed to read candidate component class: " + resource, ex); logger.trace("Ignored because not matching any filter: " + resource);
}
} }
} }
else { catch (FileNotFoundException ex) {
if (traceEnabled) { 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) { catch (IOException ex) {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -105,11 +105,11 @@ public class CronTrigger implements Trigger {
} }
} }
else { else {
date = new Date(); date = new Date(triggerContext.getClock().millis());
} }
ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), this.zoneId); ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), this.zoneId);
ZonedDateTime next = this.expression.next(dateTime); ZonedDateTime next = this.expression.next(dateTime);
return next != null ? Date.from(next.toInstant()) : null; return (next != null ? Date.from(next.toInstant()) : null);
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 @Override
public boolean isReadable() { public boolean isReadable() {
try { try {
URL url = getURL(); return checkReadable(getURL());
}
catch (IOException ex) {
return false;
}
}
boolean checkReadable(URL url) {
try {
if (ResourceUtils.isFileURL(url)) { if (ResourceUtils.isFileURL(url)) {
// Proceed with file system resolution // Proceed with file system resolution
File file = getFile(); File file = getFile();

View File

@ -142,6 +142,18 @@ public class ClassPathResource extends AbstractFileResolvingResource {
return (resolveURL() != null); 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. * Resolves a URL for the underlying class path resource.
* @return the resolved URL, or {@code null} if not resolvable * @return the resolved URL, or {@code null} if not resolvable

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 <i>required</i> * creating mail attachments. For such a use case, it is <i>required</i>
* that each {@code getInputStream()} call returns a fresh stream. * that each {@code getInputStream()} call returns a fresh stream.
* @return the input stream for the underlying resource (must not be {@code null}) * @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 * @throws IOException if the content stream could not be opened
* @see Resource#isReadable()
*/ */
InputStream getInputStream() throws IOException; InputStream getInputStream() throws IOException;

View File

@ -16,6 +16,7 @@
package org.springframework.orm.hibernate5; package org.springframework.orm.hibernate5;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -319,7 +320,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
Resource[] resources = this.resourcePatternResolver.getResources(pattern); Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) { for (Resource resource : resources) {
if (resource.isReadable()) { try {
MetadataReader reader = readerFactory.getMetadataReader(resource); MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName(); String className = reader.getClassMetadata().getClassName();
if (matchesEntityTypeFilter(reader, readerFactory)) { if (matchesEntityTypeFilter(reader, readerFactory)) {
@ -332,6 +333,9 @@ public class LocalSessionFactoryBuilder extends Configuration {
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
} }
} }
catch (FileNotFoundException ex) {
// Ignore non-readable resource
}
} }
} }
} }

View File

@ -16,6 +16,7 @@
package org.springframework.orm.jpa.persistenceunit; package org.springframework.orm.jpa.persistenceunit;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@ -583,7 +584,7 @@ public class DefaultPersistenceUnitManager
Resource[] resources = this.resourcePatternResolver.getResources(pattern); Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) { for (Resource resource : resources) {
if (resource.isReadable()) { try {
MetadataReader reader = readerFactory.getMetadataReader(resource); MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName(); String className = reader.getClassMetadata().getClassName();
if (matchesFilter(reader, readerFactory)) { if (matchesFilter(reader, readerFactory)) {
@ -600,6 +601,9 @@ public class DefaultPersistenceUnitManager
className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
} }
} }
catch (FileNotFoundException ex) {
// Ignore non-readable resource
}
} }
} }
catch (IOException ex) { catch (IOException ex) {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -72,7 +72,7 @@ class PathResourceLookupFunction implements Function<ServerRequest, Mono<Resourc
try { try {
Resource resource = this.location.createRelative(path); Resource resource = this.location.createRelative(path);
if (resource.exists() && resource.isReadable() && isResourceUnderLocation(resource)) { if (resource.isReadable() && isResourceUnderLocation(resource)) {
return Mono.just(resource); return Mono.just(resource);
} }
else { else {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -71,7 +71,7 @@ class PathResourceLookupFunction implements Function<ServerRequest, Optional<Res
try { try {
Resource resource = this.location.createRelative(path); Resource resource = this.location.createRelative(path);
if (resource.exists() && resource.isReadable() && isResourceUnderLocation(resource)) { if (resource.isReadable() && isResourceUnderLocation(resource)) {
return Optional.of(resource); return Optional.of(resource);
} }
else { else {

View File

@ -27,7 +27,6 @@ import org.mockito.Mockito;
import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext;
@ -64,7 +63,7 @@ public class ResourceHandlerRegistryTests {
@BeforeEach @BeforeEach
public void setUp() { public void setup() {
GenericWebApplicationContext appContext = new GenericWebApplicationContext(); GenericWebApplicationContext appContext = new GenericWebApplicationContext();
appContext.refresh(); appContext.refresh();
@ -76,8 +75,14 @@ public class ResourceHandlerRegistryTests {
this.response = new MockHttpServletResponse(); this.response = new MockHttpServletResponse();
} }
private ResourceHttpRequestHandler getHandler(String pathPattern) {
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
return (ResourceHttpRequestHandler) hm.getUrlMap().get(pathPattern);
}
@Test @Test
public void noResourceHandlers() throws Exception { public void noResourceHandlers() {
this.registry = new ResourceHandlerRegistry(new GenericWebApplicationContext(), new MockServletContext()); this.registry = new ResourceHandlerRegistry(new GenericWebApplicationContext(), new MockServletContext());
assertThat((Object) this.registry.getHandlerMapping()).isNull(); assertThat((Object) this.registry.getHandlerMapping()).isNull();
} }
@ -126,7 +131,7 @@ public class ResourceHandlerRegistryTests {
} }
@Test @Test
public void resourceChain() throws Exception { public void resourceChain() {
ResourceResolver mockResolver = Mockito.mock(ResourceResolver.class); ResourceResolver mockResolver = Mockito.mock(ResourceResolver.class);
ResourceTransformer mockTransformer = Mockito.mock(ResourceTransformer.class); ResourceTransformer mockTransformer = Mockito.mock(ResourceTransformer.class);
this.registration.resourceChain(true).addResolver(mockResolver).addTransformer(mockTransformer); this.registration.resourceChain(true).addResolver(mockResolver).addTransformer(mockTransformer);
@ -148,7 +153,7 @@ public class ResourceHandlerRegistryTests {
} }
@Test @Test
public void resourceChainWithoutCaching() throws Exception { public void resourceChainWithoutCaching() {
this.registration.resourceChain(false); this.registration.resourceChain(false);
ResourceHttpRequestHandler handler = getHandler("/resources/**"); ResourceHttpRequestHandler handler = getHandler("/resources/**");
@ -163,7 +168,7 @@ public class ResourceHandlerRegistryTests {
@Test @Test
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void resourceChainWithVersionResolver() throws Exception { public void resourceChainWithVersionResolver() {
VersionResourceResolver versionResolver = new VersionResourceResolver() VersionResourceResolver versionResolver = new VersionResourceResolver()
.addFixedVersionStrategy("fixed", "/**/*.js") .addFixedVersionStrategy("fixed", "/**/*.js")
.addContentVersionStrategy("/**"); .addContentVersionStrategy("/**");
@ -188,7 +193,7 @@ public class ResourceHandlerRegistryTests {
@Test @Test
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void resourceChainWithOverrides() throws Exception { public void resourceChainWithOverrides() {
CachingResourceResolver cachingResolver = Mockito.mock(CachingResourceResolver.class); CachingResourceResolver cachingResolver = Mockito.mock(CachingResourceResolver.class);
VersionResourceResolver versionResolver = Mockito.mock(VersionResourceResolver.class); VersionResourceResolver versionResolver = Mockito.mock(VersionResourceResolver.class);
WebJarsResourceResolver webjarsResolver = Mockito.mock(WebJarsResourceResolver.class); WebJarsResourceResolver webjarsResolver = Mockito.mock(WebJarsResourceResolver.class);
@ -224,13 +229,11 @@ public class ResourceHandlerRegistryTests {
} }
@Test @Test
public void urlResourceWithCharset() throws Exception { public void urlResourceWithCharset() {
this.registration.addResourceLocations("[charset=ISO-8859-1]file:///tmp"); this.registration.addResourceLocations("[charset=ISO-8859-1]file:///tmp");
this.registration.resourceChain(true); this.registration.resourceChain(true);
ResourceHttpRequestHandler handler = getHandler("/resources/**"); ResourceHttpRequestHandler handler = getHandler("/resources/**");
UrlResource resource = (UrlResource) handler.getLocations().get(1);
assertThat(resource.getURL().toString()).isEqualTo("file:/tmp");
assertThat(handler.getUrlPathHelper()).isNotNull(); assertThat(handler.getUrlPathHelper()).isNotNull();
List<ResourceResolver> resolvers = handler.getResourceResolvers(); List<ResourceResolver> resolvers = handler.getResourceResolvers();
@ -241,15 +244,10 @@ public class ResourceHandlerRegistryTests {
} }
@Test @Test
void lastModifiedDisabled() { public void lastModifiedDisabled() {
this.registration.setUseLastModified(false); this.registration.setUseLastModified(false);
ResourceHttpRequestHandler handler = getHandler("/resources/**"); ResourceHttpRequestHandler handler = getHandler("/resources/**");
assertThat(handler.isUseLastModified()).isFalse(); assertThat(handler.isUseLastModified()).isFalse();
} }
private ResourceHttpRequestHandler getHandler(String pathPattern) {
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
return (ResourceHttpRequestHandler) hm.getUrlMap().get(pathPattern);
}
} }

View File

@ -289,7 +289,6 @@ public class ResourceHttpRequestHandlerTests {
@Test // SPR-14368 @Test // SPR-14368
public void getResourceWithMediaTypeResolvedThroughServletContext() throws Exception { public void getResourceWithMediaTypeResolvedThroughServletContext() throws Exception {
MockServletContext servletContext = new MockServletContext() { MockServletContext servletContext = new MockServletContext() {
@Override @Override
public String getMimeType(String filePath) { public String getMimeType(String filePath) {
@ -311,7 +310,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(this.response.getContentAsString()).isEqualTo("h1 { color:red; }"); assertThat(this.response.getContentAsString()).isEqualTo("h1 { color:red; }");
} }
@Test // gh-27538 @Test // gh-27538
public void filterNonExistingLocations() throws Exception { public void filterNonExistingLocations() throws Exception {
List<Resource> inputLocations = Arrays.asList( List<Resource> inputLocations = Arrays.asList(
new ClassPathResource("test/", getClass()), new ClassPathResource("test/", getClass()),
@ -331,7 +330,6 @@ public class ResourceHttpRequestHandlerTests {
@Test @Test
public void testInvalidPath() throws Exception { public void testInvalidPath() throws Exception {
// Use mock ResourceResolver: i.e. we're only testing upfront validations... // Use mock ResourceResolver: i.e. we're only testing upfront validations...
Resource resource = mock(Resource.class); Resource resource = mock(Resource.class);
@ -677,7 +675,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(ranges[11]).isEqualTo("t."); assertThat(ranges[11]).isEqualTo("t.");
} }
@Test // gh-25976 @Test // gh-25976
public void partialContentByteRangeWithEncodedResource(GzipSupport.GzippedFiles gzippedFiles) throws Exception { public void partialContentByteRangeWithEncodedResource(GzipSupport.GzippedFiles gzippedFiles) throws Exception {
String path = "js/foo.js"; String path = "js/foo.js";
gzippedFiles.create(path); gzippedFiles.create(path);
@ -706,7 +704,7 @@ public class ResourceHttpRequestHandlerTests {
assertThat(this.response.getHeaderValues("Vary")).containsExactly("Accept-Encoding"); assertThat(this.response.getHeaderValues("Vary")).containsExactly("Accept-Encoding");
} }
@Test // gh-25976 @Test // gh-25976
public void partialContentWithHttpHead() throws Exception { public void partialContentWithHttpHead() throws Exception {
this.request.setMethod("HEAD"); this.request.setMethod("HEAD");
this.request.addHeader("Range", "bytes=0-1"); this.request.addHeader("Range", "bytes=0-1");