英文:
@PropertySource(factory=...) breaks @SpringBootTest when loading META-INF/build-info.properties
问题
我正在尝试设置一个从 HOCON 语法的 .conf
文件加载的自定义 @ConfigurationProperties
类。
我有一个使用 @PropertySource(factory=TypesafePropertySourceFactory.class, value = "classpath:app.conf")
注解的类:
@Configuration
@ConfigurationProperties(value = "app.server")
@PropertySource(factory = TypesafePropertySourceFactory.class, value = "classpath:app.conf")
public class ServerProperties {
public int port;
}
还有一个简单的测试类:
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeTest {
@Test
public void someCoolTest() {/* ... */}
// ...
}
当我运行 JUnit 测试运行器时,我得到以下错误:
Caused by: com.typesafe.config.ConfigException$BadPath: path parameter: Invalid path 'spring.info.build.location:classpath:META-INF/build-info.properties': Token not allowed in path expression: ':' (you can double-quote this token if you really want it here)
at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:155) ~[config-1.4.0.jar:1.4.0]
at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:74) ~[config-1.4.0.jar:1.4.0]
at com.typesafe.config.impl.PathParser.parsePath(PathParser.java:61) ~[config-1.4.0.jar:1.4.0]
...
如果我取消注释 ServerProperties
类中的 @PropertySource
行,测试会正常进行。对我来说,我的自定义 PropertySourceFactory
会干扰默认的 .properties
文件解析过程,这看起来很奇怪。
PropertySource 和 Factory 类
// TypesafeConfigPropertySource.java
import com.typesafe.config.Config;
import org.springframework.core.env.PropertySource;
public class TypesafeConfigPropertySource extends PropertySource<Config> {
public TypesafeConfigPropertySource(String name, Config source) {
super(name, source);
}
@Override
public Object getProperty(String path) {
if (source.hasPath(path)) {
return source.getAnyRef(path);
}
return null;
}
}
// TypesafePropertySourceFactory.java
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.Objects;
public class TypesafePropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
Config config = ConfigFactory.load(Objects.requireNonNull(resource.getResource().getFilename())).resolve();
String safeName = name == null ? "typeSafe" : name;
return new TypesafeConfigPropertySource(safeName, config);
}
}
我是否遗漏了关于配置自定义属性资源工厂的基本知识,还是这是一个 bug?
版本信息
- Spring Boot 2.3.4
- JUnit Jupiter 5.6.2
英文:
I am trying to setup a custom @ConfigurationProperties
class loaded from a HOCON syntax .conf
file.
I have a Class annotated with @PropertySource(factory=TypesafePropertySourceFactory.class, value = "classpath:app.conf")
@Configuration
@ConfigurationProperties(value = "app.server")
@PropertySource(factory = TypesafePropertySourceFactory.class, value = "classpath:app.conf")
public class ServerProperties {
public int port;
}
and a simple test class:
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeTest {
@Test
public void someCoolTest() {/* ... */}
// ...
}
When i run my junit test runner, i get the following error:
Caused by: com.typesafe.config.ConfigException$BadPath: path parameter: Invalid path 'spring.info.build.location:classpath:META-INF/build-info.properties': Token not allowed in path expression: ':' (you can double-quote this token if you really want it here)
at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:155) ~[config-1.4.0.jar:1.4.0]
at com.typesafe.config.impl.PathParser.parsePathExpression(PathParser.java:74) ~[config-1.4.0.jar:1.4.0]
at com.typesafe.config.impl.PathParser.parsePath(PathParser.java:61) ~[config-1.4.0.jar:1.4.0]
...
If i uncomment the @PropertySource line on the ServerProperties
class, the tests proceed normally. It seems strange to me that my custom PropertySourceFactory
gets in the way of the default .properties
file resolution process.
PropertySource and Factory classes
// TypesafeConfigPropertySource.java
import com.typesafe.config.Config;
import org.springframework.core.env.PropertySource;
public class TypesafeConfigPropertySource extends PropertySource<Config> {
public TypesafeConfigPropertySource(String name, Config source) {
super(name, source);
}
@Override
public Object getProperty(String path) {
if (source.hasPath(path)) {
return source.getAnyRef(path);
}
return null;
}
}
// TypesafePropertySourceFactory.java
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.Objects;
public class TypesafePropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
Config config = ConfigFactory.load(Objects.requireNonNull(resource.getResource().getFilename())).resolve();
String safeName = name == null ? "typeSafe" : name;
return new TypesafeConfigPropertySource(safeName, config);
}
}
Am I missing something fundamental about configuring custom property resource factories, or is this a bug?
Versions
- Spring boot 2.3.4
- Junit Jupiter 5.6.2
答案1
得分: 0
也许您也可以像这里的答案建议的那样,使用ContextInitializer来解决这个问题:
链接:https://stackoverflow.com/questions/38803381/spring-environment-backed-by-typesafe-config/58789778#58789778
英文:
Maybe you can also solve it with the use of a ContextInitializer as suggested in the answer here:
答案2
得分: 0
TL;DR
如果您的自定义实现无法处理 path
,则返回 null
public class TypesafeConfigPropertySource extends PropertySource<Config> {
// ...
@Override
public Object getProperty(String path) {
try {
if (source.hasPath(path)) {
return source.getAnyRef(path);
}
} catch(ConfigException.BadPath ignore) {
}
return null;
}
// ...
}
解释
> 我正在做一些有根据的猜测,但从功能上看,代码的行为支持这一点
在这里,最可能的情况是解析顺序会考虑我们的自定义实现,而不是任何默认实现。我们实现中使用的方法将在任何包含 ":" 和 "[" 的路径上报错,因为错误发生在对路径存在性的检查中。
我只是简单地捕获了 BadPath
异常,以便捕捉任何问题,然后返回 null
来表示没有匹配。
英文:
TL;DR
Return null
if you cannot process the path
in your custom impl
public class TypesafeConfigPropertySource extends PropertySource<Config> {
// ...
@Override
public Object getProperty(String path) {
try {
if (source.hasPath(path)) {
return source.getAnyRef(path);
}
} catch(ConfigException.BadPath ignore) {
}
return null;
}
// ...
}
Explanation
> I am making educated guesses, but functionally this appears supported by the way the code behaves
the most likely scenario here is the resolution order will consider our custom implementation before any default implementation. The method used in our implementation will error out with any path containing a ":" and "[" as the error occurs in the check for the path's existence.
I'm simply wrapping the BadPath
exception in order to catch any problem and then returning null to signify no match.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论