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:
Phillip Webb 2024-10-22 18:44:40 -07:00
parent 65fcf34773
commit e6b840004d
19 changed files with 435 additions and 39 deletions

View File

@ -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());

View File

@ -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());
}
/**

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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) {

View File

@ -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();
}
}
}

View File

@ -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
*/

View File

@ -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()));

View File

@ -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);
}

View File

@ -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) {

View File

@ -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());
}
/**

View File

@ -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());
}
/**

View File

@ -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));
}
}
}

View File

@ -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
*/

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,2 @@
org.springframework.core.io.ProtocolResolver=\
org.springframework.boot.io.ReverseStringProtocolResolver