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

Custom types on main parameters don't appear to work. (1.72) #375

Closed
Woodham opened this issue Jun 22, 2017 · 7 comments
Closed

Custom types on main parameters don't appear to work. (1.72) #375

Woodham opened this issue Jun 22, 2017 · 7 comments

Comments

@Woodham
Copy link
Contributor

Woodham commented Jun 22, 2017

My reduced test case is as follows:

public class Main {

    public static class CustomType {
        private String something;

        public CustomType(String something) {
            this.something = something;
        }
    }

    public static class CustomTypeConverter implements IStringConverter<CustomType> {
        @Override
        public CustomType convert(String value) {
            return new CustomType(value);
        }
    }
    
    @Parameters
    public static class ExampleCommandArgs {
        @Parameter(converter = CustomTypeConverter.class, required = true)
        public CustomType mainArg;

    }

    public static void main(String[] args) {
        JCommander.newBuilder()
                .addObject(new ExampleCommandArgs())
                .build()
                .parse(args);
    }
}

As far as I can see I've configured the converter properly, but the error I get is:

Exception in thread "main" com.beust.jcommander.ParameterException: Could not invoke null
    Reason: Can not set Main$CustomType field Main$ExampleCommandArgs.mainArg to java.lang.String
	at com.beust.jcommander.Parameterized.set(Parameterized.java:263)
	at com.beust.jcommander.JCommander$MainParameter.addValue(JCommander.java:101)
	at com.beust.jcommander.JCommander.parseValues(JCommander.java:773)
	at com.beust.jcommander.JCommander.parse(JCommander.java:340)
	at com.beust.jcommander.JCommander.parse(JCommander.java:319)
	at Main.main(Main.java:38)

Note I get the same error on main arguments on commands as well.

@Woodham Woodham changed the title Custom types on main parameters don't appear to work. Custom types on main parameters don't appear to work. (1.72) Jun 22, 2017
@cbeust
Copy link
Owner

cbeust commented Jun 22, 2017

Definitely looks like a bug, will take a look.

@cbeust
Copy link
Owner

cbeust commented Jun 23, 2017

So... not a bug.

First of all, the example above works if pasted verbatim in a Main.java file.

You will get the error you saw if your converter is a nested class, though:

class Main {
    class CustomTypeConverter... {
}

In this case, JCommander can't instantiate it since it needs to pass the instance of the enclosing class to it first. Admittedly, the error message should tell you that instead of failing the way it does right now.

And I'm actually considering adding support for this case.

In the meantime, can you confirm that your example above works?

@Woodham
Copy link
Contributor Author

Woodham commented Jun 24, 2017

Sorry, with that exact example I get the error posted above.

I tried moving the converter out of being a nested class but got the same error.

I've attached a full gradle project as an example. If you run ./gradlew assemble it should create a jar in the build/libs folder which you can try running, e.g. java -jar jcommander-example-1.0-SNAPSHOT.jar test

example.zip

@RealSkeptic
Copy link

Hi. I was about to post this same bug.

To be exact, custom types cannot be used in a main parameter, unless the main parameter is a list.

Here is an example that exhibits this problem:

package testing;

import java.nio.file.Path;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.converters.PathConverter;

public class JcommanderTest {

    @Parameter( converter = PathConverter.class )
    public Path filepath;
    
    public static void main(String[] args) {
        JcommanderTest cmd = new JcommanderTest();
        String[] argv = { "/tmp/file.txt" };
        
        JCommander.newBuilder().addObject(cmd).build().parse(argv);
        
        System.out.printf("The filepath is %s class %s%n", cmd.filepath, cmd.filepath.getClass().getName());
        
    }
}

The result is:

Exception in thread "main" com.beust.jcommander.ParameterException: Could not invoke null
    Reason: Can not set java.nio.file.Path field testing.JcommanderTest.filepath to java.lang.String
	at com.beust.jcommander.Parameterized.set(Parameterized.java:273)
	at com.beust.jcommander.JCommander$MainParameter.addValue(JCommander.java:101)
	at com.beust.jcommander.JCommander.parseValues(JCommander.java:771)
	at com.beust.jcommander.JCommander.parse(JCommander.java:342)
	at com.beust.jcommander.JCommander.parse(JCommander.java:321)
	at testing.JcommanderTest.main(JcommanderTest.java:18)

If I add names, or if I declare the parameter as List<Path> instead of Path, this works properly.

@juewe
Copy link
Contributor

juewe commented Aug 25, 2017

Same as #380 ?

@RealSkeptic
Copy link

@juewe Yep, that one seems to be a dupe.

@juewe
Copy link
Contributor

juewe commented Aug 27, 2017

Since this is a dupe of #380 and #380 is done with #390 one should close this?

@cbeust cbeust closed this as completed Aug 27, 2017
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

4 participants