Search code examples
javapicocli

@Option with enum List does not accept candidates that ${COMPLETION-CANDIDATES} shows


I have an @Option with an enum java.util.List and picocli just does not accept candidates that the ${COMPLETION-CANDIDATES} shows.

The way how picocli shows and accepts values does not align with each other.

Code:

@CommandLine.Option(
    names = {"-c", "--columns-to-hide"},
    description = "Comma separated list of column names that won't be displayed"
            + "%nCandidates: ${COMPLETION-CANDIDATES}",
    split = ",")
final List<Header> columnsToHide = new ArrayList<>();

Rendered help:

-c, --columns-to-hide   Comma separated list of column names that won't be displayed
                        Candidates: PORTFOLIO, TICKER, TYPE, CREATED, VOLUME, PRICE, FEE, TRANSFER_ID

The following error appears when I try to use multiply candidates as it was shown in the help:

Command:

java -jar my.jar ... -i "PORTFOLIO, TICKER, TYPE"

Error:

Invalid value for option '--columns-to-hide' (<columnsToHide>): expected one of [PORTFOLIO, TICKER, TYPE, CREATED, VOLUME, PRICE, FEE, TRANSFER_ID] (case-sensitive) but was ' TICKER'

The issue is that the rendered help shows a comma + space separated list but the picocli parser only accepts a comma separated list without space.

This is accepted:

-i "PORTFOLIO,TICKER,TYPE"

This one shows an error:

-i "PORTFOLIO, TICKER, TYPE"

My requirement is to accept candidate list with AND without space as well and this bug confuses my users.

As a workaround, I can use a String as a type instead of List and split + trim the provided String but this makes my code not as elegant as it can be without this bug. Plus I need to check whether or not the provided list contains only valid enum values.

Have you ever faced this bug?

Can I instruct picocli somehow to use the value from thesplitwhen it renders the options?


Solution

  • Solution: Custom Type Converters

    public class HeaderConverter implements CommandLine.ITypeConverter<List<Header>> {
    
        @Override
        public List<Header> convert(String s) throws Exception {
            List<Header> headers = new ArrayList<>();
            var params = s.split(",");
            Arrays.stream(params).forEach(x -> headers.add(Header.valueOf(x.trim())));
            return headers;
        }
    }
    

    This works fine, but that would be great if picocli could show candidates properly, based on the split parameter.