#java #spring-boot #configurationproperties
Вопрос:
Я пытаюсь прочитать список элементов конфигурации из application.yaml
компонента конфигурации через @ConfigurationProperties
. Список может состоять из объектов с определенным базовым типом:
@ConfigurationProperties("myapp")
public class MyConfiguration {
private Set<Point> points;
}
public abstract class Point {
private String name;
}
public class QuantityPoint extends Point {
private Number value;
}
public class StatePoint extends Point {
private String state;
}
Вот пример application.yaml
, как я его себе представляю:
myapp:
points:
- name: foo
value: 5
- name: bar
state: bar
Я нашел несколько постов, которые, как я думал, решают именно этот вопрос, но до сих пор ничего не предлагалось. Я попытался поиграть с ConfigurationProperties("myapp.points")
подтипами Point
, но, как уже было сказано, ничего не сработало.
Честно говоря, мне интересно, как парсер должен уметь различать типы. Должно быть, не хватает чего-то вроде type
аргумента, аналогичного тому, как мы преобразуем сущности в json с помощью Джексона.
На данный момент я получаю экземпляры Point
(когда я удаляю abstract
модификатор) и поля value
и state
теряюсь.
Редактировать
Я думаю, что добился некоторого прогресса в выяснении того, что нужно сделать. По-видимому, Spring использует SnakeYaml для анализа файла, и эта библиотека использует теги yaml для указания информации о типе, чтобы мой yaml выглядел примерно так
myapp:
points:
- !!foo
name: foo
value: 5
- !!bar
name: bar
state: bar
Есть несколько встроенных тегов, но мне нужно будет зарегистрировать свои собственные. Я нашел информацию о том, как написать пользовательский конструктор путем расширения AbstractConstruct
, но я не смог найти ничего о том, как зарегистрировать это в экземпляре Yaml
, настроенном springboot.
Я, по крайней мере, на правильном пути здесь?
Редактировать
Я заметил, что ConstructorException
от snakeyaml приходит так рано в процессе запуска, что, вероятно, невозможно добавить мой SafeConstructor
в процесс:
@Component
public class FooConstructor extends SafeConstructor {
public FooConstructor() {
this.yamlConstructors.put(new Tag("!foo"), new ConstructFoo());
}
private class ConstructFoo extends AbstractConstruct {
@Override
public Object construct(Node node) {
String val = (String) constructScalar((ScalarNode) node);
System.out.println(val);
return null;
}
}
}
06:48:29.380 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application run failed
org.yaml.snakeyaml.constructor.ConstructorException: could not determine a constructor for the tag !state
in 'reader', line 5, column 5:
- !foo
Комментарии:
2. Пример в вашей ссылке преобразует строку «джон,2000» в объект сотрудника. Это не мой сценарий.
3. Ваш сценарий состоит в том, чтобы преобразовать a
Map<String, Object>
в aPoint
. Это не очень отличается4. Хм, это хороший аргумент. Никогда не думал об этом с такой точки зрения. Я попробую, спасибо!
5. Это
Converter<Map<String, Object>, Point>
никогда не называется