How to get nested Spel expression based objects through @ConfigurationProperties in Spring Boot?

huangapple go评论125阅读模式
英文:

How to get nested Spel expression based objects through @ConfigurationProperties in Spring Boot?

问题

这是我的 application.yml 文件内容:

  1. translations:
  2. en:
  3. title: 'english'
  4. description: 'english text'
  5. fr:
  6. title: 'french'
  7. description: 'french text'
  8. de:
  9. title: 'german'
  10. description: 'french text'
  11. codes:
  12. GB:
  13. en: ${translations.en}
  14. CA:
  15. en: ${translations.en}
  16. fr: ${translations.fr}
  17. DE:
  18. en: ${translations.en}
  19. fr: ${translations.fr}
  20. de: ${translations.de}

现在考虑这段代码(为简洁起见,删除了不必要的 getter 方法,并且使用了 Project Lombok):

  1. @SpringBootApplication
  2. public class DemoApplication implements CommandLineRunner {
  3. // 内部类,但这些也可以放在外面
  4. @ConfigurationProperties
  5. @Getter
  6. @Component
  7. class Config {
  8. Map<String, Map<String, LanguageDTO>> codes;
  9. }
  10. @Data
  11. @AllArgsConstructor
  12. class LanguageDTO {
  13. String title;
  14. String description;
  15. }
  16. @Autowired
  17. Config config;
  18. public static void main(String[] args) {
  19. SpringApplication.run(DemoApplication.class, args);
  20. }
  21. @Override
  22. public void run(String... args) throws Exception {
  23. // 在下面的这行代码上出现了错误
  24. Map<String, Map<String, LanguageDTO>> codes = config.getCodes();
  25. }
  26. }

现在当我启动应用程序时,我会收到如下错误:

  1. APPLICATION FAILED TO START
  2. ***************************
  3. Description:
  4. Failed to bind properties under 'codes.gb.en' to com.example.demo.DemoApplication$LanguageDTO:
  5. Property: codes.gb.en
  6. Value: ${translations.en}
  7. Origin: class path resource [application.yml]:24:9
  8. Reason: No converter found capable of converting from type [java.lang.String] to type [com.example.demo.DemoApplication$LanguageDTO]
  9. Action:
  10. Update your application's configuration

我的需求是什么?

我希能够将 codes 读取为一个 Map<String, Map<String, LanguageDTO>>。也就是说,我应该能够执行 config.getCodes().get("GB").get("en") --> 这应该返回一个类型为 LanguageDTO 的数据。

英文:

This is in my application.yml

  1. translations:
  2. en:
  3. title: &#39;english&#39;
  4. description: &#39;english text&#39;
  5. fr:
  6. title: &#39;french&#39;
  7. description: &#39;french text&#39;
  8. de:
  9. title: &#39;german&#39;
  10. description: &#39;french text&#39;
  11. codes:
  12. GB:
  13. # I am assuming that en here will have an object with both title and description properties
  14. en: ${translations.en}
  15. CA:
  16. en: ${translations.en}
  17. fr: ${translations.fr}
  18. DE:
  19. en: ${translations.en}
  20. fr: ${translations.fr}
  21. de: ${translations.de}

Now consider this piece of code(removed unnecessary getters etc and also using project lombok for brevity)

  1. @SpringBootApplication
  2. public class DemoApplication implements CommandLineRunner {
  3. // Inner classes, but these can be outside as well
  4. @ConfigurationProperties
  5. @Getter
  6. @Component
  7. class Config {
  8. Map&lt;String, Map&lt;String, LanguageDTO&gt;&gt; codes;
  9. }
  10. @Data
  11. @AllArgsConstructor
  12. class LanguageDTO {
  13. String title;
  14. String description;
  15. }
  16. @Autowired
  17. Config config;
  18. public static void main(String[] args) {
  19. SpringApplication.run(DemoApplication.class, args);
  20. }
  21. @Override
  22. public void run(String... args) throws Exception {
  23. // Getting error on this line below
  24. Map&lt;String, Map&lt;String, LanguageDTO&gt;&gt; codes = config.getCodes();
  25. }
  26. }

Now when I start the app, I am getting an error like this:

  1. APPLICATION FAILED TO START
  2. ***************************
  3. Description:
  4. Failed to bind properties under &#39;codes.gb.en&#39; to com.example.demo.DemoApplication$LanguageDTO:
  5. Property: codes.gb.en
  6. Value: ${translations.en}
  7. Origin: class path resource [application.yml]:24:9
  8. Reason: No converter found capable of converting from type [java.lang.String] to type [com.example.demo.DemoApplication$LanguageDTO]
  9. Action:
  10. Update your application&#39;s configuration

What I want?

I want to be able to read codes as a Map&lt;String, Map&lt;String, LanguageDTO&gt;. That is, I should be able to do config.getCodes().get(&quot;GB&quot;).get(&quot;en&quot;) --> which should in turn have a data type of LanguageDTO.

答案1

得分: 1

我认为这是不可行的:Spring仅在application.yaml文件中支持简单的属性占位符(就我所知)。不过,你可以利用YAML格式的内置功能,使用锚点和别名:

  1. translations:
  2. en: &en
  3. title: '英文'
  4. description: '英文文本'
  5. fr: &fr
  6. title: '法文'
  7. description: '法文文本'
  8. de: &de
  9. title: '德文'
  10. description: '法文文本'
  11. codes:
  12. GB:
  13. en: *en
  14. CA:
  15. en: *en
  16. fr: *fr
  17. DE:
  18. en: *en
  19. fr: *fr
  20. 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:

  1. translations:
  2. en: &amp;en
  3. title: &#39;english&#39;
  4. description: &#39;english text&#39;
  5. fr: &amp;fr
  6. title: &#39;french&#39;
  7. description: &#39;french text&#39;
  8. de: &amp;de
  9. title: &#39;german&#39;
  10. description: &#39;french text&#39;
  11. codes:
  12. GB:
  13. en: *en
  14. CA:
  15. en: *en
  16. fr: *fr
  17. DE:
  18. en: *en
  19. fr: *fr
  20. 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.

huangapple
  • 本文由 发表于 2020年10月15日 02:34:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/64359514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定