英文:
How to get nested Spel expression based objects through @ConfigurationProperties in Spring Boot?
问题
这是我的 application.yml
文件内容:
translations:
en:
title: 'english'
description: 'english text'
fr:
title: 'french'
description: 'french text'
de:
title: 'german'
description: 'french text'
codes:
GB:
en: ${translations.en}
CA:
en: ${translations.en}
fr: ${translations.fr}
DE:
en: ${translations.en}
fr: ${translations.fr}
de: ${translations.de}
现在考虑这段代码(为简洁起见,删除了不必要的 getter 方法,并且使用了 Project Lombok):
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
// 内部类,但这些也可以放在外面
@ConfigurationProperties
@Getter
@Component
class Config {
Map<String, Map<String, LanguageDTO>> codes;
}
@Data
@AllArgsConstructor
class LanguageDTO {
String title;
String description;
}
@Autowired
Config config;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// 在下面的这行代码上出现了错误
Map<String, Map<String, LanguageDTO>> codes = config.getCodes();
}
}
现在当我启动应用程序时,我会收到如下错误:
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'codes.gb.en' to com.example.demo.DemoApplication$LanguageDTO:
Property: codes.gb.en
Value: ${translations.en}
Origin: class path resource [application.yml]:24:9
Reason: No converter found capable of converting from type [java.lang.String] to type [com.example.demo.DemoApplication$LanguageDTO]
Action:
Update your application's configuration
我的需求是什么?
我希能够将 codes
读取为一个 Map<String, Map<String, LanguageDTO>>
。也就是说,我应该能够执行 config.getCodes().get("GB").get("en")
--> 这应该返回一个类型为 LanguageDTO
的数据。
英文:
This is in my application.yml
translations:
en:
title: 'english'
description: 'english text'
fr:
title: 'french'
description: 'french text'
de:
title: 'german'
description: 'french text'
codes:
GB:
# I am assuming that en here will have an object with both title and description properties
en: ${translations.en}
CA:
en: ${translations.en}
fr: ${translations.fr}
DE:
en: ${translations.en}
fr: ${translations.fr}
de: ${translations.de}
Now consider this piece of code(removed unnecessary getters etc and also using project lombok for brevity)
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
// Inner classes, but these can be outside as well
@ConfigurationProperties
@Getter
@Component
class Config {
Map<String, Map<String, LanguageDTO>> codes;
}
@Data
@AllArgsConstructor
class LanguageDTO {
String title;
String description;
}
@Autowired
Config config;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Getting error on this line below
Map<String, Map<String, LanguageDTO>> codes = config.getCodes();
}
}
Now when I start the app, I am getting an error like this:
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'codes.gb.en' to com.example.demo.DemoApplication$LanguageDTO:
Property: codes.gb.en
Value: ${translations.en}
Origin: class path resource [application.yml]:24:9
Reason: No converter found capable of converting from type [java.lang.String] to type [com.example.demo.DemoApplication$LanguageDTO]
Action:
Update your application's configuration
What I want?
I want to be able to read codes as a Map<String, Map<String, LanguageDTO>
. That is, I should be able to do config.getCodes().get("GB").get("en")
--> which should in turn have a data type of LanguageDTO
.
答案1
得分: 1
我认为这是不可行的:Spring仅在application.yaml文件中支持简单的属性占位符(就我所知)。不过,你可以利用YAML格式的内置功能,使用锚点和别名:
translations:
en: &en
title: '英文'
description: '英文文本'
fr: &fr
title: '法文'
description: '法文文本'
de: &de
title: '德文'
description: '法文文本'
codes:
GB:
en: *en
CA:
en: *en
fr: *fr
DE:
en: *en
fr: *fr
de: *de
为使其工作,
LanguageDTO
类需要具有setter方法和默认构造函数。@AllArgsConstructor
不起作用。或者你可以尝试与constructor binding一起使用,尽管我不确定是否可行。
英文:
I don't think it's doable: Spring supports only simple property placeholders inside the application.yaml file (as far as I know). What you could do though, is leveraging YAML format built-in functionality, anchors and aliases:
translations:
en: &en
title: 'english'
description: 'english text'
fr: &fr
title: 'french'
description: 'french text'
de: &de
title: 'german'
description: 'french text'
codes:
GB:
en: *en
CA:
en: *en
fr: *fr
DE:
en: *en
fr: *fr
de: *de
> For it to work, the LanguageDTO
class needs to have setters and a default constructor. @AllArgsConstructor won't work. Alternatively you might try to get it work in conjunction with constructor binding, although I'm not sure if it's possible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论