Dynamic calling of JBehave steps from inside Java - java

In Java I have a String object that has the text that I wish to be matched and executed by JBehave as a step. How can this be done? Can it be done?
What I am really trying to do is to have a wrapper JBehave step that instruments another arbitrary JBehave step. It does a few things before and after calling on the "inner" step.
So lets say that I already have the following
When I say Hello World
and
#When("I say $text")
public void iSay(final String text)
{
System.out.println(text);
}
I want to be able to do the following :
When I repeat 4 times I say Hello World
it will call :
#When("I repeat $count times $subStepString")
public void repeat(final int repeatCount, final String subStepString)
{
// prep code here
for (int i = 0; i < repeatCount; i++)
{
howDoIdoThisBitHere(subStepString);
}
// post process code here
}
The part that says howDoIdoThisBitHere(...) should end up having JBehave match the value of subStepString as if it was encountered in the case above. This way I can use this method to call other arbitrary things.

I'm not sure this is a great idea since the step classes shouldn't have any dependency on the core configuration (StepMatchers, Runners etc.), but is this solution kind of what you're looking for?
#When("I repeat $count times $subStepString")
public void repeat(final int repeatCount, final String subStepString)
{
// prep code here
for (int i = 0; i < repeatCount; i++)
{
StoryParser sp = configuration().storyParser();
Story s = sp.parseStory(subStepString);
StoryRunner e = configuredEmbedder().storyRunner();
e.run(configuration(), configuredEmbedder().candidateSteps(), s);
}
}

Related

How can I change code based on Method Argument?

public static void calculate(List<Person> data, String categoryType) {
for(int i = 0; i < categoryData.size(); i++) {
if(data.get(i).calculateCategoryOne() == firstPlace) {
...
}
}
}
If you see data.get(i).calculateCategoryOne(), the method call is for category one. The problem is that I need to copy-paste the entire code in a if-block for each category to just change this method call data.get(i).calculateCategoryTwo(), data.get(i).calculateCategoryThree(), ... data.get(i).calculateCategoryTen(),
While I can still make the logic work in this way, I feel it is redundant and not a good programming practice. Just to change one line of code, I would have to replicate the same code ten different times which will add nearly 500 lines of code.
So, my question is: Is there a way to dynamically change my method call based on the category type string argument.
I was thinking one possible way is to pass the method call in a string and convert it to a method call itself. For example, let's assume CategoryType string argument is "calculateCategoryOne()". So, data.get(i)."calculateCategoryOne()" would be recognized by the compiler as the method call itself. Is there a way to actually implement this?
I'm open to other ideas as well to reduce redundancy.
I would think using a functional interface would be appropriate here. You want different functionality depending on the categoryType, so passing in the function you want to use, rather than a String representation of it, would accomplish this.
#FunctionalInterface
public interface Calculate {
int calculate(Person data);
}
public static void calculate(List<Person> data, Calculate calculate) {
for(int i = 0; i < categoryData.size(); i++) {
if(calculate.calculate(data.get(i)) == firstPlace) {
...
}
}
}
and the call to the method would define what the calculation would be
calculate(list, p -> {
// calculation done here
});
or if this would happen frequently, you could predefine your categories once and pass those in:
Calculate categoryOne = p -> { ... };
Calculate categoryTwo = p -> { ... };
.
.
calculate(list, categoryOne);

Call functions put in array

for my code in Java I need to call functions for some figures inside a number. In fact, if my number is 464, I have to call functions named assert4 and assert6. I hope that you're understanding. But if I'm right, we can't concatenate a string and a variable to have the name of a function and execute it. For example :
for (int i = 0; i < number.length(); i++) {
assert + i + (); // For example executing the function assert4
}
So I can't see how I can do it. Thanks for help !
You can do this with reflection using something like YourClass.class.getMethod(...).invoke(...). (See this question for instance.)
However, this is a bit of a code smell and I encourage you to do something like
Map<Integer, Runnable> methods = new HashMap<>();
methods.put(464, YourClass::assert464);
...
for (int i = 0; i < number.length(); i++) {
methods.get(i).run();
}
If you're on Java 7 or older, the equivalent would be
methods.put(464, new Runnable() { public void run() { assert464(); } });
You can call a method using a String name using the reflection API.
Here's some tutorials on how to get started:
http://docs.oracle.com/javase/tutorial/reflect/
http://www.ibm.com/developerworks/library/j-dyn0603/

Static variables within Interception class java

I've got a problem which is kinda obvious, though I'm not sure how to solve it.
I've got 2 classes, 1 of which is Interceptor.
#Stateless
#Interceptors(AutoId.class)
public class TestClass {
private static final Logger LOG = Logger.getLogger(RepositoryBean.class.getName());
public void executeUpdate(){
int k=0;
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 100000; j++) {
for (int r = 0; r < 1000000; r++) {
k = 1;
}
}
}
getLogger().log(Level.INFO, "Current time some time ago was "+AutoId.MyTime/1000);
}
private Logger getLogger() {
return Logger.getLogger(getClass().getCanonicalName());
}}
and here is Interceptor class:
public class AutoId {
public static Long MyTime;
#AroundInvoke
public Object addLog(InvocationContext context) throws Exception {
MyTime= System.currentTimeMillis();
return context.proceed();
}
}
an obvious problem is that if I run this application (when it's deployed on a glassfish server) and then in a couple of seconds I run another copy of it, it is going to rewrite MyTime variable with new time and, as a result, both programs will print same time.
One of the obvious solutions is to make a variable inside executeUpdate which will save the value of MyTime, BUT this is not good for the real project I'm working on.
I was told that I might want to do something with ContextResolver and #Context.
Any thoughs on how do I solve this?
Thanks.
EDIT
I found one solution, though I don't think it is the best
public class AutoId {
private static Long[] MyTime = new Long[1000];
#AroundInvoke
public Object addLog(InvocationContext context) throws Exception {
MyTime[(int)Thread.currentThread().getId()]= System.currentTimeMillis();
return context.proceed();
}
public static Long MyTime(){
return MyTime[(int)Thread.currentThread().getId()];
}
}
naming array the same way as procedure allows to minimize code changes in main class only by adding () after AutoId.MyTime -> AutoId.MyTime()
That's still not the best Idea, though it doesn't cause rewriting of variable anymore.
EDIT2 please don't really mind all the code in executeUpdate() procedure. It is just written in a way it takes some tome to finish working, so that I can execute 1 more copy of it and print out AutoId.MyTime. The value of this variable is the only thing that matters.
Also it's qute obvious that if I wasn't using Interceptor and just created an AutoId variable within class to call it before any other procedure (that's what interceptors for) that error wouldn't appear since every copy of program will have its own id easily - that's not option though. Interceptors are required for autorisation here before executing any procedure. Hope that explains everything I haven't told before :)
You could use #Produces for logger creation and use then #Inject to inject your logger in your class and interceptor. This way you should log different times.

Is there any difference between these two loops?

Is there any difference performance-wise between the two code snippets below?
for(String project : auth.getProjects()) {
// Do something with 'project'
}
and
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
For me, I think the second one is better, but it is longer. The first one is shorter, but I am not really sure if it is faster. I am not sure, but to me it seems like every time that loop is iterated, auth.getProjects is called. Is that not so?
Edit: #StephenC is right, the JLS is a much better place to find an answer for something of this nature. Here is a link to the enhanced for loop in the language specification. In there you will find that there are a few different types of for statements it generates but none of them would call the method more than 1 time.
Simple test shows that the method is only called once
public class TestA {
public String [] theStrings;
public TestA() {
theStrings = new String[] {"one","two", "three"};
for(String string : getTheStrings()) {
System.out.println(string);
}
}
public String[] getTheStrings() {
System.out.println("get the strings");
return theStrings;
}
public static void main(String [] args) {
new TestA();
}
}
Output:
get the strings
one
two
three
So essentially they are the same thing. The only thing that may be beneficial about the 2nd would be if you want to use the array outside the for loop.
Edit
You got me curious about how the java compiler handled this so using the code above I decompiled the class file and heres what the result is
public class TestA
{
public TestA()
{
String as[];
int j = (as = getTheStrings()).length;
for(int i = 0; i < j; i++)
{
String string = as[i];
System.out.println(string);
}
}
public String[] getTheStrings()
{
System.out.println("get the strings");
return theStrings;
}
public static void main(String args[])
{
new TestA();
}
public String theStrings[] = {
"one", "two", "three"
};
}
As you can see the compiler simply restructured your for loop into a standard loop! It also further proves that in fact they are exactly the same after the compiler gets through with it.
Assumng that by in you mean :, there is no difference in performance; they both do the same thing. Even in the first example, auth.getProjects() is executed only once; it can't be executed multiple times, since if it was, the for iteration would have to start over each time, which is not how it works.
I'd recommend using the version you find to be clearer.
There are a few more operations in the second example. Instead of referencing the array directly using the method, you are declaring a new reference variable, storing it in that new variable, then referencing the new variable.
You can check out the bytecode with ASM Bytecode Outline.
BUT, this is micro-optimization. If you need a new reference variable, then create one. If you don't need one, save the work and don't create a new one.
There is no difference.
According to the JLS 14.14.2, an enhanced for loop (for an array type) is equivalent to a regular for loop with the following pattern:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
{VariableModifier} TargetType Identifier = #a[#i];
Statement
}
If we substitute for your first example:
for(String project : auth.getProjects()) {
// Do something with 'project'
}
we get:
String[] $a = auth.getProjects();
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
For your second example:
String[] projects = auth.getProjects();
for(String project : projects) {
// Do something with 'project'
}
we get:
String[] projects = auth.getProjects();
String[] $a = projects;
for (int $i = 0; $i < $a.length; $i++) {
String project = $a[$i];
// Do something with 'project'
}
The two versions of the code are clearly equivalent, and assuming that javac or the JIT is capable of optimizing away the redundant local variable $a, the two versions should perform the same.
Note that the local variable $a is only created once at the start of the loop in both cases.
The second one is better performance-wise, it is not creating a variable multiple times. Therefore, yes, auth.getProjects is being called every time.
Both are same as found above.
But do one thing use 1st approcah and after the for loop, de-reference the projects variable as-
projects = null;
Else, it will stay alive for the complete method life and will consume unnecessary memory.

Code Structure for Parsing Command line Arguments in Java

I have a question regarding structuring of code.
I have let us say three types of packages A,B and C.
Now, classes in package A contains classes which contain the main() function. These classes
need some command line arguments to run.
In package B, there are classes which contains some public variables, which need to be configured, at different times. For example before calling function A, the variable should be set or reset, the output differs according to this variable.
In package C, uses the classes in package B to perform some tasks. They do configure their variables as said before. Not only when the object is created, but also at intermediate stage.
Package A also has classes which in turn use classes from package B and package C. In order to configure the variables in classes of B and C, class in package A containing the main() function, reads command line arguments and passes the correct values to respective class.
Now, given this scenario, I want to use Apache Commons CLI parser.
I am unable to understand how exactly I should write my code to be structured in an elegant way. What is a good design practice for such scenario.
Initially I wrote a class without Apache to parse the command line arguments.
Since I want a suggestion on design issue, I will give an excerpt of code rather than complete code.
public class ProcessArgs
{
private String optionA= "default";
private String optionB= "default";
private String optionC= "default";
public void printHelp ()
{
System.out.println ("FLAG : DESCRIPTION : DEFAULT VALUE");
System.out.println ("-A <Option A> : Enable Option A : " + optionA);
System.out.println ("-B <Option B> : Enable Option B : " + optionB);
System.out.println ("-C <Option C> : Enable Option C : " + optionC);
}
public void printConfig()
{
System.out.println ("Option A " + optionA);
System.out.println ("Option B " + optionB);
System.out.println ("Option C " + optionC);
}
public void parseArgs (String[] args)
{
for (int i=0;i<args.length;i++)
{
if (args[i].equalsIgnoreCase ("-A"))
optionA = args[++i];
else if (args[i].equalsIgnoreCase ("-B"))
optionB = args[++i];
else if (args[i].equalsIgnoreCase ("-C"))
optionC = args[++i];
else
throw new RuntimeException ("Wrong Argument : " + args[i] + " :: -h for Help.");
}
}
}
Points to note -
I already have 50+ command line options and they are all in one place.
Every class uses only a group of command line options.
I tried to write an interface, somehow but I am unsuccessful. I am not sure if this is a good way to do it or not. I need some design guidelines.
Here is the code which I wrote -
public interface ClassOptions
{
Options getClassOptions();
void setClassOptions(Options options);
}
public class Aclass implements ClassOptions
{
private String optionA="defaultA";
private String optionB="defaultB";
public Options getClassOptions()
{
Options options = new Options();
options.addOption("A", true, "Enable Option A");
options.addOption("B", true, "Enable Option B");
return options;
}
public void setClassOptions(Options options, String args[])
{
CommandLineParser parser = new BasicParser();
CommandLine cmd=null;
try
{
cmd = parser.parse( options, args);
} catch (ParseException e)
{
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("ignored option");
}
if(cmd.hasOption("A"))
optionA = "enabled";
if(cmd.hasOption("B"))
optionB = "enabled";
}
}
I think the problems in such writing of code are -
There are different types of arguments like int, double, string, boolean. How to handle them all.
getClassOption() and setClassOption() both contain the arguments "A", "B" for example. This code is prone to errors made while writing code, which I would like to eliminate.
I think the code is getting repetitive here, which could be encapsulated somehow in another class.
Not all the arguments are required, but can be ignored.
Thank You !
I would recommend to you JCommander.
I think it's a really good Argument Parser for Java.
You define all the Argument stuff within annotations and just call JCommander to parse it.
On top of that it also (based on your annotations) can print out the corresponding help page.
You don't have to take care about anything.
I believe you will love it! :)
Take a look at it: http://jcommander.org/
There are a lot of examples and such!
Good Luck! :)
simple example for command line argument
class CMDLineArgument
{
public static void main(String args[])
{
int length=args.length();
String array[]=new String[length];
for(int i=0;i<length;i++)
{
array[i]=args[i];
}
for(int i=0;i<length;i++)
{
System.out.println(array[i]);
}

Categories

Resources