Как использовать пикокли для обработки опций с несколькими типами

Я конвертирую существующее приложение для использования picocli. Один из существующих вариантов выглядит так:

-t, --threads           [1, n] for fixed thread pool, 'cpus' for number of cpus, 'cached' for cached

Это позволяет параметру быть положительным целым числом или одной из пары специальных строк. Существующий код рассматривает ее как строку и, если это не одна из специальных строк, передает ее в Integer.parseInt.

Я могу сделать то же самое с пикокли, конечно, но мне было интересно, есть ли лучший способ справиться с этим. Например, что-то, что позволяет использовать несколько полей для одной и той же опции, при этом соответствующее поле заполняется в зависимости от того, что было передано? Это также может позволить мне использовать перечисление для возможных параметров строки.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
482
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Одна из идей состоит в том, чтобы создать для этого класс, например, ThreadPoolSize, который инкапсулирует либо фиксированное числовое значение, либо перечисление для динамических значений. Вам нужно будет создать собственный преобразователь для этого типа данных.

Затем вы можете определить параметр следующим образом:

@Option(names = { "-t", "--threads" }, converter = ThreadPoolSizeConverter.class,
  description = "[1, n] for fixed thread pool, 'cpus' for number of cpus, 'cached' for cached")
ThreadPoolSize threadPoolSize;

Пользовательский тип данных для размера пула потоков и преобразователя может выглядеть примерно так:

class ThreadPoolSize {
    enum Dynamic { cpus, cached }

    int fixed = -1;  // if -1, then use the dynamic value
    Dynamic dynamic; // if null, then use the fixed value
}

class ThreadPoolSizeConverter implements CommandLine.ITypeConverter<ThreadPoolSize> {

    @Override
    public ThreadPoolSize convert(String value) throws Exception {
        ThreadPoolSize result = new ThreadPoolSize();
        try {
            result.fixed = Integer.parseInt(value);
            if (result.fixed < 1) {
                throw new CommandLine.TypeConversionException("Invalid value " +
                        value + ": must be 1 or more.");
            }
        } catch (NumberFormatException nan) {
            try {
                result.dynamic = ThreadPoolSize.Dynamic.valueOf(
                        value.toLowerCase(Locale.ENGLISH));
            } catch (IllegalArgumentException ex) {
                throw new CommandLine.TypeConversionException("Invalid value " +
                        value + ": must be one of " + 
                        Arrays.toString(ThreadPoolSize.Dynamic.values()));
            }
        }
        return result;
    }
}

Спасибо - это лучше, чем просто использование String! Интересно, есть ли в picocli место для универсального составного типа — например, вы создаете класс, в котором есть поле для каждого возможного типа, и класс получает что-то вроде @Option(composite = true). Затем он автоматически пытается преобразовать arg в каждый тип поля в том порядке, в котором они определены, и останавливается в случае успеха. Внутренние поля также могут быть аннотированы, если они требуют пользовательских преобразований и т. д. Возможно, этот случай слишком редок, чтобы его стоило поддерживать напрямую.

marinier 23.12.2020 22:13

Моя интуиция подсказывает, что делать это в пользовательском преобразователе типов, как мы сделали здесь, чище, чем пытаться впихнуть это в библиотеку.

Remko Popma 24.12.2020 13:34

Другие вопросы по теме