Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jcommander support Enum #526

Open
jja725 opened this issue Oct 7, 2021 · 1 comment
Open

Jcommander support Enum #526

jja725 opened this issue Oct 7, 2021 · 1 comment

Comments

@jja725
Copy link

jja725 commented Oct 7, 2021

I try to create an abstract class with some common parameters so I can inherit from this class and create several similar parameters. But I'm struggling with the Jcommander with Enum types. The following code giving me the error. I'm wondering if no converter is specified for an enum type, does EnumConverter gets called?

public abstract class GeneralParameters<T extends Enum<T>> extends Parameters {
    @Parameter(names = {"--operation"}, description =
        "the operation to perform", required = true)
    public T mOperation;
}
com.beust.jcommander.ParameterException: Could not invoke null
    Reason: Can not set java.lang.Enum field alluxio.stress.GeneralParameters.mOperation to java.lang.String
	at com.beust.jcommander.Parameterized.set(Parameterized.java:273)
	at com.beust.jcommander.WrappedParameter.addValue(WrappedParameter.java:86)
	at com.beust.jcommander.WrappedParameter.addValue(WrappedParameter.java:74)
	at com.beust.jcommander.ParameterDescription.addValue(ParameterDescription.java:277)
	at com.beust.jcommander.JCommander.processFixedArity(JCommander.java:913)
	at com.beust.jcommander.JCommander.processFixedArity(JCommander.java:894)
	at com.beust.jcommander.JCommander.parseValues(JCommander.java:724)
	at com.beust.jcommander.JCommander.parse(JCommander.java:356)
	at com.beust.jcommander.JCommander.parse(JCommander.java:335)

I search online and try to add converter but doesn't know how to do so. (Need an interface for Enum with common fromString method)

public abstract class GeneralParameters<T extends Operation> extends Parameters {
    @Parameter(names = {"--operation"}, description =
        "the operation to perform for the stress bench", converter = OperationConverter.class, required = true)
    public T mOperation;

    public static class OperationConverter<S extends Operation> implements IStringConverter<S> {
        private final Class<S> clazz;

        protected OperationConverter(Class<S> clazz) {
            this.clazz = clazz;
        }

        @Override
        public S convert(String value) {

            return S.fromString(value, Class<T>);
        }
    }

Does anyone have any idea how to make it work?

@thnaeff
Copy link
Contributor

thnaeff commented Jan 30, 2022

If I see this correctly, because of type erasure it does not actually know the type of the enum (or the fact that it is an enum) once the code is compiled. Meaning what it actually is after compilation is public Object mOperation;

What you could try in your OperationConverter

if (clazz.isEnum()) // probably good to check to ensure it is an enum and throw an exception if not. You should get some safety with your initial approach with `T extends Enum<T>` though.

for (S element : clazz.getEnumConstants()) {
  if (value.equals(element.name()) 
    ...
}

but I am not sure what you would get provided to this constructor protected OperationConverter(Class<S> clazz), I would think that JCommander requires an empty constructor to create an instance. Again, JCommander would not know what type the enum is supposed to be due to type erasure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants