Support ResourceLoader delegation from ApplicationResourceLoader
Update `ApplicationResourceLoader` to support delegation to another `ResourceLoader`. The update allows customer resource loaders to be used when loading SSL resources. Closes gh-42835
This commit is contained in:
parent
65fcf34773
commit
e6b840004d
|
|
@ -60,6 +60,7 @@ import org.springframework.context.annotation.Conditional;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -81,9 +82,12 @@ import org.springframework.util.StringUtils;
|
|||
@EnableConfigurationProperties(CouchbaseProperties.class)
|
||||
public class CouchbaseAutoConfiguration {
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final CouchbaseProperties properties;
|
||||
|
||||
CouchbaseAutoConfiguration(CouchbaseProperties properties) {
|
||||
CouchbaseAutoConfiguration(ResourceLoader resourceLoader, CouchbaseProperties properties) {
|
||||
this.resourceLoader = ApplicationResourceLoader.get(resourceLoader);
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +121,7 @@ public class CouchbaseAutoConfiguration {
|
|||
}
|
||||
Jks jks = this.properties.getAuthentication().getJks();
|
||||
if (jks.getLocation() != null) {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(jks.getLocation());
|
||||
Resource resource = this.resourceLoader.getResource(jks.getLocation());
|
||||
String keystorePassword = jks.getPassword();
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public final class PropertiesSslBundle implements SslBundle {
|
|||
* @return an {@link SslBundle} instance
|
||||
*/
|
||||
public static SslBundle get(PemSslBundleProperties properties) {
|
||||
return get(properties, new ApplicationResourceLoader());
|
||||
return get(properties, ApplicationResourceLoader.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -143,7 +143,7 @@ public final class PropertiesSslBundle implements SslBundle {
|
|||
* @return an {@link SslBundle} instance
|
||||
*/
|
||||
public static SslBundle get(JksSslBundleProperties properties) {
|
||||
return get(properties, new ApplicationResourceLoader());
|
||||
return get(properties, ApplicationResourceLoader.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ import org.springframework.core.io.ResourceLoader;
|
|||
@EnableConfigurationProperties(SslProperties.class)
|
||||
public class SslAutoConfiguration {
|
||||
|
||||
private final ApplicationResourceLoader resourceLoader;
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final SslProperties sslProperties;
|
||||
|
||||
SslAutoConfiguration(ResourceLoader resourceLoader, SslProperties sslProperties) {
|
||||
this.resourceLoader = new ApplicationResourceLoader(resourceLoader.getClassLoader());
|
||||
this.resourceLoader = ApplicationResourceLoader.get(resourceLoader);
|
||||
this.sslProperties = sslProperties;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class BundleContentPropertyTests {
|
|||
@Test
|
||||
void toWatchPathWhenNotPathThrowsException() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", PEM_TEXT);
|
||||
assertThatIllegalStateException().isThrownBy(() -> property.toWatchPath(new ApplicationResourceLoader()))
|
||||
assertThatIllegalStateException().isThrownBy(() -> property.toWatchPath(ApplicationResourceLoader.get()))
|
||||
.withMessage("Unable to convert value of property 'name' to a path");
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ class BundleContentPropertyTests {
|
|||
URL resource = getClass().getResource("keystore.jks");
|
||||
Path file = Path.of(resource.toURI()).toAbsolutePath();
|
||||
BundleContentProperty property = new BundleContentProperty("name", file.toString());
|
||||
assertThat(property.toWatchPath(new ApplicationResourceLoader())).isEqualTo(file);
|
||||
assertThat(property.toWatchPath(ApplicationResourceLoader.get())).isEqualTo(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -95,7 +95,7 @@ class BundleContentPropertyTests {
|
|||
URL resource = getClass().getResource("keystore.jks");
|
||||
Path file = Path.of(resource.toURI()).toAbsolutePath();
|
||||
BundleContentProperty property = new BundleContentProperty("name", file.toString());
|
||||
ResourceLoader resourceLoader = spy(new ApplicationResourceLoader());
|
||||
ResourceLoader resourceLoader = spy(ApplicationResourceLoader.get());
|
||||
assertThat(property.toWatchPath(resourceLoader)).isEqualTo(file);
|
||||
then(resourceLoader).should(atLeastOnce()).getResource(file.toString());
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ class BundleContentPropertyTests {
|
|||
void shouldThrowBundleContentNotWatchableExceptionIfContentIsNotWatchable() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", "https://example.com/");
|
||||
assertThatExceptionOfType(BundleContentNotWatchableException.class)
|
||||
.isThrownBy(() -> property.toWatchPath(new ApplicationResourceLoader()))
|
||||
.isThrownBy(() -> property.toWatchPath(ApplicationResourceLoader.get()))
|
||||
.withMessageContaining("Only 'file:' resources are watchable");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ class StringToFileConverter implements Converter<String, File> {
|
|||
|
||||
@Override
|
||||
public File convert(String source) {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(source);
|
||||
return getFile(resource);
|
||||
return getFile(ApplicationResourceLoader.get().getResource(source));
|
||||
}
|
||||
|
||||
private File getFile(Resource resource) {
|
||||
|
|
|
|||
|
|
@ -16,27 +16,38 @@
|
|||
|
||||
package org.springframework.boot.io;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.ProtocolResolver;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link DefaultResourceLoader} with any {@link ProtocolResolver ProtocolResolvers}
|
||||
* registered in a {@code spring.factories} file applied to it. Plain paths without a
|
||||
* qualifier will resolve to file system resources. This is different from
|
||||
* Class can be used to obtain {@link ResourceLoader ResourceLoaders} supporting
|
||||
* additional {@link ProtocolResolver ProtocolResolvers} registered in
|
||||
* {@code spring.factories}.
|
||||
* <p>
|
||||
* When not delegating to an existing resource loader, plain paths without a qualifier
|
||||
* will resolve to file system resources. This is different from
|
||||
* {@code DefaultResourceLoader}, which resolves unqualified paths to classpath resources.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public class ApplicationResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationResourceLoader}.
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of {@link #get()}
|
||||
*/
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
public ApplicationResourceLoader() {
|
||||
this(null);
|
||||
}
|
||||
|
|
@ -46,7 +57,9 @@ public class ApplicationResourceLoader extends DefaultResourceLoader {
|
|||
* @param classLoader the {@link ClassLoader} to load class path resources with, or
|
||||
* {@code null} for using the thread context class loader at the time of actual
|
||||
* resource access
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of {@link #get(ClassLoader)}
|
||||
*/
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
public ApplicationResourceLoader(ClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
SpringFactoriesLoader loader = SpringFactoriesLoader.forDefaultResourceLocation(classLoader);
|
||||
|
|
@ -55,12 +68,107 @@ public class ApplicationResourceLoader extends DefaultResourceLoader {
|
|||
|
||||
@Override
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new FileSystemContextResource(path);
|
||||
return new ApplicationResource(path);
|
||||
}
|
||||
|
||||
private static class FileSystemContextResource extends FileSystemResource implements ContextResource {
|
||||
/**
|
||||
* Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver
|
||||
* ProtocolResolvers} registered in {@code spring.factories}. The factories file will
|
||||
* be resolved using the default class loader at the time this call is made. Resources
|
||||
* will be resolved using the default class loader at the time they are resolved.
|
||||
* @return a {@link ResourceLoader} instance
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static ResourceLoader get() {
|
||||
return get((ClassLoader) null);
|
||||
}
|
||||
|
||||
FileSystemContextResource(String path) {
|
||||
/**
|
||||
* Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver
|
||||
* ProtocolResolvers} registered in {@code spring.factories}. The factories files and
|
||||
* resources will be resolved using the specified class loader.
|
||||
* @param classLoader the class loader to use or {@code null} to use the default class
|
||||
* loader
|
||||
* @return a {@link ResourceLoader} instance
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static ResourceLoader get(ClassLoader classLoader) {
|
||||
return get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver
|
||||
* ProtocolResolvers} registered in {@code spring.factories}.
|
||||
* @param classLoader the class loader to use or {@code null} to use the default class
|
||||
* loader
|
||||
* @param springFactoriesLoader the {@link SpringFactoriesLoader} used to load
|
||||
* {@link ProtocolResolver ProtocolResolvers}
|
||||
* @return a {@link ResourceLoader} instance
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static ResourceLoader get(ClassLoader classLoader, SpringFactoriesLoader springFactoriesLoader) {
|
||||
return get(ApplicationFileSystemResourceLoader.get(classLoader), springFactoriesLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link ResourceLoader} delegating to the given resource loader and
|
||||
* supporting additional {@link ProtocolResolver ProtocolResolvers} registered in
|
||||
* {@code spring.factories}. The factories file will be resolved using the default
|
||||
* class loader at the time this call is made.
|
||||
* @param resourceLoader the delegate resource loader
|
||||
* @return a {@link ResourceLoader} instance
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static ResourceLoader get(ResourceLoader resourceLoader) {
|
||||
Assert.notNull(resourceLoader, "'resourceLoader' must not be null");
|
||||
return get(resourceLoader, SpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link ResourceLoader} delegating to the given resource loader and
|
||||
* supporting additional {@link ProtocolResolver ProtocolResolvers} registered in
|
||||
* {@code spring.factories}.
|
||||
* @param resourceLoader the delegate resource loader
|
||||
* @param springFactoriesLoader the {@link SpringFactoriesLoader} used to load
|
||||
* {@link ProtocolResolver ProtocolResolvers}
|
||||
* @return a {@link ResourceLoader} instance
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static ResourceLoader get(ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader) {
|
||||
Assert.notNull(resourceLoader, "'resourceLoader' must not be null");
|
||||
Assert.notNull(springFactoriesLoader, "'springFactoriesLoader' must not be null");
|
||||
return new ProtocolResolvingResourceLoader(resourceLoader, springFactoriesLoader.load(ProtocolResolver.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal {@link ResourceLoader} used to load {@link ApplicationResource}.
|
||||
*/
|
||||
private static final class ApplicationFileSystemResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
private static final ResourceLoader shared = new ApplicationFileSystemResourceLoader(null);
|
||||
|
||||
private ApplicationFileSystemResourceLoader(ClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ApplicationResource(path);
|
||||
}
|
||||
|
||||
static ResourceLoader get(ClassLoader classLoader) {
|
||||
return (classLoader != null) ? new ApplicationFileSystemResourceLoader(classLoader)
|
||||
: ApplicationFileSystemResourceLoader.shared;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An application {@link Resource}.
|
||||
*/
|
||||
private static final class ApplicationResource extends FileSystemResource implements ContextResource {
|
||||
|
||||
ApplicationResource(String path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
|
|
@ -71,4 +179,39 @@ public class ApplicationResourceLoader extends DefaultResourceLoader {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceLoader} decorator that adds support for additional
|
||||
* {@link ProtocolResolver ProtocolResolvers}.
|
||||
*/
|
||||
private static class ProtocolResolvingResourceLoader implements ResourceLoader {
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final List<ProtocolResolver> protocolResolvers;
|
||||
|
||||
ProtocolResolvingResourceLoader(ResourceLoader resourceLoader, List<ProtocolResolver> protocolResolvers) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.protocolResolvers = protocolResolvers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
if (StringUtils.hasLength(location)) {
|
||||
for (ProtocolResolver protocolResolver : this.protocolResolvers) {
|
||||
Resource resource = protocolResolver.resolve(location, this);
|
||||
if (resource != null) {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.resourceLoader.getResource(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.resourceLoader.getClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import org.springframework.core.io.ProtocolResolver;
|
|||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextInitializer} that adds all {@link ProtocolResolver}s
|
||||
* registered in a {@code spring.factories} file.
|
||||
* {@link ApplicationContextInitializer} that adds all {@link ProtocolResolver
|
||||
* ProtocolResolvers} registered in a {@code spring.factories} file.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class JavaLoggingSystem extends AbstractLoggingSystem {
|
|||
protected void loadConfiguration(String location, LogFile logFile) {
|
||||
Assert.notNull(location, "Location must not be null");
|
||||
try {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(location);
|
||||
Resource resource = ApplicationResourceLoader.get().getResource(location);
|
||||
String configuration = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
|
||||
if (logFile != null) {
|
||||
configuration = configuration.replace("${LOG_FILE}", StringUtils.cleanPath(logFile.toString()));
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem {
|
|||
}
|
||||
|
||||
private Configuration load(String location, LoggerContext context) throws IOException {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(location);
|
||||
Resource resource = ApplicationResourceLoader.get().getResource(location);
|
||||
ConfigurationSource source = getConfigurationSource(resource);
|
||||
return ConfigurationFactory.getInstance().getConfiguration(context, source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanF
|
|||
applySystemProperties(initializationContext.getEnvironment(), logFile);
|
||||
}
|
||||
try {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(location);
|
||||
Resource resource = ApplicationResourceLoader.get().getResource(location);
|
||||
configureByResourceUrl(initializationContext, loggerContext, resource.getURL());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class JksSslStoreBundle implements SslStoreBundle {
|
|||
* @param trustStoreDetails the trust store details
|
||||
*/
|
||||
public JksSslStoreBundle(JksSslStoreDetails keyStoreDetails, JksSslStoreDetails trustStoreDetails) {
|
||||
this(keyStoreDetails, trustStoreDetails, new ApplicationResourceLoader());
|
||||
this(keyStoreDetails, trustStoreDetails, ApplicationResourceLoader.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ public interface PemSslStore {
|
|||
* @return a loaded {@link PemSslStore} or {@code null}.
|
||||
*/
|
||||
static PemSslStore load(PemSslStoreDetails details) {
|
||||
return load(details, new ApplicationResourceLoader());
|
||||
return load(details, ApplicationResourceLoader.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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
|
||||
*
|
||||
* https://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.boot.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ApplicationResourceLoader}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ApplicationResourceLoaderTests {
|
||||
|
||||
private static final String SPRING_FACTORIES = "META-INF/spring.factories";
|
||||
|
||||
private static final String TEST_PROTOCOL_RESOLVERS_FACTORIES = "META-INF/spring-test-protocol-resolvers.factories";
|
||||
|
||||
private static final String TEST_BASE_64_VALUE = Base64.getEncoder().encodeToString("test".getBytes());
|
||||
|
||||
@Test
|
||||
void getIncludesProtocolResolvers() throws IOException {
|
||||
ResourceLoader loader = ApplicationResourceLoader.get();
|
||||
Resource resource = loader.getResource("base64:" + TEST_BASE_64_VALUE);
|
||||
assertThat(contentAsString(resource)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithClassPathIncludesProtocolResolvers() throws IOException {
|
||||
ClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories);
|
||||
ResourceLoader loader = ApplicationResourceLoader.get(classLoader);
|
||||
Resource resource = loader.getResource("reverse:test");
|
||||
assertThat(contentAsString(resource)).isEqualTo("tset");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithClassPathWhenClassPathIsNullIncludesProtocolResolvers() throws IOException {
|
||||
ResourceLoader loader = ApplicationResourceLoader.get((ClassLoader) null);
|
||||
Resource resource = loader.getResource("base64:" + TEST_BASE_64_VALUE);
|
||||
assertThat(contentAsString(resource)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithClassPathAndSpringFactoriesLoaderIncludesProtocolResolvers() throws IOException {
|
||||
SpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader
|
||||
.forResourceLocation(TEST_PROTOCOL_RESOLVERS_FACTORIES);
|
||||
ResourceLoader loader = ApplicationResourceLoader.get((ClassLoader) null, springFactoriesLoader);
|
||||
Resource resource = loader.getResource("reverse:test");
|
||||
assertThat(contentAsString(resource)).isEqualTo("tset");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithClassPathAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ClassLoader) null, null))
|
||||
.withMessage("'springFactoriesLoader' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderIncludesProtocolResolvers() throws IOException {
|
||||
ResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader());
|
||||
Resource resource = loader.getResource("base64:" + TEST_BASE_64_VALUE);
|
||||
assertThat(contentAsString(resource)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderDelegatesLoading() throws IOException {
|
||||
DefaultResourceLoader delegate = new TestResourceLoader();
|
||||
ResourceLoader loader = ApplicationResourceLoader.get(delegate);
|
||||
assertThat(contentAsString(loader.getResource("spring"))).isEqualTo("boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderWhenResourceLoaderIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ResourceLoader) null))
|
||||
.withMessage("'resourceLoader' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderAndSpringFactoriesLoaderIncludesProtocolResolvers() throws IOException {
|
||||
DefaultResourceLoader delegate = new TestResourceLoader();
|
||||
ResourceLoader loader = ApplicationResourceLoader.get(delegate);
|
||||
Resource resource = loader.getResource("base64:" + TEST_BASE_64_VALUE);
|
||||
assertThat(contentAsString(resource)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderAndSpringFactoriesLoaderWhenResourceLoaderIsNullThrowsException() {
|
||||
SpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader
|
||||
.forResourceLocation(TEST_PROTOCOL_RESOLVERS_FACTORIES);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ApplicationResourceLoader.get((ResourceLoader) null, springFactoriesLoader))
|
||||
.withMessage("'resourceLoader' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithResourceLoaderAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> ApplicationResourceLoader.get(new TestResourceLoader(), null))
|
||||
.withMessage("'springFactoriesLoader' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getResourceWhenPathIsRelative() throws IOException {
|
||||
ResourceLoader loader = ApplicationResourceLoader.get();
|
||||
String name = "src/test/resources/" + TEST_PROTOCOL_RESOLVERS_FACTORIES;
|
||||
Resource resource = loader.getResource(name);
|
||||
assertThat(resource.getFile()).isEqualTo(new File(name));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getResourceWhenPathIsAbsolute() throws IOException {
|
||||
File file = new File("src/test/resources/" + TEST_PROTOCOL_RESOLVERS_FACTORIES);
|
||||
ResourceLoader loader = ApplicationResourceLoader.get();
|
||||
Resource resource = loader.getResource(file.getAbsolutePath());
|
||||
assertThat(resource.getFile()).hasSameBinaryContentAs(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getResourceWhenPathIsNull() {
|
||||
ResourceLoader loader = ApplicationResourceLoader.get();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> loader.getResource(null))
|
||||
.withMessage("Location must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getClassLoaderReturnsDelegateClassLoader() {
|
||||
ClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories);
|
||||
ResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(classLoader));
|
||||
assertThat(loader.getClassLoader()).isSameAs(classLoader);
|
||||
}
|
||||
|
||||
private String contentAsString(Resource resource) throws IOException {
|
||||
return resource.getContentAsString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String useTestProtocolResolversFactories(String name) {
|
||||
return (!SPRING_FACTORIES.equals(name)) ? name : TEST_PROTOCOL_RESOLVERS_FACTORIES;
|
||||
}
|
||||
|
||||
static class TestClassLoader extends ClassLoader {
|
||||
|
||||
private final UnaryOperator<String> mapper;
|
||||
|
||||
TestClassLoader(UnaryOperator<String> mapper) {
|
||||
super(Thread.currentThread().getContextClassLoader());
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
return super.getResource(this.mapper.apply(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return super.getResources(this.mapper.apply(name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
return (!"spring".equals(location)) ? super.getResource(location)
|
||||
: new ByteArrayResource("boot".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
|
||||
/**
|
||||
* Integration tests for resolving configuration properties using
|
||||
* {@code ProtocolResolver}s.
|
||||
* {@code ProtocolResolver ProtocolResolvers}.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2024 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
|
||||
*
|
||||
* https://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.boot.io;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ProtocolResolver;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Test {@link ProtocolResolver} that reverses a String.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ReverseStringProtocolResolver implements ProtocolResolver {
|
||||
|
||||
private static final String PREFIX = "reverse:";
|
||||
|
||||
@Override
|
||||
public Resource resolve(String location, ResourceLoader resourceLoader) {
|
||||
if (!location.startsWith(PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
return new ByteArrayResource(reverse(location.substring(PREFIX.length())));
|
||||
}
|
||||
|
||||
private byte[] reverse(String substring) {
|
||||
return new StringBuilder(substring).reverse().toString().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ class JksSslStoreBundleTests {
|
|||
}
|
||||
|
||||
private String encodeFileContent(String location) throws IOException {
|
||||
Resource resource = new ApplicationResourceLoader().getResource(location);
|
||||
Resource resource = ApplicationResourceLoader.get().getResource(location);
|
||||
byte[] bytes = Files.readAllBytes(resource.getFile().toPath());
|
||||
return "base64:" + Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class LoadedPemSslStoreTests {
|
|||
void certificatesAreLoadedLazily() {
|
||||
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
|
||||
.withPrivateKey("classpath:test-key.pem");
|
||||
LoadedPemSslStore store = new LoadedPemSslStore(details, new ApplicationResourceLoader());
|
||||
LoadedPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get());
|
||||
assertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class LoadedPemSslStoreTests {
|
|||
void privateKeyIsLoadedLazily() {
|
||||
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:test-cert.pem")
|
||||
.withPrivateKey("classpath:missing-test-key.pem");
|
||||
LoadedPemSslStore store = new LoadedPemSslStore(details, new ApplicationResourceLoader());
|
||||
LoadedPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get());
|
||||
assertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::privateKey);
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ class LoadedPemSslStoreTests {
|
|||
void withAliasIsLazy() {
|
||||
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
|
||||
.withPrivateKey("classpath:test-key.pem");
|
||||
PemSslStore store = new LoadedPemSslStore(details, new ApplicationResourceLoader()).withAlias("alias");
|
||||
PemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get()).withAlias("alias");
|
||||
assertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ class LoadedPemSslStoreTests {
|
|||
void withPasswordIsLazy() {
|
||||
PemSslStoreDetails details = PemSslStoreDetails.forCertificate("classpath:missing-test-cert.pem")
|
||||
.withPrivateKey("classpath:test-key.pem");
|
||||
PemSslStore store = new LoadedPemSslStore(details, new ApplicationResourceLoader()).withPassword("password");
|
||||
PemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get()).withPassword("password");
|
||||
assertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class PemContentTests {
|
|||
@Test
|
||||
void getCertificateReturnsCertificates() throws Exception {
|
||||
PemContent content = PemContent.load(contentFromClasspath("/test-cert-chain.pem"),
|
||||
new ApplicationResourceLoader());
|
||||
ApplicationResourceLoader.get());
|
||||
List<X509Certificate> certificates = content.getCertificates();
|
||||
assertThat(certificates).isNotNull();
|
||||
assertThat(certificates).hasSize(2);
|
||||
|
|
@ -71,7 +71,7 @@ class PemContentTests {
|
|||
@Test
|
||||
void getPrivateKeyReturnsPrivateKey() throws Exception {
|
||||
PemContent content = PemContent.load(contentFromClasspath("/org/springframework/boot/web/server/pkcs8/dsa.key"),
|
||||
new ApplicationResourceLoader());
|
||||
ApplicationResourceLoader.get());
|
||||
PrivateKey privateKey = content.getPrivateKey();
|
||||
assertThat(privateKey).isNotNull();
|
||||
assertThat(privateKey.getFormat()).isEqualTo("PKCS#8");
|
||||
|
|
@ -95,7 +95,7 @@ class PemContentTests {
|
|||
|
||||
@Test
|
||||
void loadWithStringWhenContentIsNullReturnsNull() throws Exception {
|
||||
assertThat(PemContent.load((String) null, new ApplicationResourceLoader())).isNull();
|
||||
assertThat(PemContent.load((String) null, ApplicationResourceLoader.get())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -118,7 +118,7 @@ class PemContentTests {
|
|||
+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO
|
||||
32C9XWHwRA4=
|
||||
-----END CERTIFICATE-----""";
|
||||
assertThat(PemContent.load(content, new ApplicationResourceLoader())).hasToString(content);
|
||||
assertThat(PemContent.load(content, ApplicationResourceLoader.get())).hasToString(content);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -159,11 +159,11 @@ class PemContentTests {
|
|||
+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO
|
||||
32C9XWHwRA4=
|
||||
-----END CERTIFICATE-----""";
|
||||
assertThat(PemContent.load(content, new ApplicationResourceLoader())).hasToString(trimmedContent);
|
||||
assertThat(PemContent.load(content, ApplicationResourceLoader.get())).hasToString(trimmedContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPresentInTextWithUntrimmedContent() throws Exception {
|
||||
void isPresentInTextWithUntrimmedContent() {
|
||||
String content = """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICpDCCAYwCCQCDOqHKPjAhCTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls
|
||||
|
|
@ -187,14 +187,14 @@ class PemContentTests {
|
|||
|
||||
@Test
|
||||
void loadWithStringWhenClasspathLocationReturnsContent() throws IOException {
|
||||
String actual = PemContent.load("classpath:test-cert.pem", new ApplicationResourceLoader()).toString();
|
||||
String actual = PemContent.load("classpath:test-cert.pem", ApplicationResourceLoader.get()).toString();
|
||||
String expected = contentFromClasspath("test-cert.pem");
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadWithStringWhenFileLocationReturnsContent() throws IOException {
|
||||
String actual = PemContent.load("src/test/resources/test-cert.pem", new ApplicationResourceLoader()).toString();
|
||||
String actual = PemContent.load("src/test/resources/test-cert.pem", ApplicationResourceLoader.get()).toString();
|
||||
String expected = contentFromClasspath("test-cert.pem");
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
org.springframework.core.io.ProtocolResolver=\
|
||||
org.springframework.boot.io.ReverseStringProtocolResolver
|
||||
Loading…
Reference in New Issue