Merge branch '6.0.x'
This commit is contained in:
commit
14911fb32f
|
@ -34,6 +34,7 @@ import org.springframework.core.env.MutablePropertySources;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
@ -44,27 +45,30 @@ import org.springframework.util.ReflectionUtils;
|
||||||
* single {@link PropertySource} rather than creating dedicated ones.
|
* single {@link PropertySource} rather than creating dedicated ones.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Sam Brannen
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
* @see PropertySourceDescriptor
|
* @see PropertySourceDescriptor
|
||||||
*/
|
*/
|
||||||
public class PropertySourceProcessor {
|
public class PropertySourceProcessor {
|
||||||
|
|
||||||
private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();
|
private static final PropertySourceFactory defaultPropertySourceFactory = new DefaultPropertySourceFactory();
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(PropertySourceProcessor.class);
|
private static final Log logger = LogFactory.getLog(PropertySourceProcessor.class);
|
||||||
|
|
||||||
|
|
||||||
private final ConfigurableEnvironment environment;
|
private final ConfigurableEnvironment environment;
|
||||||
|
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
|
|
||||||
private final List<String> propertySourceNames;
|
private final List<String> propertySourceNames = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public PropertySourceProcessor(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
|
public PropertySourceProcessor(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.resourceLoader = resourceLoader;
|
this.resourceLoader = resourceLoader;
|
||||||
this.propertySourceNames = new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the specified {@link PropertySourceDescriptor} against the
|
* Process the specified {@link PropertySourceDescriptor} against the
|
||||||
* environment managed by this instance.
|
* environment managed by this instance.
|
||||||
|
@ -78,7 +82,7 @@ public class PropertySourceProcessor {
|
||||||
Assert.isTrue(locations.size() > 0, "At least one @PropertySource(value) location is required");
|
Assert.isTrue(locations.size() > 0, "At least one @PropertySource(value) location is required");
|
||||||
boolean ignoreResourceNotFound = descriptor.ignoreResourceNotFound();
|
boolean ignoreResourceNotFound = descriptor.ignoreResourceNotFound();
|
||||||
PropertySourceFactory factory = (descriptor.propertySourceFactory() != null ?
|
PropertySourceFactory factory = (descriptor.propertySourceFactory() != null ?
|
||||||
instantiateClass(descriptor.propertySourceFactory()) : DEFAULT_PROPERTY_SOURCE_FACTORY);
|
instantiateClass(descriptor.propertySourceFactory()) : defaultPropertySourceFactory);
|
||||||
|
|
||||||
for (String location : locations) {
|
for (String location : locations) {
|
||||||
try {
|
try {
|
||||||
|
@ -86,9 +90,10 @@ public class PropertySourceProcessor {
|
||||||
Resource resource = this.resourceLoader.getResource(resolvedLocation);
|
Resource resource = this.resourceLoader.getResource(resolvedLocation);
|
||||||
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
|
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
|
catch (RuntimeException | IOException ex) {
|
||||||
// Placeholders not resolvable or resource not found when trying to open it
|
// Placeholders not resolvable (IllegalArgumentException) or resource not found when trying to open it
|
||||||
if (ignoreResourceNotFound) {
|
if (ignoreResourceNotFound && (ex instanceof IllegalArgumentException || isIgnorableException(ex) ||
|
||||||
|
isIgnorableException(ex.getCause()))) {
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
|
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -100,13 +105,13 @@ public class PropertySourceProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertySource(org.springframework.core.env.PropertySource<?> propertySource) {
|
private void addPropertySource(PropertySource<?> propertySource) {
|
||||||
String name = propertySource.getName();
|
String name = propertySource.getName();
|
||||||
MutablePropertySources propertySources = this.environment.getPropertySources();
|
MutablePropertySources propertySources = this.environment.getPropertySources();
|
||||||
|
|
||||||
if (this.propertySourceNames.contains(name)) {
|
if (this.propertySourceNames.contains(name)) {
|
||||||
// We've already added a version, we need to extend it
|
// We've already added a version, we need to extend it
|
||||||
org.springframework.core.env.PropertySource<?> existing = propertySources.get(name);
|
PropertySource<?> existing = propertySources.get(name);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource rps ?
|
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource rps ?
|
||||||
rps.withResourceName() : propertySource);
|
rps.withResourceName() : propertySource);
|
||||||
|
@ -136,7 +141,8 @@ public class PropertySourceProcessor {
|
||||||
this.propertySourceNames.add(name);
|
this.propertySourceNames.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertySourceFactory instantiateClass(Class<? extends PropertySourceFactory> type) {
|
|
||||||
|
private static PropertySourceFactory instantiateClass(Class<? extends PropertySourceFactory> type) {
|
||||||
try {
|
try {
|
||||||
Constructor<? extends PropertySourceFactory> constructor = type.getDeclaredConstructor();
|
Constructor<? extends PropertySourceFactory> constructor = type.getDeclaredConstructor();
|
||||||
ReflectionUtils.makeAccessible(constructor);
|
ReflectionUtils.makeAccessible(constructor);
|
||||||
|
@ -147,4 +153,14 @@ public class PropertySourceProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the supplied exception can be ignored according to
|
||||||
|
* {@code ignoreResourceNotFound} semantics.
|
||||||
|
*/
|
||||||
|
private static boolean isIgnorableException(@Nullable Throwable ex) {
|
||||||
|
return (ex instanceof FileNotFoundException ||
|
||||||
|
ex instanceof UnknownHostException ||
|
||||||
|
ex instanceof SocketException);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2023 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.core.io.support;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link PropertySourceProcessor}.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 6.0.12
|
||||||
|
*/
|
||||||
|
class PropertySourceProcessorTests {
|
||||||
|
|
||||||
|
private static final String PROPS_FILE = ClassUtils.classPackageAsResourcePath(PropertySourceProcessorTests.class) + "/test.properties";
|
||||||
|
|
||||||
|
private final StandardEnvironment environment = new StandardEnvironment();
|
||||||
|
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
private final PropertySourceProcessor processor = new PropertySourceProcessor(environment, resourceLoader);
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void checkInitialPropertySources() {
|
||||||
|
assertThat(environment.getPropertySources()).hasSize(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorRegistersPropertySource() throws Exception {
|
||||||
|
PropertySourceDescriptor descriptor = new PropertySourceDescriptor(List.of(PROPS_FILE), false, null, DefaultPropertySourceFactory.class, null);
|
||||||
|
processor.processPropertySource(descriptor);
|
||||||
|
assertThat(environment.getPropertySources()).hasSize(3);
|
||||||
|
assertThat(environment.getProperty("enigma")).isEqualTo("42");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class FailOnErrorTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorFailsOnIllegalArgumentException() {
|
||||||
|
assertProcessorFailsOnError(IllegalArgumentExceptionPropertySourceFactory.class, IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorFailsOnFileNotFoundException() {
|
||||||
|
assertProcessorFailsOnError(FileNotFoundExceptionPropertySourceFactory.class, FileNotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertProcessorFailsOnError(
|
||||||
|
Class<? extends PropertySourceFactory> factoryClass, Class<? extends Throwable> exceptionType) {
|
||||||
|
|
||||||
|
PropertySourceDescriptor descriptor =
|
||||||
|
new PropertySourceDescriptor(List.of(PROPS_FILE), false, null, factoryClass, null);
|
||||||
|
assertThatExceptionOfType(exceptionType).isThrownBy(() -> processor.processPropertySource(descriptor));
|
||||||
|
assertThat(environment.getPropertySources()).hasSize(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class IgnoreResourceNotFoundTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresIllegalArgumentException() {
|
||||||
|
assertProcessorIgnoresFailure(IllegalArgumentExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresFileNotFoundException() {
|
||||||
|
assertProcessorIgnoresFailure(FileNotFoundExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresUnknownHostException() {
|
||||||
|
assertProcessorIgnoresFailure(UnknownHostExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresSocketException() {
|
||||||
|
assertProcessorIgnoresFailure(SocketExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresSupportedExceptionWrappedInIllegalStateException() {
|
||||||
|
assertProcessorIgnoresFailure(WrappedIOExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processorIgnoresSupportedExceptionWrappedInUncheckedIOException() {
|
||||||
|
assertProcessorIgnoresFailure(UncheckedIOExceptionPropertySourceFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertProcessorIgnoresFailure(Class<? extends PropertySourceFactory> factoryClass) {
|
||||||
|
PropertySourceDescriptor descriptor = new PropertySourceDescriptor(List.of(PROPS_FILE), true, null, factoryClass, null);
|
||||||
|
assertThatNoException().isThrownBy(() -> processor.processPropertySource(descriptor));
|
||||||
|
assertThat(environment.getPropertySources()).hasSize(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class IllegalArgumentExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
|
||||||
|
throw new IllegalArgumentException("bogus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FileNotFoundExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
|
||||||
|
throw new FileNotFoundException("bogus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UnknownHostExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
|
||||||
|
throw new UnknownHostException("bogus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SocketExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
|
||||||
|
throw new SocketException("bogus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WrappedIOExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) {
|
||||||
|
throw new IllegalStateException("Wrapped", new FileNotFoundException("bogus"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UncheckedIOExceptionPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) {
|
||||||
|
throw new UncheckedIOException("Wrapped", new FileNotFoundException("bogus"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
enigma = 42
|
Loading…
Reference in New Issue