Is it possible to resolve mathematical function dynamically - java

Is it possible, to resolve mathematical functions dynamically, e.g by the use of a given API?
Given there is a function
a = b + c
is there a way to write something comparable to:
Function func = new Function("a=b+c");
Result result = func.resolve("a=1", "b=?", "c=a");
System.out.println(result.getValue());
Ideally, resolve(Object... args) should accept further classes of type Function.
EDIT 1: The API should be includable into a Java EE environment such as jBossAS.
EDIT 2: Actually I want to solve equations with one unknown variable, but I want to avoid hard coded functions. Thus, for the function
a+b=c
I don't want to write the functions hard coded
getA(int b, int c){...}
getB(int a, int c){...}
getC(int a, int b){...}
Instead, as #Berylium says, I want to evaluate the expression dynamically.
EDIT 3: I'm trying symja right now and I think I'm getting closer, but I have troubles with the syntax.
try {
F.initSymbols(null);
EvalUtilities util = new EvalUtilities();
StringBufferWriter buf = new StringBufferWriter();
String input = "....";
IExpr result = util.evaluate(input);
OutputFormFactory.get().convert(buf, result);
String output = buf.toString();
System.out.println("Evaluation for " + input + " is " + output);
} catch (final Exception e) {
Can you help me with the input syntax?
EDIT 4: Got it :-) For input
String input = "Solve[{a==10,c==20,a+b==c},{a,b,c}]";
the output is
Evaluation for Solve[{a==10,c==20,a+b==c},{a,b,c}] is {{a->10,c->20,b->10}}

Any embeddable Java scripting engine will do:
For example, using BeanShell:
final Interpreter interp = new Interpreter();
try {
interp.eval("System.out.println(\"Hello, world\");");
final String s = "Hello, world (2)";
interp.set("test", s);
interp.eval("System.out.println(test);");
System.out.println("3+4=" + interp.eval("3+4"));
interp.set("a", 4);
interp.set("b", 5);
System.out.println("a + b = " + interp.eval("a + b"));
final String script1 =
"public int f(int a) { return a * a; }; System.out.println(f(4));";
interp.eval(script1);
final String script2 =
"public int f(int a) { return a * a; }; f(4)";
System.out.println(interp.eval(script2));
final String script3 =
"import java.util.Date; Date date = new Date(); date";
System.out.println(interp.eval(script3));
final String script4 =
"class X { public int a; } X x = new X(); x.a = 5; x.a";
System.out.println(interp.eval(script4));
} catch (EvalError e) {
e.printStackTrace();
}
One advantage is that BeanShell uses Java syntax which is quite close to Java. So there is no need to learn/use another language/syntax.

After adding symja JAR to the build path, the following code prints the output below:
Code:
public static void main(String[] args) {
try {
F.initSymbols(null);
EvalUtilities util = new EvalUtilities();
StringBufferWriter buf = new StringBufferWriter();
String input = "Solve[{a==10,c==20,a+b==c},{a,b,c}]";
IExpr result = util.evaluate(input);
OutputFormFactory.get().convert(buf, result);
String output = buf.toString();
System.out.println("Evaluation for " + input + " is " + output);
} catch (final Exception e) {
e.printStackTrace();
} finally {
// Call terminate() only one time at the end of the program
ComputerThreads.terminate();
}
}
Output:
Evaluation for Solve[{a==10,c==20,a+b==c},{a,b,c}] is {{a->10,c->20,b->10}}

Related

Use return of a method for string compare in a main if statement [duplicate]

This question already has answers here:
How do I call a non static method from a main method? [duplicate]
(7 answers)
Closed 3 years ago.
I created a method (apiType) that executes a command on a linux server. The result of the method should be used in my main class for executing a class or other class, depending if the result is "app2" or "app3".
The result of the linux command (cat /opt/pcu/bin/version | grep PRODUCT | cut -d' ' -f2) is either "app2" or "app3"
So my question is how can I call and use the result of the method in my main class?
OR what I do wrong or I miss in the code?
public class Api {
private final static String version = "v2";
private final static String path = FileSystems.getDefault().getPath(".").toAbsolutePath().getParent().toString();
public String apiType() throws Exception {
try {
Exec exec = new Exec();
exec.setCommand("cat /opt/pcu/bin/version | grep PRODUCT | cut -d' ' -f2");
exec.setLogPath(path);
exec.run("apiType");
exec.join(200);
Vector<String> output = exec.getOutput(false);
return output.get(0); //this should return "app2" or "app3"?!
} catch (Exception e) {
System.out.println("Failed to run command");
throw e;
}
}
public static void main(String[] args) {
if (args.length == 0) {
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy/hh:mm:ss");
System.out.println(
"\n\n==================================== TestAPI program ====================================\n");
System.out.println("Date: " + dateFormat.format(date.getTime()) + " " + version);
System.out.println(
"\n==============================================================================================\n\n");
Console console = System.console();
String user = console.readLine("Username: ");
String password = new String((console.readPassword("Password: ")));
String testID = console.readLine("TestID: ");
String pattern = "[Tt]?(\\d+)";
Pattern pat = Pattern.compile(pattern);
Matcher m = pat.matcher(testID);
if (!m.matches()) {
System.out.println("Test ID doesn't have a valid format");
return;
}
testID = m.group(1);
String csvFilePath = console.readLine("CSV Test File: ");
if (????.equals("app2")) {
TestApi2 test = new TestApi2(user, password, testID, csvFilePath);
test.runTest();
} else if (????.equals("app3")) {
TestApi3 test2 = new TestApi3(user, password, testID, csvFilePath);
test2.runTest();
} else {
System.out.println("Unknown");
}
} else if (args.length == 1 && args[0].equalsIgnoreCase("--help")) {
}
}
}
You need to intstantiate an Api
Api api = new Api();
then call the method and assign its returned value to a string
String apiType = api.apiType();
At that point you can use your newly created string apiType to check for the returned value
if (apiType.equals("app2")) {
// ...
} else if (apiType.equals("app3")) {
// ...
}
I'm assuming that the main method is only meant for testing the class itself, so I will assume you actually don't want to make apiType itself static.

GroovyCastException while running java code containing new line "\n" with groovy script engine(GroovyClassLoader)

Currently I am working on a way to run java code in string form. So here is how I did it.
import java.util.HashMap;
import java.util.Map;
import groovy.lang.GroovyClassLoader;
public class GroovyStackOverflow {
public static void main(String[] args) {
GroovyClassLoader gcl = new GroovyClassLoader();
String codeSnippet = "double calculatedAnswer = (Double)"
+ "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
+ " calculatedAnswer = Math.sqrt(calculatedAnswer); "
+ "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
+ "System.out.println(calculatedAnswer);"
+ " return calculatedAnswer;";
StringBuilder sb = new StringBuilder();
sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
sb.append(codeSnippet);
sb.append("} }");
Class<?> clazz = gcl.parseClass(sb.toString());
ScriptEvaluator scriptEvaluator = null;
double calculatedAnswer = 100.0;
try {
Map contextMap = new HashMap();
contextMap.put("doubleValue", (double)100.0);
contextMap.put("threadId", "thread"+100);
contextMap.put("hashCode", 100);
scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
scriptEvaluator.evaluate(contextMap);;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public interface ScriptEvaluator {
public Object evaluate(Map contextMap);
}
Problem is that it fails in following case.
import java.util.HashMap;
import java.util.Map;
import groovy.lang.GroovyClassLoader;
public class GroovyStackOverflow {
public static void main(String[] args) {
GroovyClassLoader gcl = new GroovyClassLoader();
String codeSnippet = "double calculatedAnswer = (Double)"
+ "\n "
+ "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
+ " calculatedAnswer = Math.sqrt(calculatedAnswer); "
+ "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
+ "System.out.println(calculatedAnswer);"
+ " return calculatedAnswer;";
StringBuilder sb = new StringBuilder();
sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
//sb.append(codeSnippet.replaceAll("\n", " "));
sb.append(codeSnippet);
sb.append("} }");
Class<?> clazz = gcl.parseClass(sb.toString());
ScriptEvaluator scriptEvaluator = null;
double calculatedAnswer = 100.0;
try {
Map contextMap = new HashMap();
contextMap.put("doubleValue", (double)100.0);
contextMap.put("threadId", "thread"+100);
contextMap.put("hashCode", 100);
scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
scriptEvaluator.evaluate(contextMap);;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public interface ScriptEvaluator {
public Object evaluate(Map contextMap);
}
I don't understand why it fails and what this error message means-
Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class java.lang.Double' with class 'java.lang.Class' to class 'double'
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToNumber(DefaultTypeTransformation.java:163)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.doubleUnbox(DefaultTypeTransformation.java:88)
at ScriptImplementor.evaluate(script15126616543572010791987.groovy:1)
at GroovyStackOverflow.main(GroovyStackOverflow.java:33)
After uncommenting this code //sb.append(codeSnippet.replaceAll("\n", " ")); it works. But please suggest a better way to handle it. Also why it does not give error while parsing class?
And what other surprises I can expect like this?
You hit a difference between Java and Groovy.
In Java a statement is ended by a semicolon.
In Groovy a satement is ended by a semicolon, or by a linebreak if the statement already is a complete statement.
In your case this means the code
double calculatedAnswer = (Double)
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")
is two statements.
The first of these statements is double calculatedAnswer = (Double).
In Groovy you can also omit .class to reference a class, so Double.class can be written as Double.
So what you do in that statement is, that you assign the Double class object to a double variable. The parentheses are just no-ops here.
This of course fails like the message says, as the Double class object cannot be case automatically to a double.
You can explicitly escape a linebreak to make it not end a statement like in
double calculatedAnswer = (Double)\
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")
which would work like you expected.
But there can of course be other cases where Groovy and Java are different.
Always remember, the Groovy syntax is close to the Java syntax, yet not identical.
Afair each valid Java code is also valid Groovy code, but not necessarily with the exact same meaning as you can see in this example.

Parsing a .txt file (considering performance measure)

DurationOfRun:5
ThreadSize:10
ExistingRange:1-1000
NewRange:5000-10000
Percentage:55 - AutoRefreshStoreCategories Data:Previous/30,New/70 UserLogged:true/50,false/50 SleepTime:5000 AttributeGet:1,16,10106,10111 AttributeSet:2060/30,10053/27
Percentage:25 - CrossPromoEditItemRule Data:Previous/60,New/40 UserLogged:true/50,false/50 SleepTime:4000 AttributeGet:1,10107 AttributeSet:10108/34,10109/25
Percentage:20 - CrossPromoManageRules Data:Previous/30,New/70 UserLogged:true/50,false/50 SleepTime:2000 AttributeGet:1,10107 AttributeSet:10108/26,10109/21
I am trying to parse above .txt file(first four lines are fixed and last three Lines can increase means it can be more than 3), so for that I wrote the below code and its working but it looks so messy. so Is there any better way to parse the above .txt file and also if we consider performance then which will be best way to parse the above txt file.
private static int noOfThreads;
private static List<Command> commands;
public static int startRange;
public static int endRange;
public static int newStartRange;
public static int newEndRange;
private static BufferedReader br = null;
private static String sCurrentLine = null;
private static List<String> values;
private static String commandName;
private static String percentage;
private static List<String> attributeIDGet;
private static List<String> attributeIDSet;
private static LinkedHashMap<String, Double> dataCriteria;
private static LinkedHashMap<Boolean, Double> userLoggingCriteria;
private static long sleepTimeOfCommand;
private static long durationOfRun;
br = new BufferedReader(new FileReader("S:\\Testing\\PDSTest1.txt"));
values = new ArrayList<String>();
while ((sCurrentLine = br.readLine()) != null) {
if(sCurrentLine.startsWith("DurationOfRun")) {
durationOfRun = Long.parseLong(sCurrentLine.split(":")[1]);
} else if(sCurrentLine.startsWith("ThreadSize")) {
noOfThreads = Integer.parseInt(sCurrentLine.split(":")[1]);
} else if(sCurrentLine.startsWith("ExistingRange")) {
startRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
endRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else if(sCurrentLine.startsWith("NewRange")) {
newStartRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
newEndRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else {
attributeIDGet = new ArrayList<String>();
attributeIDSet = new ArrayList<String>();
dataCriteria = new LinkedHashMap<String, Double>();
userLoggingCriteria = new LinkedHashMap<Boolean, Double>();
percentage = sCurrentLine.split("-")[0].split(":")[1].trim();
values = Arrays.asList(sCurrentLine.split("-")[1].trim().split("\\s+"));
for(String s : values) {
if(s.startsWith("Data")) {
String[] data = s.split(":")[1].split(",");
for (String n : data) {
dataCriteria.put(n.split("/")[0], Double.parseDouble(n.split("/")[1]));
}
//dataCriteria.put(data.split("/")[0], value)
} else if(s.startsWith("UserLogged")) {
String[] userLogged = s.split(":")[1].split(",");
for (String t : userLogged) {
userLoggingCriteria.put(Boolean.parseBoolean(t.split("/")[0]), Double.parseDouble(t.split("/")[1]));
}
//userLogged = Boolean.parseBoolean(s.split(":")[1]);
} else if(s.startsWith("SleepTime")) {
sleepTimeOfCommand = Long.parseLong(s.split(":")[1]);
} else if(s.startsWith("AttributeGet")) {
String[] strGet = s.split(":")[1].split(",");
for(String q : strGet) attributeIDGet.add(q);
} else if(s.startsWith("AttributeSet:")) {
String[] strSet = s.split(":")[1].split(",");
for(String p : strSet) attributeIDSet.add(p);
} else {
commandName = s;
}
}
Command command = new Command();
command.setName(commandName);
command.setExecutionPercentage(Double.parseDouble(percentage));
command.setAttributeIDGet(attributeIDGet);
command.setAttributeIDSet(attributeIDSet);
command.setDataUsageCriteria(dataCriteria);
command.setUserLoggingCriteria(userLoggingCriteria);
command.setSleepTime(sleepTimeOfCommand);
commands.add(command);
Well, parsers usually are messy once you get down to the lower layers of them :-)
However, one possible improvement, at least in terms of code quality, would be to recognize the fact that your grammar is layered.
By that, I mean every line is an identifying token followed by some properties.
In the case of DurationOfRun, ThreadSize, ExistingRange and NewRange, the properties are relatively simple. Percentage is somewhat more complex but still okay.
I would structure the code as (pseudo-code):
def parseFile (fileHandle):
while (currentLine = fileHandle.getNextLine()) != EOF:
if currentLine.beginsWith ("DurationOfRun:"):
processDurationOfRun (currentLine[14:])
elsif currentLine.beginsWith ("ThreadSize:"):
processThreadSize (currentLine[11:])
elsif currentLine.beginsWith ("ExistingRange:"):
processExistingRange (currentLine[14:])
elsif currentLine.beginsWith ("NewRange:"):
processNewRange (currentLine[9:])
elsif currentLine.beginsWith ("Percentage:"):
processPercentage (currentLine[11:])
else
raise error
Then, in each of those processWhatever() functions, you parse the remainder of the line based on the expected format. That keeps your code small and readable and easily changed in future, without having to navigate a morass :-)
For example, processDurationOfRun() simply gets an integer from the remainder of the line:
def processDurationOfRun (line):
this.durationOfRun = line.parseAsInt()
Similarly, the functions for the two ranges split the string on - and get two integers from the resultant values:
def processExistingRange (line):
values[] = line.split("-")
this.existingRangeStart = values[0].parseAsInt()
this.existingRangeEnd = values[1].parseAsInt()
The processPercentage() function is the tricky one but that is also easily doable if you layer it as well. Assuming those things are always in the same order, it consists of:
an integer;
a literal -;
some sort of textual category; and
a series of key:value pairs.
And even these values within the pairs can be parsed by lower levels, splitting first on commas to get subvalues like Previous/30 and New/70, then splitting each of those subvalues on slashes to get individual items. That way, a logical hierarchy can be reflected in your code.
Unless you're expecting to be parsing this text files many times per second, or unless it's many megabytes in size, I'd be more concerned about the readability and maintainability of your code than the speed of the parsing.
Mostly gone are the days when we need to wring the last ounce of performance from our code but we still have problems in fixing said code in a timely manner when bugs are found or enhancements are desired.
Sometimes it's preferable to optimise for readability.
I would not worry about performance until I was sure there was actually a performance issue. Regarding the rest of the code, if you won't be adding any new line types I would not worry about it. If you do worry about it, however, a factory design pattern can help you separate the selection of the type of processing needed from the actual processing. It makes adding new line types easier without introducing as much opportunity for error.
The younger and more convenient class is Scanner. You just need to modify the delimiter, and get reading of data in the desired format (readInt, readLong) in one go - no need for separate x.parseX - calls.
Second: Split your code into small, reusable pieces. They make the program readable, and you can hide details easily.
Don't hesitate to use a struct-like class for a range, for example. Returning multiple values from a method can be done by these, without boilerplate (getter,setter,ctor).
import java.util.*;
import java.io.*;
public class ReadSampleFile
{
// struct like classes:
class PercentageRow {
public int percentage;
public String name;
public int dataPrevious;
public int dataNew;
public int userLoggedTrue;
public int userLoggedFalse;
public List<Integer> attributeGet;
public List<Integer> attributeSet;
}
class Range {
public int from;
public int to;
}
private int readInt (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
return sc.nextLong ();
}
else err (name + " expected, found: " + s);
}
private long readLong (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
return sc.nextInt ();
}
else err (name + " expected, found: " + s);
}
private Range readRange (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
Range r = new Range ();
r.from = sc.nextInt ();
r.to = sc.nextInt ();
return r;
}
else err (name + " expected, found: " + s);
}
private PercentageLine readPercentageLine (Scanner sc) {
// reuse above methods
PercentageLine percentageLine = new PercentageLine ();
percentageLine.percentage = readInt ("Percentage", sc);
// ...
return percentageLine;
}
public ReadSampleFile () throws FileNotFoundException
{
/* I only read from my sourcefile for convenience.
So I could scroll up to see what's the next entry.
Don't do this at home. :) The dummy later ...
*/
Scanner sc = new Scanner (new File ("./ReadSampleFile.java"));
sc.useDelimiter ("[ \n/,:-]");
// ... is the comment I had to insert.
String dummy = sc.nextLine ();
List <String> values = new ArrayList<String> ();
if (sc.hasNext ()) {
// see how nice the data structure is reflected
// by this code:
long duration = readLong ("DurationOfRun");
int noOfThreads = readInt ("ThreadSize");
Range eRange = readRange ("ExistingRange");
Range nRange = readRange ("NewRange");
List <PercentageRow> percentageRows = new ArrayList <PercentageRow> ();
// including the repetition ...
while (sc.hasNext ()) {
percentageRows.add (readPercentageLine ());
}
}
}
public static void main (String args[]) throws FileNotFoundException
{
new ReadSampleFile ();
}
public static void err (String msg)
{
System.out.println ("Err:\t" + msg);
}
}

How to deal with command line arguments in Java

Suppose I have a simple program which takes argument input in one of the following forms
do1 inputLocation outputLocation
do2 inputLocation outputLocation
do3 [30 or 60 or 90] inputLocation outputLocation
do4 [P D or C] inputLocation outputLocation
do5 [G H I] inputLocation outputLocation
I also have 5 functions with the same names in the program that I need to call. So far I thought of doing it this way (In 'semi pseudocode')
static void main(String[] args)
{
if (args.length == 3)
processTriple(args);
if (args.length == 4)
processQuadruple(args);
throw new UnsupportedOperationException("dasdhklasdha");
}
where the process functions look like this
processDouble(String args[])
{
String operation = "args[0]";
Location input = getInput(args[1]);
Location output = getInput(args[2]);
if (operation.equals("do1"))
do1(input,output);
if (operation.equals("do2"))
do2(input,output);
... etc
}
The way I'm doing it doesn't seem very extensible. If a function's arguments change, or new functions are added it seems like this would be a pain to maintain.
What's the "best" way of going about something like this
at this point I would use commons-cli or jargs. Unless you are trying to do something really special with arguments I would say focus in the real business of your app and don't deal with the mess of the application arguments
Use a command line parsing library.
Ive used JOpt Simple in the past with great results. It lets you abstract away the command line arg mess, and keep a really clean update-able list of arguments. An added benefit is it will generate the help output that standard command line utilities have.
Heres a quick example:
private void runWithArgs (String[] args) {
OptionParser parser = getOptionParser ();
OptionSet options = null;
try {
options = parser.parse (args);
}
catch (OptionException e) {
log.error ("Sorry the command line option(s): " + e.options () +
" is/are not recognized. -h for help.");
return;
}
if (options.has ("h")) {
try {
log.info ("Help: ");
parser.printHelpOn (System.out);
}
catch (IOException e) {
log.error ("Trying to print the help screen." + e.toString ());
}
return;
}
if (options.has ("i")) {
defaultHost = (String) options.valueOf ("i");
}
if (options.has ("p")) {
defaultPort = (Integer) options.valueOf ("p");
}
if (options.has ("q")) {
String queryString = (String) options.valueOf ("q");
log.info ("Performing Query: " + queryString);
performQuery (queryString, defaultHost, defaultPort);
return;
}
}
You can use Cédric Beust's JCommander library
Because life is too short to parse command line parameters
I even creatively violate the original intent of the library to parse NMEA 0183 sentences like $GPRTE as follows:
import java.util.List;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.internal.Lists;
public class GPRTE {
#Parameter
public List<String> parameters = Lists.newArrayList();
#Parameter(names = "-GPRTE", arity = 4, description = "GPRTE")
public List<String> gprte;
}
Code snippet that processes NMEA 0183 sentence $GPRTE from $GPRTE,1,1,c,*37 into -GPRTE 1 1 c *37 to comply with JCommander parsing syntax:
/**
* <b>RTE</b> - route message<p>
* Processes each <b>RTE</b> message received from the serial port in following format:<p>$GPRTE,d1,d2,d3,d4<p>Example: $GPRTE,1,1,c,*37
* #param sequences result of {#link #Utils.process(String)} method
* #see <a href="http://www.gpsinformation.org/dale/nmea.htm#RTE">http://www.gpsinformation.org/dale/nmea.htm#RTE<a><p>*/
public static void processGPRTE(final String command){
final String NMEA_SENTENCE = "GPRTE";
final String PARAM = "\u0001";
final String DOLLAR = "\u0004";
final String COMMA = "\u0005";
String parsedString = command;
if (parsedString.contains("$"+NMEA_SENTENCE)){
parsedString = parsedString.replaceAll("\\$", DOLLAR+PARAM);
parsedString = parsedString.replaceAll(",", COMMA);
System.out.println("GPRTE: " + parsedString);
String[] splits = parsedString.split(DOLLAR);
for(String info: splits){
if (info.contains(PARAM+NMEA_SENTENCE)) {
info = info.replaceFirst(PARAM, "-");
System.out.println("GPRTE info: " + info);
String[] args = info.split(COMMA);
GPRTE cmd = new GPRTE();
new JCommander(cmd, processEmptyString(args));
List<String> message = cmd.gprte;
String data1 = SerialOutils.unescape(message.get(0));
System.out.println("GPRTE: data1 = " + data1);
String data2 = SerialOutils.unescape(message.get(1));
System.out.println("GPRTE: data2 = " + data2);
String data3 = SerialOutils.unescape(message.get(2));
System.out.println("GPRTE: data3 = " + data3);
String data4 = SerialOutils.unescape(message.get(3));
System.out.println("GPRTE: data4 = " + data4);
System.out.println("");
}
}
}
}
I've used args4j with successful results before as well.
Just another option.

Use JDT to get full method name

I am new to eclipse plugin development and I am trying to convert a IMethod to a string representation of the full method name. I.E.
my.full.package.ClassName.methodName(int param, String string)
so far I have had to hand roll my own solution. Is there a better way?
private static String getMethodFullName(IMethod iMethod)
{
String packageString = "[Default Package]";
try {
IPackageDeclaration[] declarations = iMethod.getCompilationUnit().getPackageDeclarations();
if(declarations.length > 0)
{
packageString = declarations[0].getElementName();
}
} catch (JavaModelException e) {
}
String classString = iMethod.getCompilationUnit().getElementName();
classString = classString.replaceAll(".java", "");
String methodString = iMethod.getElementName() + "(";
for (String type : iMethod.getParameterTypes()) {
methodString += type + ",";
}
methodString += ")";
return packageString + "." + classString + "." + methodString;
}
You can get the Fully qualified name for the type using
method.getDeclaringType().getFullyQualifiedName();
This is probably easier than accessing the package from the compilation unit. The rest of you function looks correct.
One small point: you should use StringBuilder to build up the string instead of adding to a standard String. Strings are immutable so addition creates loads of unrecesary temparary objects.
private static String getMethodFullName(IMethod iMethod)
{
StringBuilder name = new StringBuilder();
name.append(iMethod.getDeclaringType().getFullyQualifiedName());
name.append(".");
name.append(iMethod.getElementName());
name.append("(");
String comma = "";
for (String type : iMethod.getParameterTypes()) {
name.append(comma);
comma = ", ";
name.append(type);
}
name.append(")");
return name.toString();
}
Thanks to iain and some more research I have come up with this solution. It seems like something like this should be built into the JDT....
import org.eclipse.jdt.core.Signature;
private static String getMethodFullName(IMethod iMethod)
{
StringBuilder name = new StringBuilder();
name.append(iMethod.getDeclaringType().getFullyQualifiedName());
name.append(".");
name.append(iMethod.getElementName());
name.append("(");
String comma = "";
String[] parameterTypes = iMethod.getParameterTypes();
try {
String[] parameterNames = iMethod.getParameterNames();
for (int i=0; i<iMethod.getParameterTypes().length; ++i) {
name.append(comma);
name.append(Signature.toString(parameterTypes[i]));
name.append(" ");
name.append(parameterNames[i]);
comma = ", ";
}
} catch (JavaModelException e) {
}
name.append(")");
return name.toString();
}
I am not sure it would take into account all cases (method within an internal class, an anonymous class, with generic parameters...)
When it comes to methods signatures, the classes to look into are:
org.eclipse.jdt.internal.corext.codemanipulation.AddUnimplementedMethodsOperation
org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2
You need to get the jdt.core.dom.IMethodBinding, from which you can extract all what you need.
If you have a MethodInvocation, you can:
//MethodInvocation node
ITypeBinding type = node.getExpression().resolveTypeBinding();
IMethodBinding method=node.resolveMethodBinding();

Categories