Can Apache Commons CLI options parser ignore unknown command-line options? - java

I am writing a Java application that takes command line arguments which are processed using Apache Commons CLI with the GnuParser. For reasons that are not interesting to get into, I would like it to silently ignore unknown command line options instead of throwing a ParseException but I don't see a way to do that. I see that there is a stopAtNonOption boolean option on GnuParser.parse() but what I want is more like ignoreAtNonOption where it will keep processing options after encountering an unknown token.
I could implement my own parser to accomplish this but I'm surprised there isn't this functionality built in so I thought I'd check before going down that road.
Example code for what I'm talking about:
try {
CommandLine commandLine = parser.parse(options, args);
// stopAtNonOption set to true (below) is also not what I want
// CommandLine commandLine = parser.parse(options, args, true);
} catch (ParseException e) {
LOG.error("error parsing arguments", e);
throw new RuntimeException(e);
}

This works for me (other parsers can be derived, too):
public class ExtendedGnuParser extends GnuParser {
private boolean ignoreUnrecognizedOption;
public ExtendedGnuParser(final boolean ignoreUnrecognizedOption) {
this.ignoreUnrecognizedOption = ignoreUnrecognizedOption;
}
#Override
protected void processOption(final String arg, final ListIterator iter) throws ParseException {
boolean hasOption = getOptions().hasOption(arg);
if (hasOption || !ignoreUnrecognizedOption) {
super.processOption(arg, iter);
}
}
}

As mentioned in a comment, the accepted solution is no more suitable because the processOption method has been deprecated and removed.
Here's my solution:
public class ExtendedParser extends DefaultParser {
private final ArrayList<String> notParsedArgs = new ArrayList<>();
public String[] getNotParsedArgs() {
return notParsedArgs.toArray(new String[notParsedArgs.size()]);
}
#Override
public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
if(stopAtNonOption) {
return parse(options, arguments);
}
List<String> knownArguments = new ArrayList<>();
notParsedArgs.clear();
boolean nextArgument = false;
for (String arg : arguments) {
if (options.hasOption(arg) || nextArgument) {
knownArguments.add(arg);
} else {
notParsedArgs.add(arg);
}
nextArgument = options.hasOption(arg) && options.getOption(arg).hasArg();
}
return super.parse(options, knownArguments.toArray(new String[knownArguments.size()]));
}
}
Compared with the solution proposed by Pascal, it also checks for options with arguments and it keeps not parsed args in a separate list.

This is not possible with Commons CLI. But there may be another way to achieve the result you expect if you give more details of your use case.

I am a very bad developer, and I do this to break the code:
public class EasyPosixParser extends PosixParser {
#Override
protected void processOption(String arg, ListIterator iter) throws ParseException
{
try {
super.processOption(arg, iter);
} catch (ParseException e) {
// do nothing
}
}
}
in your main code, you do:
CommandLineParser commandlineParser = new EasyPosixParser();

Related

Renaming classes, including inner classes using ByteBuddy

I am trying to use ByteBuddy to rename all classes during the process-classes phase in a maven plugin. However despite many tries I am stuck on renaming the inner class. This is my last attempt:
String className = classNameOfFile(root, file);
try {
Class<?> clazz = cl.loadClass(className);
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
return;
}
var builder = new ByteBuddy().rebase(clazz).name(className + "Impl");
var unloaded = builder.make();
var loaded = unloaded.load(cl);
unloaded.saveIn(root);
Queue<Class<?>> queue = new LinkedList<>(Arrays.stream(clazz.getDeclaredClasses()).toList());
while (!queue.isEmpty()) {
var innerClass = queue.poll();
String name = innerClass.getSimpleName();
new ByteBuddy().rebase(innerClass).innerTypeOf(loaded.getLoaded()).name(className+"Impl$"+name+"Impl").make().saveIn(root);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
In here the top level class is changed successfully, however the inner class is not doesn't get defined and gives the following error:
Constructor public dev.rvr.MainImpl$CoolImpl() defines an illegal receiver class dev.rvr.Main
For reference, this is the class it is trying to change:
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
public TestingThing getTestingThing() {
return new TestingThing();
}
public Cool getCool() {
return new Cool();
}
public static class Cool{
public void cool(){
System.out.println("Cool");
}
public void cool2(){
System.out.println("Cool2");
}
public void cool3(){
System.out.println("Cool3");
}
}
}
I hope anyone can help me solving this issue, thanks in advance!
Byte Buddy is not a good tool for this. As Holger states in the comment, you need to change all classes that reference it in any way.
ASM has a Renamer for this purpose. You would need to use this. If you want to use Byte Buddy's build tool infrastructure, you can register such a transformer via visit on the builder API.

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.

TypeMismatch in PropertyEditorSupport

I'm afraid I don't fully understand how to use PropertyEditorSupport in Spring.
public class IntegerFormat extends PropertyEditorSupport
{
#Override
public void setAsText(String text) throws IllegalArgumentException
{
try
{
int v = Integer.parseInt(text);
super.setValue(v);
}
catch(Exception ex)
{
super.setValue(null); // TypeMismatch
}
}
}
In the code snippet above how am I supposed to indicate type mismatch occurred?
If I do setValue(null) type mismatch will be confused with the case in which the parameter is not provided at all.
There are two solutions
Ideally you should go for client side validation using JavaScript
Using typeMismatch.java.lang.Integer
Else you can go for server side spring validation
public static boolean isParsable(String input){ boolean parsable = true; try{ Integer.parseInt(input); }catch(NumberFormatException e){ parsable = false; } return parsable; }

Java: Use the same code with two different versions of a dependent class

Consider a Java class Foo that uses a library Bar. Foo should be distributed as a binary .class file and use the version of Bar that is already existing on a clients classpath.
There are two different versions of Bar that only differ in its method signatures. Foo should be compatible with both of them.
Example code:
public class Foo {
public static void main(String[] args){
Bar.librarycall("hello from foo");
//or
Bar.librarycall("hello from foo",1);
}
}
//v1
public class Bar {
public static void librarycall(String argument){
System.out.println("Bar1: " + argument);
}
}
//v2
public class Bar {
public static void librarycall(String argument,int i){
for(int j = 0; j < i; j++)
System.out.println("Bar2: " + argument);
}
}
I want to avoid reflection if possible. How would you propose to create a class Foo that is compatible with both versions of Bar?
[Edit]
This problem originates in a project I am working on. Bar corresponds to an external library I am using but cannot be modified for the code to work (I don't have the source code and the license doesn't allow modifications).
A refelective solution.
Class<?> c;
try {
c = Class.forName("Bar");
Method meths[] = c.getMethods();
Method v1method = null;
Method v2method = null;
for(Method m:meths) {
if(!m.getName().equals("librarycall")) continue;
if(!Modifier.isStatic(m.getModifiers())) {
System.out.println("Should be static");
continue;
}
Class<?> params[] = m.getParameterTypes();
if(params.length == 1 && params[0].equals(String.class) )
v1method = m;
if(params.length == 2 && params[0].equals(String.class) && params[1].equals(Integer.TYPE) )
v2method = m;
}
if(v2method!=null) {
v2method.invoke(null,"V2",5);
}
else if(v1method!=null) {
v1method.invoke(null,"V1");
}
else
System.out.println("No method found");
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
You could use c = Bar.class; or if you already have an instance bar of Bar c = bar.getClass(). The invoke syntax is for static methods if its non static you need v1method.invoke(bar,"V1");.
Reflection does seem like the simplest way. The alternative would be to try calling the second version and catch a NoSuchMethodException.
public class Foo {
public static void main(String[] args){
try {
Bar.librarycall("hello from foo",1);
catch(NoSuchMethodException e) {
Bar.librarycall("hello from foo");
}
}
This is ugly, and slower, use Reflection its what its there for.
It sounds like this one task that is handled by the strategy pattern.
I'm assuming that:
You cannot change any of the versions of the Bar class files
You have the ability to write new Foo files
For some reason, you really want to avoid using Reflection
The two Bar files have the same package name
You may need to distribute two versions of the Foo class, as mentioned by JB Nizet in the comment to your question.

Better way to write this Java code? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
public void handleParsedCommand(String[] commandArr) {
if(commandArr[0].equalsIgnoreCase("message")) {
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
MachatServer.sendMessage(target, this.conId, message);
} else if(commandArr[0].equalsIgnoreCase("quit")) {
// Tell the server to disconnect us.
MachatServer.disconnect(conId);
} else if(commandArr[0].equalsIgnoreCase("confirmconnect")) {
// Blah blah and so on for another 10 types of command
} else {
try {
out.write("Unknown: " + commandArr[0] + "\n");
} catch (IOException e) {
System.out.println("Failed output warning of unknown command.");
}
}
}
I have this part of my server code for handling the types of messages. Each message contains the type in commandArr[0] and the parameters in the rest of commandArr[]. However, this current code, while working seems very unelegant. Is there a better way to handle it? (To the best of my knowledge, String values can't be used in switch statements, and even then, a switch statement would only be a small improvement.
I'd refactor this using the Command Design Pattern.
Basically each of your commands, message, quit, confirmconnect and a default will have a class implementation and will implement the Command Interface.
/*the Command interface*/
public interface ICommand {
void execute(String[] commandArr);
}
public class Message implements ICommand {
void execute(String[] commandArr) {
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
MachatServer.sendMessage(target, this.conId, message);
}
}
//same type of class for other commands
public class CommandManager {
public ICommand getCommand(String commandName) {
//store all the commands in a hashtable.
//Pull them out by name as requested.
}
//Esko's suggestion from comments
public static void executeImmediately(String[] commandArr) {
getCommand(commandArr[0]).execute(commandArr);
}
}
public void handleParsedCommand(String[] commandArr) {
ICommand command = CommandManager.getCommand(commandArr[0]);
command.execute(commandArr);
//or Esko
CommandManager.executeImmediately(commandArr);
}
Here are two variants using enums that (nearly) provide the same behavior in a much more readable way:
1) Enums for a type-safe switch:
enum CommandType {
MESSAGE,
QUIT,
CONFIRMCONNECT
}
public void handleParsedCommand(String[] commandArr) {
CommandType cmd = null;
try {
cmd = CommandType.valueOf(commandArr[0].toUpperCase());
} catch (IllegalArgumentException e) {
// this kind of error handling, seems a bit strange, by the way.
try {
out.write("Unknown: " + commandArr[0] + "\n");
} catch (IOException e) {
System.out.println("Failed output warning of unknown command.");
}
return;
}
switch(cmd) {
case MESSAGE:
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
MachatServer.sendMessage(target, this.conId, message);
case QUIT:
// Tell the server to disconnect us.
MachatServer.disconnect(conId);
case CONFIRMCONNECT:
// Blah blah and so on for another 10 types of command
}
}
}
The main benefits are that the code is more readable, but you avoid creating new methods or classes for each of the cases, which is not allows what you want if the handling code has only one or two lines.
2) Another enum-based variant, that is in fact a Command pattern, but which out much bloat code:
enum CommandType {
MESSAGE {
void execute(CommandProcessor cp, String[] params) {
int target = Integer.parseInt(params[1]);
String message = params[2];
MachatServer.sendMessage(target, cp.conId, message);
}
},
QUIT {
void execute(CommandProcessor cp, params param) {
MachatServer.disconnect(cp.conId);
}
},
CONFIRMCONNECT {
void execute(CommandProcessor cp, params param) {
// Blah blah and so on for another 10 types of command
}
};
abstract void execute(CommandProcessor cp, String[] param);
}
public void handleParsedCommand(String[] commandArr) {
CommandType cmd = null;
try {
cmd = CommandType.valueOf(commandArr[0].toUpperCase());
} catch (IllegalArgumentException e) {
try {
out.write("Unknown: " + commandArr[0] + "\n");
} catch (IOException e) {
System.out.println("Failed output warning of unknown command.");
}
return;
}
cmd.execute(this, commandArr);
}
Yeap, looks like a Command + Prototype pattern to me.
In the command you define what is going to be done, and the prototype is to place an instance of each command in a lookup table and "clone" them to be executed each time.
The refactoring would be like:
Before:
public void handleParsedCommand(String[] commandArr) {
if(commandArr[0].equalsIgnoreCase("message")) {
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
MachatServer.sendMessage(target, this.conId, message);
} else if(commandArr[0].equalsIgnoreCase("quit")) {
// Tell the server to disconnect us.
MachatServer.disconnect(conId);
} else if(commandArr[0].equalsIgnoreCase("confirmconnect")) {
// Blah blah and so on for another 10 types of command
} else {
try {
out.write("Unknown: " + commandArr[0] + "\n");
} catch (IOException e) {
System.out.println("Failed output warning of unknown command.");
}
}
}
After:
public void handleParsedCommand(String[] commandArr) {
Command.getCommand( commandArr ).execute();
}
// Define the command and a lookup table
abstract class Command {
// Factory using prototype
public static Command getCommand( String [] commandArr ) {
// find the handling command
Command commandPrototype = commandMap.get( commandArr[0] );
// if none was found, then use "uknown"
if ( commandPrototype == null ) {
commandPrototype = commandMap.get("unknown");
}
// Create an instance using clone
Command instance = commandPrototype.clone();
instance.args = commanrArr;
return instance;
}
// lookup table ( switch substitute )
private static Map<String,Command> commandsMap = new HashMap()<String,Command>(){{
put("message" , new MessagCommand());
put("quit" , new QuitCommand());
put("confirmconnect", new ConfirmConnectCommand());
...
put("unknow" , new UnknownCommand());
}};
// args of the command
private String [] args;
public void execute();
String [] getArgs(){
return this.args;
}
}
And the provide the specific implementations
class MessageCommand extends Command {
public void execute(){
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
MachatServer.sendMessage(target, this.conId, message);
}
}
class MessageCommand extends Command {
public void execute(){
int target = Integer.parseInt(getArgs()[1]);
String message = getArgs()[2];
MachatServer.sendMessage(target, this.conId, message);
}
}
class QuitCommand extends Command {
public void execute() {
MachatServer.disconnect(conId);
}
}
class ConfirmConnectCommand extends Command {
public void execute() {
/// blah blah blah
}
}
class UnknowCommand extends Command {
public void execute() {
try {
out.write("Unknown: " + commandArr[0] + "\n");
} catch (IOException e) {
System.out.println("Failed output warning of unknown command.");
}
}
}
// ... other 10 implementations here...
Take a look at Commons CLI which is a command-line argument parser.
Here are some examples of its usage.
You can use enums
For starters, I would make a map between the commands and a class which executes each type of command (say an anonymous class that implements a known interface) and then retrieve the right class from the map, and then passes it the rest of the parameters.
If it made sense, you could use an enum here with a static method to retrieve the right one, that way you could switch if and when you needed to (say you had to do the same thing on 5 of the 10 commands).
First of all you are reading the same element of the array every time. This should be the first thing to factor out. equalsIgnoreCase is a bit long, so normalise the case first (don't pick up the default locale!).
It is possible to use enums to hack a switch of Swtings. JDK7 may include a switch on String, IIRC.
I like Bob's answer. Another method would be to use the Spring framework and the IoC functionality. Basically, I've done this before to use Spring (inflates from xml) to create a Map where you have each command object stored with a key. The key would be the same as the text in commandArr[0].
So your xml looks something like
<property name="commands">
<map>
<entry>
<key>
<value>message</value>
</key>
<ref bean="messageCommand" />
</entry>
</map>
</property>
<bean id="messageCommand" ref="org.yourorg.yourproject.MessageCommand" />
And then in your code...
commands.get(commandArr[0]).execute() //or whatever
This allows you to not run any sort of initialization code. All you have to do is inflate the xml. Spring handles populating the map for you. Also, you can define any necessary data members in the classes using a similar syntax. Also, if you need to add functionality, all you have to do is change the xml rather than mucking with and recompiling code. I'm personally a huuuuge fan :)
For more info, check out this article for a brief overview of IoC and then check out this article for the documentation

Categories