1

I am trying to find the best solution to make my Java application configurable over the command line. The issue I am facing is that I need to configure complex nested structures.

Example

Consider the following structure (words starting with a capital are classes, indenting notates attributes)

  • InterfaceOptimizer
    • AbstractProblem
      • dimension
    • populationSize
    • numberOfRuns

The first thing I need to select from the command line is a class that implements InterfaceOptimizer (e.g. java App -O SomeOptimizer). The next thing to select would be the AbstractProblem which by itself takes another parameter dimension (e.g. java App -O SomeOptimizer -- -P ConcreteProblem.

The issue here is that some parameters are parameters for a specific class and depend on what parameter was first given. ConcreteProblem might take different parameters than OtherProblem.

Tested Libraries

I tested args4j and commons-cli, but those both fail when trying to do what I need.

WEKA (a popular machine learning tool) seems to have implemented a solution for this problem, but it basically requires each class to implement it's own CLI parser (and they seem to have issues with consistency).

Is there any good solution (existing library?) to this problem? What would be the recommended pattern be to solve this?

12
  • 1
    I don't know about easy, but you could create a LL(*) grammar and then use ANTLR. Commented Dec 10, 2013 at 15:32
  • 1
    We used to solve complex parameterlists for commandlinetools by using a config-file. In your case I would consider to use xml since you have a hierarchical structure. This solution is also more convenient for the user - compared to editing a complex parameter at the commandline and repeating this several times if you make mistakes ;-) Commented Dec 10, 2013 at 15:34
  • I'm not sure that there is an easy solution to your problem. I've solved this problem in the past using a mixture of carefully defined interfaces and/or abstract superclasses and the Reflection API. This allows you to bind parameters to method signatures. Commented Dec 10, 2013 at 15:35
  • @ElliottFrisch: Interesting, but I think the LL(*) would just allow me to implement a generic CLI parser and not one that knows about the specific class implementations/parameters. Commented Dec 10, 2013 at 15:37
  • 1
    Actually, that's just the parser... you're implementation can leverage the generator stage (or more likely, use an evaluator)! :) Commented Dec 10, 2013 at 15:52

3 Answers 3

1

I think you're probably going to have to just write the code that selects the right classes. After that, you can use reflection to put the values into the objects and/or validate that the command line options are appropriate. Annotations would help you out tremendously here, because you could use that to help drive the reflection engine, as well as for generating documentation e.g. command line help.

Sign up to request clarification or add additional context in comments.

Comments

0

Just an idea, but this looks a lot like deserializing an object graph to me. Java has built-in serialization/deserialization of object. E.g. to construct an object from an XML file:

FileInputStream is = new FileInputStream(new File("config.xml"));
XMLDecoder d = new XMLDecoder(is);
InterfaceOptimizer obj = (InterfaceOptimizer)d.readObject();

To get an initial config file (as a starting point that you could manually alter), you could create the object programmatically, then dump it to an XML file using this:

FileOutputStream os = new FileOutputStream(new File("config.xml"));
XMLEncoder e = new XMLEncoder(os);
e.writeObject(myOptimizerObject);

You would then have to pass only the config file on the command line.

Comments

0

I don't see how this CLI is very complex, unless I didn't understand fully. You want

java X classname problem dimension population numberruns

Now, even if the part

classname problem dimension

or just

problem dimension

can be repeated, it is quite easy:

  • First, take the population and numberofruns from the end and check for validity.
  • Check if the remaining arguments are a multiple of 3 (assuming classname problem dimension can be repeated).
  • For each 3 tuple of arguments, resolve and load the class, check if it accepts the given problem, and check the dimension argument. A simple way to do this would be to just call the constructor or some initialization code of that class, like so:

Code (to be refined):

try {
    IOptimizer io = (IOptimizer) Class.forName(args[n]).newInstance();
    io.init(args[n+1], args[n+2]);
}
catch (ClassNotFoundException ...) { ... }
catch (ClassCastException ...) { ... }
catch (InvalidArgumentException ...) { ... }

Note that if some Problem needs more than one paramter, you can implment like so:

 java X classname problem3 a,b,c population numbers

and then you can split the dimension parameter in the init() method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.