【问题标题】:make picocli parse local date format让 picocli 解析本地日期格式
【发布时间】:2019-06-24 11:16:57
【问题描述】:

picocli 接受 2019-04-26 作为 Localdate 变量的输入,但它不接受德语日期格式 26.04.2019。
为此,您需要:

SimpleDateFormat 格式 = new SimpleDateFormat("dd.MM.yyyy",Locale.GERMANY);

如何告诉 picocli 使用此格式化程序而不依赖于美国日期输入?

【问题讨论】:

    标签: localdate picocli


    【解决方案1】:

    您可以为特定选项定义自定义type converter,也可以为特定类型的所有选项和位置参数全局定义。

    注册自定义转换器最紧凑的方法通常是使用 lambda 表达式:

    new CommandLine(new DateFormatDemo())
          .registerConverter(Date.class,
                             s -> new SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).parse(s))
          .execute(args);
    

    如果您需要为特定选项设置转换器,则需要定义一个类并在该选项的@Option(converter = X.class) 注释中指定该类。

    请注意,如果用户输入无效,则可以从 ITypeConverter.convert 方法中引发异常。 Picocli 将捕获此异常并向最终用户显示错误消息。

    例如:

    class StrictGermanDateConverter implements ITypeConverter<Date> {
        @Override
        public Date convert(String value) throws Exception {
            Date result = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).parse(value);
            if (result.getYear() < 0) {
                throw new IllegalArgumentException("year should be after 1900");
            }
            return result;
        }
    }
    

    下面是一个使用这个更严格的转换器来演示的例子:

    • 错误检查
    • 为所有 java.util.Date 选项注册一个全局类型转换器
    • 无效输入导致 picocli 显示错误消息,后跟使用帮助消息
    import picocli.CommandLine;
    import picocli.CommandLine.Command;
    import picocli.CommandLine.ITypeConverter;
    import picocli.CommandLine.Model.CommandSpec;
    import picocli.CommandLine.Option;
    import picocli.CommandLine.Spec;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    import java.util.Locale;
    
    @Command(name = "demo")
    public class DateFormatDemo implements Runnable {
    
        @Option(names = {"-d", "--date"}, description = "Date in German format `dd.MM.yyyy`",
                converter = StrictGermanDateConverter.class, paramLabel = "dd.MM.yyyy")
        Date specialDate;
    
        @Option(names = {"-x", "--default"}, paramLabel = "yyyy-MM-dd",
                description = "This option uses the default converter")
        Date defaultDate;
    
        @Spec CommandSpec spec;
    
        public void run() {
            List<String> args = spec.commandLine().getParseResult().originalArgs();
            System.out.printf("%s -> %s; %s%n", args, specialDate, defaultDate);
        }
    
        public static void main(String[] args) {
    
            // invalid input: shows error message and usage help
            new CommandLine(new DateFormatDemo()).execute("-d=55.55.55");
    
            // alternatively, register a global converter
            // for _all_ Date options
            new CommandLine(new DateFormatDemo())
                  .registerConverter(Date.class,
                       s -> new SimpleDateFormat("MMM.dd.yyyy", Locale.ITALIAN).parse(s))
                  .execute("-d=31.07.1969", "--default=Gennaio.01.2020");
        }
    }
    

    第一次调用无效输入 -d=55.55.55 打印以下输出:

    Invalid value for option '--date': cannot convert '55.55.55' to Date (java.lang.IllegalArgumentException: year should be after 1900)
    Usage: demo [-d=dd.MM.yyyy] [-x=yyyy-MM-dd]
      -d, --date=dd.MM.yyyy      Date in German format `dd.MM.yyyy`
      -x, --default=yyyy-MM-dd   This option uses the default converter
    

    第二次调用,我们通过 --default=Gennaio.01.2020 来确认全局类型转换器现在以我们的自定义意大利语格式处理日期,提供以下输出:

    [-d=31.07.1969, --default=Gennaio.01.2020] -> Thu Jul 31 00:00:00 JST 1969; Wed Jan 01 00:00:00 JST 2020
    

    【讨论】:

    • 这个答案对您有用吗?如果它解决了问题,请接受答案。如果是现在,请说明还有哪些工作要做。
    • 感谢您的详细评论。但是,看起来这意味着我们需要为每种日期格式提供一个单独的类型转换器类。其他 CLI 库提供处理程序/转换器参数(例如 args4j)来指定格式模式。缺少此功能会导致迁移工作量增加并降低灵活性。
    • @MRalwasser 我更新了我的答案。 Picocli 不需要完整的类:对于自定义日期转换器,一个 lambda 通常就足够了。示例:new CommandLine(new MyApp()).registerConverter(Date.class, s -&gt; new SimpleDateFormat("MMM.dd.yyyy", Locale.ITALIAN).parse(s)).execute("--date=Gennaio.01.2020")。 (另请参阅picocli-examples。)这能满足您的需求吗?
    • 感谢您的更新。然而,由于 lambda 表达式只是语法糖,它并没有多大帮助,因为我们仍然需要为每种可能的日期格式创建一个单独的转换器(类)并在 @Option 中引用它们。我可以忍受它,但是能够为转换器提供参数确实会简化事情(并且会在这个主题上将 picocli 带到与 args4j 相同的水平)。
    • 我查看了 Args4j,但找不到 DateConverter。也许您有不同的 CLI 库?你能指出一个具体的例子来说明如何在选项定义中指定格式模式吗?
    猜你喜欢
    • 1970-01-01
    • 2021-11-10
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-05
    • 2017-08-16
    相关资源
    最近更新 更多