Skip to content

Feature: Support options of types without (String) constructor #40

@okorz001

Description

@okorz001

JewelCli 0.8.9 requires that the type of an option has a (String) constructor, but many value types do not meet this requirement.

Exception in thread "main" java.lang.ClassCastException: cannot convert class java.lang.String to interface java.nio.file.Path
	at com.lexicalscope.jewel.cli.ConvertTypeOfObject.convertValueTo(ConvertTypeOfObject.java:159)
	at com.lexicalscope.jewel.cli.ConvertTypeOfObject.convert(ConvertTypeOfObject.java:98)
	at com.lexicalscope.jewel.cli.ArgumentPresenterImpl.putValuesInMap(ArgumentPresenterImpl.java:79)
	at com.lexicalscope.jewel.cli.ArgumentPresenterImpl.presentArguments(ArgumentPresenterImpl.java:40)
	at com.lexicalscope.jewel.cli.AbstractCliImpl.parseArguments(AbstractCliImpl.java:42)

The workaround is to build an intermediate type that parses a String into the desired type, but since JewelCli also does not support Java 8 default methods (#38), this cannot be done transparently.

Other option libraries such as jopt-simple (see withValuesConvertedBy) allow a factory method to be registered in case a constructor is not available or is otherwise undesirable.

Here's two different ways to do this:

  1. Add a parser attribute to @Option that accepts a Class<? extends Function<String, ?>>. The main downside of this approach is that, as far as I know, we cannot guarantee the function return type matches the annotated method's return type at compile time. :( It can also cause some duplication if there are multiple arguments of the same type, but on the other hand it has the flexibility of allowing different parsers (or validators) for each argument as well.

  2. Add a method to either Cli or CliFactory to register a parser, e.g. <T> Cli<O> withParser(Class<T>, Function<String, T>). The downside of this is that it is not aligned with the rest of JewelCli's annotation-centric API.

I think the first approach is more desirable since it maintains API consistency and option parsing tends to happen very early in the application, lessening the pain of errors at runtime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions