Java commons-cli, options with list of possible values - java

How can I make an option accept only some specified values like in the following example:
$ java -jar Mumu.jar -a foo
OK
$ java -jar Mumu.jar -a bar
OK
$ java -jar Mumu.jar -a foobar
foobar is not a valid value for -a

Since commons-cli doesn't support that directly, the simplest solution is probably to check the value of an option when you get it.

The other way can be to extend the Option class. At work we have made that:
public static class ChoiceOption extends Option {
private final String[] choices;
public ChoiceOption(
final String opt,
final String longOpt,
final boolean hasArg,
final String description,
final String... choices) throws IllegalArgumentException {
super(opt, longOpt, hasArg, description + ' ' + Arrays.toString(choices));
this.choices = choices;
}
public String getChoiceValue() throws RuntimeException {
final String value = super.getValue();
if (value == null) {
return value;
}
if (ArrayUtils.contains(choices, value)) {
return value;
}
throw new RuntimeException( value " + describe(this) + " should be one of " + Arrays.toString(choices));
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
return new EqualsBuilder().appendSuper(super.equals(o))
.append(choices, ((ChoiceOption) o).choices)
.isEquals();
}
#Override
public int hashCode() {
return new ashCodeBuilder().appendSuper(super.hashCode()).append(choices).toHashCode();
}
}

I've wanted this kind of behaviour before, and never came across a way to do this with an already provided method. That's not to say it doesn't exist. A kind of lame way, is to add the code yourself such as:
private void checkSuitableValue(CommandLine line) {
if(line.hasOption("a")) {
String value = line.getOptionValue("a");
if("foo".equals(value)) {
println("OK");
} else if("bar".equals(value)) {
println("OK");
} else {
println(value + "is not a valid value for -a");
System.exit(1);
}
}
}
Obviously there would be nicer ways to do this than the long if/else, possibly with an enum, but that should be all you'd need. Also I've not compiled this, but I reckon it should work.
This example also does not make the "-a" switch mandatory, since that wasn't specified in the question.

Related

Modify java method body with spoon

I am trying to refactor old SimpleFormController. I would like to replace getSuccessView() and gerFormView() calls with actual success view and form view Strings.
I went through https://spoon.gforge.inria.fr/first_transformation.html, it shows how to generate and add statements however I could not understand how to modify.
I have tried couple of things.
Replace statements with the getSuccessView() and getFormView() calls
public class SimpleFormControllerReplaceViewCall extends AbstractProcessor<CtMethod> {
MetaData meta;
String successView= "successView";
String formView = "formView";
public SimpleFormControllerReplaceViewCall(MetaData meta) {
this.meta = meta;
}
#Override
public boolean isToBeProcessed(CtMethod candidate) {
if(candidate.getBody() == null) { //Ignore abstract methods
return false;
}
String sourceCode;
try {
sourceCode = candidate.getBody()
.getOriginalSourceFragment()
.getSourceCode();
} catch (Exception e) {
return false;
}
return sourceCode.contains(getViewFunctionName(successView))
|| sourceCode.contains(getViewFunctionName(formView));
}
#Override
public void process(CtMethod method) {
Node beanNode = getBeanNode(method);
CtBlock<Object> body = getFactory().createBlock();
method.getBody().getStatements()
.stream()
.map(s -> {
Optional<String> sourceCode = getStatementSourceCode(s);
if(!sourceCode.isPresent()) {
return s.clone(); // Clone required to handle runtime error for trying attach a node to two parents
} else {
System.out.println("Modifying: " + method.getSignature());
String code = sourceCode.get();
code = replaceViewCalls(beanNode, code, successView);
code = replaceViewCalls(beanNode, code, formView);
return getFactory().createCodeSnippetStatement(code);
}
}).forEach(body::addStatement);
method.setBody(body);
}
private Optional<String> getStatementSourceCode(CtStatement s) {
String sourceCode = null;
try {
sourceCode = s.getOriginalSourceFragment()
.getSourceCode();
} catch (Exception e) {}
System.out.println(sourceCode);
if (sourceCode != null &&
(sourceCode.contains(getViewFunctionName(successView))
|| sourceCode.contains(getViewFunctionName(formView)))) {
sourceCode = sourceCode.trim();
if(sourceCode.endsWith(";"))
sourceCode = sourceCode.substring(0, sourceCode.length()-1);
return Optional.of(sourceCode);
} else {
return Optional.empty();
}
}
public String replaceViewCalls(Node beanNode, String code, String viewType) {
String getViewFunctionName = getViewFunctionName(viewType);
if (!code.contains(getViewFunctionName)) {
return code;
}
String view = AppUtil.getSpringBeanPropertyValue(beanNode, viewType);
return code.replaceAll(getViewFunctionName + "\\(\\)", String.format("\"%s\"", view));
}
public Node getBeanNode(CtMethod method) {
String qualifiedName = method.getParent(CtClass.class).getQualifiedName();
return meta.getFullyQualifiedNameToNodeMap().get(qualifiedName);
}
private String getViewFunctionName(String viewType) {
return "get" + viewType.substring(0, 1).toUpperCase() + viewType.substring(1);
}
}
This however adds unwanted at end of blocks if() {... }; This creates syntax errors when if {} else {} blocks contain return statement(s). Auto import is turned on and imports are not added when there is more one class with same name (e.g., Map is present in classpath from few libraries) - this is consistent with the document. Can this be avoided when refactoring code? Original java file has correct imports.
Another approach I tried is to directly manipulate the body as a whole.
#Override
public void process(CtMethod method) {
String code = method.getBody()
.getOriginalSourceFragment()
.getSourceCode();
Node beanNode = getBeanNode(method);
code = replaceViewCalls(beanNode, code, successView);
code = replaceViewCalls(beanNode, code, formView);
CtCodeSnippetStatement codeStatement = getFactory().createCodeSnippetStatement(code);
method.setBody(codeStatement);
}
this still has same auto import issue as first one. Apart from that it adds redundant curly braces, for examples
void method() { x=y;}
will become
void method() { {x=y;} }
That that will be pretty printed ofcourse.
Also javadocs for getOriginalSourceFragment() also has below warning
Warning: this is a advanced method which cannot be considered as part
of the stable API
One more thing I thought of doing is creating pattern for each type of usage of getSuccessView() like
viewName = getSuccessView();
return getSuccessView();
return ModelAndView(getSuccessView(), map); etc, however for that I will have to write a whole bunch of processors / templates.
Since it is simple replacement, easiest is do something like below
//Walk over all files and execute
Files.lines(Paths.get("/path/to/java/file"))
.map(l -> l.replaceAll("getSuccessView\\(\\)", "actualViewNameWithEscapedQuotes"))
.map(l -> l.replaceAll("getFormView\\(\\)", "actualViewNameWithEscapedQuotes"))
.forEach(l -> {
//write to file
});
Since I can avoid text manipulation with the help of spoon for things like changing modifiers, annotations, method name, annotations etc, I am hoping there should be a better way to modify the method body.
You should treat the processor input as an abstract syntax tree instead of a string:
public class SimpleFormControllerReplaceViewCall extends AbstractProcessor<CtMethod<?>> {
#Override
public boolean isToBeProcessed(CtMethod candidate) {
if(candidate.isAbstract()) { //Ignore abstract methods
return false;
}
return !candidate.filterChildren((CtInvocation i)->
i.getExecutable().getSimpleName().equals("getSuccessView")
|| i.getExecutable().getSimpleName().equals("getFormView")).list().isEmpty();
}
#Override
public void process(CtMethod<?> ctMethod) {
Launcher launcher = new Launcher();
CodeFactory factory = launcher.createFactory().Code();
List<CtInvocation> invocations = ctMethod.filterChildren((CtInvocation i)->
i.getExecutable().getSimpleName().equals("getSuccessView")
|| i.getExecutable().getSimpleName().equals("getFormView")).list();
for(CtInvocation i : invocations) {
if(i.getExecutable().getSimpleName().equals("getSuccessView")) {
i.replace(factory.createLiteral("successView"));
} else {
i.replace(factory.createLiteral("formView"));
}
}
}
}
Here the CtMethod AST is traversed in search for CtInvocation elements with the specified properties. The found elements are then replaced with new string literal elements.

How to check to see that a set of variables is not null before continuing

I have a class that extends org.apache.ant.tools.Task. This class has 5 variables which are set via public setters:
private String server;
private String username;
private String password;
private String appname;
private String version;
private String file;
And then there is a public execute() method which is invoked by ant:
public void execute() throws BuildException {
checkArgs()
... // my execute code goes here
}
Before execute runs, I want to check that none of my required variables are null and, if so, throw a BuildException() describing the problem, so the user back in ant has some idea what's wrong:
private void checkArgs() {
if (server == null) {
throw new BuildException("server cannot be null.");
}
if (username == null) {
throw new BuildException("username cannot be null.");
}
if (password == null) {
throw new BuildException("password cannot be null.");
}
if (file == null) {
throw new BuildException("file cannot be null.");
}
if (version == null) {
throw new BuildException("version cannot be null.");
}
}
Is there a less verbose way to do this? I hate the repeated use of if like this and if there's a more efficient way to do it, I'd love to see it. I can just imagine how it would look if I had, say, 20 different variables I need to check before execute() can run.
What is a good method for validating large numbers of different variables as a precursor continuing code execution or throwing a useful error message?
You could store the args in a HashMap<String, String> argMap, mapping the argument names to their values. Adjust your getters/setters accordingly. Then:
for (String key : argMap.keySet()) {
if (argMap.get(key) == null) {
throw new BuildException(key + " cannot be null.");
}
}
A little improvement could be achieved by using asserts:
public void execute()
throws BuildException
{
assert server!=null : "server cannot be null";
assert version!=null : "version cannot be null";
...
}
... And then running ant always with the -ea JVM option (Enable Asserts).
Yes, you still have to code one assert by variable, but at least it would be just one line per one of them.
If you prefer not to add the Map (as in Claudiu answer), you could use reflection:
private void checkArgs() throws BuildException, IllegalAccessException {
for (Field field: this.getClass().getDeclaredFields()) {
if (field.get(this) == null) {
throw new BuildException(field.getName() + " cannot be null.");
}
}
}
but pay attention: the getDeclaredFields() will return all the fields of the class (either private, protected or public).

java getting concept of OOP right

hi guys I already searched a lot but weren't really satisfied with what I found. hope it's the right place to ask this question.
I'm doing Java now for a small amount of time (changed from C) and have problems of getting a grip of how to structure my code best for OOP.
let's give a simple example:
If I'm using some predefined strings (let's say e.g. filepaths or error messages) I'm currently creating an own class doing something like:
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
Would it be better to create a Map, add everything to it and get it by key?
Or am I doing it completely wrong?
Second example:
let's say I return an error string somewhere
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
And anywhere else in my program I'm checking for the return value:
if (!string.equals("I HAVE AN ERROR")) {
//do something
}
else {
// handle error
}
that's obviously a bad way having to change the code twice once the error message changes. and yeah, I could define the error string the same way I'm doing it in the first example but as I'm not satisfied with that one either I'm reaching a dead end.
would be glad to hear some of your suggestions how to properly do OOP !
First example :
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
In this case, no need to create a Map. That is the right way to do it. Just note that the libPath would be better defined like this :
private static final Path libPath = Paths.get("this", "is", "a", "path");
(The class Path exists since Java 7, current version is Java 8)
Second example:
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
No : Never return error codes in Java. Prefer using an exception.
Example :
public class ElementNotFoundException extends Exception {
...
}
public String getSomething() {
if (something == null) {
throw new ElementNotFoundException();
} else {
return something;
}
}
Then, you handle the exception like this :
try {
myObject.getSomething();
} catch(ElementNotFoundException e) {
//handle error
}
For the first example, take a look at Internationalization: http://docs.oracle.com/javase/tutorial/i18n/
You can use statics or maps, but sooner or later you will need to show the messages in several languages.
For the second example, it's better to use Exceptions as they are intended to be used when an abnormal condition (like an error) happens.
Anyway, with Exceptions take care not to use it as flow control structures: Why not use exceptions as regular flow of control?
Here are some examples for handling constants throug out your code:
1. Class
public final class MyConstants {
public static final int ERROR_CODE = -1;
}
if (getSomething() == MyConstants.ERROR_CODE) {
// ...
}
2. Interface
public interface MyConstantsHolder {
int ERROR_CODE = -1;
}
public MyClass implements MyConstantsHolder {
public void myMethod() {
if (getSomething() == ERROR_CODE) {
// ...
}
}
}

Java - Input Verifier

I was just creating this specific but I was a little confused on documenting this. Am just stuck on explaining what the last couple of lines do :
class MyVerifier extends InputVerifier {
public boolean verify(JComponent input) {
if (input==id) {
return validId();
}
else if (input==name) {
return validName();
}
return false;
}
public boolean validId() {
boolean status;
String theID = id.getText();
Pattern pattern = Pattern.compile("\\d{8}");
Matcher matcher = pattern.matcher(theID);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
public boolean validName() {
boolean status;
String theName = name.getText();
Pattern pattern = Pattern.compile("[A-za-z0-9 ]+");
Matcher matcher = pattern.matcher(theName);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
}
COULD YOU EXPLAIN THESE SPECIFIC LINES HERE ONE BY ONE ?
/**
* #param o the object corresponding to the user's selection
*/
#Override
public void tell(Object o) { -- Where has this come from ?
deptCode.setText(o.toString());
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == submit) {
MyVerifier test = new MyVerifier();
if (Staff.getStaff(id.getText()) == null && test.verify(id) &&
test.verify(name)) {
System.out.println("YAY");-- What is this doing
}
else if (!(Staff.getStaff(id.getText()) == null)) {
String errorMessage = "ID EXISTS: " + Staff.getStaff(id.getText()).toString(); -- What is this doing
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error",
JOptionPane.WARNING_MESSAGE);-- What is this doing
}
else {
System.out.println("Woops.");
}
}
else if (e.getSource() == clear) {
id.setText(null);
deptCode.setText(null);
name.setText(null);
}
}
public static void main(String[] args) {
Registration test = new Registration();
}
}
Now that you understand what you're trying to accomplish with this program, start from a clean slate (using your first attempt as an example if necessary). It's often easier to start over than to fix a program.
It appears that your public void tell(Object o) method is setting a String with the value of the object passed. Because you haven't shown us what your using it for, though, it's impossible for us to know for sure. On the other hand, your other problems are fairly clear:
System.out.println("YAY");
It appears that Staff.getStaff(id.getText) is checking either a String or a text file for a list of names and id's. This statement prints "YAY" only if there hasn't previously been created a staff member with the provided id and name. But since you also haven't shown us where those variables are, this is only my best guess.
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error", JOptionPane.WARNING_MESSAGE);
This displays a JOptionPane warning message if there is already a staff member with the given id or name. Obviously, you cannot create an account that someone else has, so this JOptionPane displays an error message if this is, indeed, the case.

How can I provide a pseudo file system for r.js?

Ok, so r.js can run on Rhino. Which is great.
To do the stuff it needs to do.
On rhino it basically uses java.io.File, java.io.FileOutputStream and java.io.FileInputStream to achieve the filesystem modifications that it needs to do.
(Background: I am working on delivering a better development experience for Maven based Java/Javascript developers. Being Maven, there is the power of convention and the power of being opinionated. You can see the progress at jszip.org.)
So what I want to do is have the on-disk structure appear by magic as a virtual file system.
So on disk we will have a structure like so:
/
/module1/src/main/js/controllers/controller.js
/module2/src/main/js/models/model.js
/module3/src/main/js/views/view.js
/webapp/src/build/js/profile.js
/webapp/src/main/js/main.js
/webapp/src/main/webapp/index.html
The /webapp/src/build/js/profile.js should look something like this:
({
appDir: "src",
baseUrl:".",
dir: "target",
optimize: "closure",
modules:[
{
name:"main"
}
]
})
Such that
when r.js asks for new File("src/main.js") I will actually give it new File("/webapp/src/main/js/main.js")
when it asks for new File("profile.js") I will give it new File("/webapp/src/build/js/profile.js")
when it asks for new File("controllers/controller.js") I will give it new File("/module1/src/main/js/controllers/controller.js")
when it asks for new File("target") I will give it new File("/webapp/target/webapp-1.0-SNAPSHOT").
I have no issue writing the three mock classes required, i.e. the ones to use in place of java.io.File, java.io.FileInputStream and java.io.FileOutputStream,
Some questions such as this have answers that point to things like ClassShutter, which I can see I could use like this:
context.setClassShutter(new ClassShutter() {
public boolean visibleToScripts(String fullClassName) {
if (File.class.getName().equals(fullClassName)) return false;
if (FileOutputStream.class.getName().equals(fullClassName)) return false;
if (FileInputStream.class.getName().equals(fullClassName)) return false;
return true;
}
});
To hide the original implementations.
The problem is then getting Rhino to resolve the sandboxed equivalents... I keep on getting
TypeError: [JavaPackage java.io.File] is not a function, it is object.
Even if I prefix the call with a prior execution of java.io.File = org.jszip.rhino.SandboxFile map my sandboxed implementation over the now missing java.io.File
I could even consider using search and replace on the loaded r.js file just prior to compiling it... but I feel there must be a better way.
Does anyone have any hints?
Ok, after much experimentation, this seems to be the way to do this:
Scriptable scope = context.newObject(global);
scope.setPrototype(global);
scope.setParentScope(null);
NativeJavaTopPackage $packages = (NativeJavaTopPackage) global.get("Packages");
NativeJavaPackage $java = (NativeJavaPackage) $packages.get("java");
NativeJavaPackage $java_io = (NativeJavaPackage) $java.get("io");
ProxyNativeJavaPackage proxy$java = new ProxyNativeJavaPackage($java);
ProxyNativeJavaPackage proxy$java_io = new ProxyNativeJavaPackage($java_io);
proxy$java_io.put("File", scope, get(scope, "Packages." + PseudoFile.class.getName()));
proxy$java_io.put("FileInputStream", scope,
get(scope, "Packages." + PseudoFileInputStream.class.getName()));
proxy$java_io.put("FileOutputStream", scope,
get(scope, "Packages." + PseudoFileOutputStream.class.getName()));
proxy$java.put("io", scope, proxy$java_io);
scope.put("java", scope, proxy$java);
There is a helper method:
private static Object get(Scriptable scope, String name) {
Scriptable cur = scope;
for (String part : StringUtils.split(name, ".")) {
Object next = cur.get(part, scope);
if (next instanceof Scriptable) {
cur = (Scriptable) next;
} else {
return null;
}
}
return cur;
}
And where ProxyNativeJavaPackage is something like
public class ProxyNativeJavaPackage extends ScriptableObject implements Serializable {
static final long serialVersionUID = 1L;
protected final NativeJavaPackage delegate;
private final Map<String, Object> mutations = new HashMap<String, Object>();
public ProxyNativeJavaPackage(NativeJavaPackage delegate) {
delegate.getClass();
this.delegate = delegate;
}
#Override
public String getClassName() {
return delegate.getClassName();
}
#Override
public boolean has(String id, Scriptable start) {
return mutations.containsKey(id) ? mutations.get(id) != null : delegate.has(id, start);
}
#Override
public boolean has(int index, Scriptable start) {
return delegate.has(index, start);
}
#Override
public void put(String id, Scriptable start, Object value) {
mutations.put(id, value);
}
#Override
public void put(int index, Scriptable start, Object value) {
delegate.put(index, start, value);
}
#Override
public Object get(String id, Scriptable start) {
if (mutations.containsKey(id)) {
return mutations.get(id);
}
return delegate.get(id, start);
}
#Override
public Object get(int index, Scriptable start) {
return delegate.get(index, start);
}
#Override
public Object getDefaultValue(Class<?> ignored) {
return toString();
}
#Override
public String toString() {
return delegate.toString();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof ProxyNativeJavaPackage) {
ProxyNativeJavaPackage that = (ProxyNativeJavaPackage) obj;
return delegate.equals(that.delegate) && mutations.equals(that.mutations);
}
return false;
}
#Override
public int hashCode() {
return delegate.hashCode();
}
}
That still leaves the original classes at Packages.java.io.File etc, but for the r.js requirement this is sufficient, and it should be possible for others to extend this trick to the general case.

Categories