Args4j の EnumOptionHandler の使い方を記載します。


Args4j の version

'2.33'使用しています。

// https://mvnrepository.com/artifact/args4j/args4j
compile group: 'args4j', name: 'args4j', version: '2.33'


使い方

Option アノテーションを使用する場合は、以下のように記載します。

    @Option(name = "-format", usage = "Format of output ", metaVar = "[console or json]")
    private Format format = Format.CONSOLE;
ポイントは以下の2点です。

  • Field の型を指定したい Enum にする。
  • Handler は指定しない。

Handler を指定するとどうなるか?

handler を指定すると以下のように書けます。

    @Option(name = "-format", usage = "Format of output ", metaVar = "[console or json]", handler = EnumOptionHandler.class)
    private Format format = Format.CONSOLE;

この状態で Command を実行すると、以下のエラーが発生します。

Caused by: java.lang.IllegalArgumentException: class org.kohsuke.args4j.spi.EnumOptionHandler does not have the proper constructor
        at org.kohsuke.args4j.OptionHandlerRegistry.getConstructor(OptionHandlerRegistry.java:111) ~[args4j-2.33.jar!/:na]
        at org.kohsuke.args4j.OptionHandlerRegistry.access$000(OptionHandlerRegistry.java:43) ~[args4j-2.33.jar!/:na]
        at org.kohsuke.args4j.OptionHandlerRegistry$DefaultConstructorHandlerFactory.<init>(OptionHandlerRegistry.java:217) ~[args4j-2.33.jar!/:na]
        at org.kohsuke.args4j.OptionHandlerRegistry.createOptionHandler(OptionHandlerRegistry.java:188) ~[args4j-2.33.jar!/:na]

Args4j には、handler を登録する機能があり、試しに Enum のHanlder を登録してみたのですが、結果は変わりませんでした。

    // registerHandler
    OptionHandlerRegistry.OptionHandlerFactory factory = (parser, o, setter) -> {
        // infer the type
        Class<?> t = setter.getType();
        return new EnumOptionHandler(parser,o,setter,t);
    };
    OptionHandlerRegistry.getRegistry().registerHandler(Format.class, factory);


OptionHandlerRegistry#createOptionHandler() の動作について

以下、args4j/OptionHandlerRegistry.java at master · kohsuke/args4j createOptionHandler抜粋です。
指定されたアノテーション、パラメータの型を元に、使用する Handler取得する処理になります。

   /**
     * Creates an {@link OptionHandler} that handles the given {@link Option} annotation
     * and the {@link Setter} instance.
     */
    @SuppressWarnings("unchecked")
    protected OptionHandler createOptionHandler(CmdLineParser parser, OptionDef o, Setter setter) {
        checkNonNull(o, "CmdLineParser");
        checkNonNull(o, "OptionDef");
        checkNonNull(setter, "Setter");

        Class<? extends OptionHandler> h = o.handler();
        if(h==OptionHandler.class) {
            // infer the type
            Class<?> t = setter.getType();

            // enum is the special case
            if(Enum.class.isAssignableFrom(t))
                return new EnumOptionHandler(parser,o,setter,t);

            OptionHandlerFactory factory = handlers.get(t);
            if (factory==null)
                throw new IllegalAnnotationError(Messages.UNKNOWN_HANDLER.format(t));

            return factory.getHandler(parser, o, setter);
        } else {
            // explicit handler specified
            return new DefaultConstructorHandlerFactory(h).getHandler(parser, o, setter);
        }
    }

OptionHalder を指定すると、else のほうに処理が流れて、EnumOptionHandler は、Constructor の引数が4つなので、DefaultConstructorHandlerFactory getHandler メソッドでは、インスタンス化できずエラーになるようです。

最初に、handler を指定する形式で実装して、エラーが出てはまってしまいました。
以上です。

コメント