Register ProtocolResolvers with the application context by default

Any ProtocolResolvers that are registered in a spring.factories file
will be added to the application context using an
ApplicationContextInitializer.

Closes gh-41433
This commit is contained in:
Scott Frederick 2024-07-09 18:13:40 -05:00
parent a349170073
commit 09c0714730
5 changed files with 172 additions and 3 deletions

View File

@ -0,0 +1,43 @@
/*
* 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.util.List;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
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.
*
* @author Scott Frederick
*/
class ProtocolResolverApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
SpringFactoriesLoader loader = SpringFactoriesLoader
.forDefaultResourceLocation(applicationContext.getClassLoader());
List<ProtocolResolver> protocolResolvers = loader.load(ProtocolResolver.class);
protocolResolvers.forEach(applicationContext::addProtocolResolver);
}
}

View File

@ -36,6 +36,7 @@ org.springframework.boot.diagnostics.FailureAnalyzers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.io.ProtocolResolverApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

View File

@ -265,7 +265,7 @@ class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.web(WebApplicationType.NONE);
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(4);
assertThat(application.application().getInitializers()).hasSize(5);
}
@Test
@ -274,7 +274,7 @@ class SpringApplicationBuilderTests {
.child(ChildConfig.class)
.web(WebApplicationType.NONE);
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(5);
assertThat(application.application().getInitializers()).hasSize(6);
}
@Test
@ -284,7 +284,7 @@ class SpringApplicationBuilderTests {
.initializers((ConfigurableApplicationContext applicationContext) -> {
});
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(5);
assertThat(application.application().getInitializers()).hasSize(6);
}
@Test

View File

@ -0,0 +1,77 @@
/*
* 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.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for resolving configuration properties using
* {@code ProtocolResolver}s.
*
* @author Scott Frederick
*/
class ProtocolResolverApplicationContextInitializerIntegrationTests {
@Test
void base64ResourceResolves() throws IOException {
SpringApplication application = new SpringApplication(TestConfiguration.class);
application.setDefaultProperties(Map.of("test.resource", "base64:dGVzdC12YWx1ZQ=="));
application.setWebApplicationType(WebApplicationType.NONE);
ConfigurableApplicationContext context = application.run();
TestProperties propertiesBean = context.getBean(TestProperties.class);
Resource resource = propertiesBean.getResource();
assertThat(resource).isNotNull();
assertThat(resource.exists()).isTrue();
assertThat(resource.getContentAsString(Charset.defaultCharset())).isEqualTo("test-value");
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TestProperties.class)
static class TestConfiguration {
}
@ConfigurationProperties(prefix = "test")
static class TestProperties {
Resource resource;
Resource getResource() {
return this.resource;
}
void setResource(Resource resource) {
this.resource = resource;
}
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.util.Collection;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ProtocolResolver;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ProtocolResolverApplicationContextInitializer}.
*
* @author Scott Frederick
*/
class ProtocolResolverApplicationContextInitializerTests {
@Test
void initializeAddsProtocolResolversToApplicationContext() {
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext()) {
ProtocolResolverApplicationContextInitializer initializer = new ProtocolResolverApplicationContextInitializer();
initializer.initialize(context);
assertThat(context).isInstanceOf(DefaultResourceLoader.class);
Collection<ProtocolResolver> protocolResolvers = ((DefaultResourceLoader) context).getProtocolResolvers();
assertThat(protocolResolvers).hasExactlyElementsOfTypes(Base64ProtocolResolver.class);
}
}
}