Чтение поля содержащего реализации интерфейса

У меня есть объект с полем:

public List<Mod> mods;

Mod это интерфейс. Есть несколько классов, реализующих его.

Мой yaml выглядит так:

mods:
  mod1: # Идентификатор мода
    id: "Yaml test" # Данные мода
  mod2:
    type: SEMI

Идентификатор не совпадает с названием класса

Как я могу эффективно прочитать этот объект?


Ответы (1 шт):

Автор решения: Nowhere Man

Фактически содержимое yaml-файла соответствует не списку, а словарю (мапе) Map<String, Mod> mods, поэтому для решения данной проблемы есть два способа:

  1. Изменить Java-код, чтобы он соответствовал формату yaml-файла.
    Тогда можно будет извлечь коллекцию значений из словаря/мапы при помощи стандартного метода Map::values:
public Map<String, Mod> mods; // List<Mod> -> Map<String, Mod>

public List<Mod> modsAsList() {
    return mods == null ? null : new ArrayList<>(mods.values());
}
  1. Изменить структуру yaml-файла, чтобы она соответствовала списку List<Mod> (например, ключи mod1, mod2 станут комментариями):
mods:
  -
    #mod1
    id: Yaml test
  -
    #mod2
    type: SEMI

Обновление

Если требуется получить словарь классов экземпляров Mod на основании данных из yaml-файла, то следует создать новый экземпляр словаря с соответствующей типизацией и сгенерировать его на основании словаря Map<String, Mod>, используя к примеру "ленивую" загрузку:

public Map<String, Mod> mods; // первый вариант решения

private Map<String, Class<? extends Mod>> modClasses;

public Map<String, Class<? extends Mod>> getModClasses() {
    if (modClasses == null && mods != null) {
        modClasses = mods.entrySet()
            .stream() // Stream<Map.Entry<String, Mod>>
            .collect(Collectors.toMap(
                Map.Entry::getKey, e -> e.getValue().getClass()
            ));
    }
    return modClasses;
}
→ Ссылка