Passing parameters from Java to Groovy in SOAPUI - groovy

I have a java program as below,
package test;
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hi");
String a="World";
}
}
And groovy script as below,
import test.HelloWorld
HelloWorld.main(null)
And I am using this groovy script in SOAPUI after keeping the jar file in /bin/ext SOAPUI folder.
I am able to execute this groovy script in console.
But my requirement is,I need to pass variable say "a" in java program in SOAPUI test input.
For eg:
Add test input in soapui
<add>
<a> "Variable a" </a>
<b>5</b>
</add>
I want to refer that variable coming out of java program in this test input.Please let me know the way.

Java and Groovy integrates smooth. However to access the String a value a must be and attribute in object not a variable in a method. Let me explain; in your case for example in the Java part instead of a main method create an object like:
package test;
class HelloWorld {
private String a;
public HelloWorld(){
this.a = "World";
}
public String getA(){
return this.a;
}
}
Compile and add the jars to SOAPUI_HOME/bin/ext.
Then from groovy script in SOAPUI you can instantiate the class and get the value:
import test.HelloWorld
def a = new HelloWorld().getA()
log.info a // this prints --> World
If besides you want to use this value in a request you've to set the property value at some test level (for example in testCase):
import test.HelloWorld
def a = new HelloWorld().getA()
log.info a // this prints --> World
testRunner.testCase.setPropertyValue('myVar',a)
Now that your variable is set you can use the follow notation to use it in your requests: ${#TestCase#myVar}, in your request sample:
<add>
<a>${#TestCase#myVar}</a>
<b>5</b>
</add>
Hope it helps,

Related

How to pass binding.variables to a method inside a class in Groovy

i am new to groovy, trying to write a groovy which reads input values from a .csv file and performs certain actions.
I have a class defined inside the groovy and trying to access the variables from the .csv file by calling binding.variables and it doesnt look to be working.
when i try the same from a method which is part of the Groovy(not part of the class) it works fine. is there a way to pass the binding.variables to the method which is inside the class
methodA(String a, String b){
if(binding.variables.containsKey(a)){
print something//Works fine
}
}
Class A{
methodB(String a, String b){
if(binding.variables.containsKey(a)){//Doesnt work
print something
}
}
Just pass binding into your class
class A{
def binding
def methodB(){
if(binding.variables.containsKey(a)){
print something
}
}
new A(binding:binding).methodB()

#CompileStatic used on plain Groovy scripts

I'm not sure if this is already possible but is it possible to use #CompileStatic on just plain groovy scripts without wrapping the script in a class?
I'm using the GroovyClassLoader to parse and compile scripts dynamically and so it would be nice if scripts could use #CompileStatic
You can add a compiler customizer:
configuration.addCompilationCustomizers(
new ASTTransformationCustomizer(CompileStatic))
If you were on the command line you could provide a --configscript config.groovy. This answer has an example of how the script should look like:
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
You can add the #CompileStatic annotation to a class or a method.
It does not work for a whole script but you can add it to some methods or some classes of your script.
You have to add the import groovy.transform.CompileStatic in the imports of your script or class.
As an example you can try the following script in a GroovyConsole, commenting/uncommenting the method annotation:
import groovy.transform.CompileStatic
#CompileStatic
void loop() {
def d1 = new Date();
int[] t = new int[32*1024*1024]
(0 .. 32*1024*1024-1).each {
it -> t[it] = it
}
def d2 = new Date();
println d2.getTime() - d1.getTime()
}
loop()

Can I obtain method parameter name in Groovy? [duplicate]

If I have a class like this:
public class Whatever
{
public void aMethod(int aParam);
}
is there any way to know that aMethod uses a parameter named aParam, that is of type int?
In Java 8 you can do the following:
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
public final class Methods {
public static List<String> getParameterNames(Method method) {
Parameter[] parameters = method.getParameters();
List<String> parameterNames = new ArrayList<>();
for (Parameter parameter : parameters) {
if(!parameter.isNamePresent()) {
throw new IllegalArgumentException("Parameter names are not present!");
}
String parameterName = parameter.getName();
parameterNames.add(parameterName);
}
return parameterNames;
}
private Methods(){}
}
So for your class Whatever we can do a manual test:
import java.lang.reflect.Method;
public class ManualTest {
public static void main(String[] args) {
Method[] declaredMethods = Whatever.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.getName().equals("aMethod")) {
System.out.println(Methods.getParameterNames(declaredMethod));
break;
}
}
}
}
which should print [aParam] if you have passed -parameters argument to your Java 8 compiler.
For Maven users:
<properties>
<!-- PLUGIN VERSIONS -->
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<!-- OTHER PROPERTIES -->
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!-- Original answer -->
<compilerArgument>-parameters</compilerArgument>
<!-- Or, if you use the plugin version >= 3.6.2 -->
<parameters>true</parameters>
<testCompilerArgument>-parameters</testCompilerArgument>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
For more information see following links:
Official Java Tutorial: Obtaining Names of Method Parameters
JEP 118: Access to Parameter Names at Runtime
Javadoc for Parameter class
To summarize:
getting parameter names is possible if debug information is included during compilation. See this answer for more details
otherwise getting parameter names is not possible
getting parameter type is possible, using method.getParameterTypes()
For the sake of writing autocomplete functionality for an editor (as you stated in one of the comments) there are a few options:
use arg0, arg1, arg2 etc.
use intParam, stringParam, objectTypeParam, etc.
use a combination of the above - the former for non-primitive types, and the latter for primitive types.
don't show argument names at all - just the types.
The Paranamer library was created to solve this same problem.
It tries to determine method names in a few different ways. If the class was compiled with debugging it can extract the information by reading the bytecode of the class.
Another way is for it to inject a private static member into the bytecode of the class after it is compiled, but before it is placed in a jar. It then uses reflection to extract this information from the class at runtime.
https://github.com/paul-hammant/paranamer
I had problems using this library, but I did get it working in the end. I'm hoping to report the problems to the maintainer.
see org.springframework.core.DefaultParameterNameDiscoverer class
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
Yes.
Code must be compiled with Java 8 compliant compiler with option to store formal parameter names turned on (-parameters option).
Then this code snippet should work:
Class<String> clz = String.class;
for (Method m : clz.getDeclaredMethods()) {
System.err.println(m.getName());
for (Parameter p : m.getParameters()) {
System.err.println(" " + p.getName());
}
}
See java.beans.ConstructorProperties, it's an annotation designed for doing exactly this.
It is possible and Spring MVC 3 does it, but I didn't take the time to see exactly how.
The matching of method parameter names
to URI Template variable names can
only be done if your code is compiled
with debugging enabled. If you do have
not debugging enabled, you must
specify the name of the URI Template
variable name in the #PathVariable
annotation in order to bind the
resolved value of the variable name to
a method parameter. For example:
Taken from the spring documentation
While it is not possible (as others have illustrated), you could use an annotation to carry over the parameter name, and obtain that though reflection.
Not the cleanest solution, but it gets the job done. Some webservices actually do this to keep parameter names (ie: deploying WSs with glassfish).
So you should be able to do:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
But you'll probably get a list like so:
["int : arg0"]
I believe this will be fixed in Groovy 2.5+
So currently, the answer is:
If it's a Groovy class, then no, you can't get the name, but you should be able to in the future.
If it's a Java class compiled under Java 8, you should be able to.
See also:
http://openjdk.java.net/jeps/118
https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html
For every method, then something like:
Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join(';')
}
.each {
println it
}
if you use the eclipse, see the bellow image to allow the compiler to store the information about method parameters
As #Bozho stated, it is possible to do it if debug information is included during compilation.
There's a good answer here...
How to get the parameter names of an object's constructors (reflection)? by
#AdamPaynter
...using the ASM library. I put together an example showing how you can achieve your goal.
First of all, start with a pom.xml with these dependencies.
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Then, this class should do what you want. Just invoke the static method getParameterNames().
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;
public class ArgumentReflection {
/**
* Returns a list containing one parameter name for each argument accepted
* by the given constructor. If the class was compiled with debugging
* symbols, the parameter names will match those provided in the Java source
* code. Otherwise, a generic "arg" parameter name is generated ("arg0" for
* the first argument, "arg1" for the second...).
*
* This method relies on the constructor's class loader to locate the
* bytecode resource that defined its class.
*
* #param theMethod
* #return
* #throws IOException
*/
public static List<String> getParameterNames(Method theMethod) throws IOException {
Class<?> declaringClass = theMethod.getDeclaringClass();
ClassLoader declaringClassLoader = declaringClass.getClassLoader();
Type declaringType = Type.getType(declaringClass);
String constructorDescriptor = Type.getMethodDescriptor(theMethod);
String url = declaringType.getInternalName() + ".class";
InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url);
if (classFileInputStream == null) {
throw new IllegalArgumentException(
"The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: "
+ url + ")");
}
ClassNode classNode;
try {
classNode = new ClassNode();
ClassReader classReader = new ClassReader(classFileInputStream);
classReader.accept(classNode, 0);
} finally {
classFileInputStream.close();
}
#SuppressWarnings("unchecked")
List<MethodNode> methods = classNode.methods;
for (MethodNode method : methods) {
if (method.name.equals(theMethod.getName()) && method.desc.equals(constructorDescriptor)) {
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
List<String> parameterNames = new ArrayList<String>(argumentTypes.length);
#SuppressWarnings("unchecked")
List<LocalVariableNode> localVariables = method.localVariables;
for (int i = 1; i <= argumentTypes.length; i++) {
// The first local variable actually represents the "this"
// object if the method is not static!
parameterNames.add(localVariables.get(i).name);
}
return parameterNames;
}
}
return null;
}
}
Here's an example with a unit test.
public class ArgumentReflectionTest {
#Test
public void shouldExtractTheNamesOfTheParameters3() throws NoSuchMethodException, SecurityException, IOException {
List<String> parameterNames = ArgumentReflection
.getParameterNames(Clazz.class.getMethod("callMe", String.class, String.class));
assertEquals("firstName", parameterNames.get(0));
assertEquals("lastName", parameterNames.get(1));
assertEquals(2, parameterNames.size());
}
public static final class Clazz {
public void callMe(String firstName, String lastName) {
}
}
}
You can find the complete example on GitHub
Caveats
I slightly changed the original solution from #AdamPaynter to make it work for Methods. If I properly understood, his solution works only with constructors.
This solution does not work with static methods. This is becasue in this case the number of arguments returned by ASM is different, but it something that can be easily fixed.
You can't tell the name of the argument used.
You can retrieve the method signature with reflection and detect its argument types, however. Check getParameterTypes().
Parameter names are only useful to the compiler. When the compiler generates a class file, the parameter names are not included - a method's argument list only consists of the number and types of its arguments. So it would be impossible to retrieve the parameter name using reflection (as tagged in your question) - it doesn't exist anywhere.
However, if the use of reflection is not a hard requirement, you can retrieve this information directly from the source code (assuming you have it).
To add my 2 cents; parameter info is available in a class file "for debugging" when you use javac -g to compile the source. And it is available to APT but you'll need an annotation so no use to you. (Somebody discussed something similar 4-5 years ago here: http://forums.java.net/jive/thread.jspa?messageID=13467&tstart=0 )
Overall in-short you can't get it unless you work on Source files directly (similar to what APT does at compile time).
One simple method to read additional symbol informations from Java bytecode is:
Reflector reflector = new Reflector();
JavaMethod method = reflector.reflect(Whatever.class)
.getMethods()
.stream()
.filter(m -> "aMethod".equals(m.getName()))
.findFirst()
.get();
String paramName = method.getParameters().getVariables().get(0).getName();
System.out.println(paramName);
From Maven Central artifact:
<dependency>
<groupId>com.intersult</groupId>
<artifactId>coder</artifactId>
<version>1.5</version>
</dependency>

SoapUI/Groovy - Class defined but getting NoClassDefFoundError error

I am using Soap UI (Free version) v4.6.4. One of the test steps in my test case is to declare a class, which should be referred further in other groovy test steps; create instances and such. But to start with I tried the following in test step named ts01:
class SomeClass {
private String name
public SomeClass(String name) {
this.name = name
}
public print() {
log.info "SomeClass.print - " + this.name
}
}
// After the class definition, in the same groovy script
context.project = "myproject"
context.scinst = new SomeClass("hello")
log.info context
When I run this test step separately, I get the following error popup:
java.lang.NoClassDefFoundError: Could not initialize class SomeClass
error at line: XX
and randomly popping another error:
java.lang.ExceptionInInitializerError
When I run this test step as part of the test case, it runs but context.scinst is not available.
What am I missing? Why is SomeClass not available even though it is defined?
Your help is highly appreciated.
Thanks
Vivek Ragunathan

accessing non-statics from static method in groovy "script"

I have a groovy script named myScript.groovy that i run from command line using "java cp . myScript".
I am trying to add log4j logger to it, but keep getting the can't access non-static variable from static method kind of errors, and if i define logger as static the compiler complains saying i can't do that. The problem i realize is because this is a groovy script, and not a class.
I've tried the #Field, and #Log4j annotations without any luck. Can someone plz help me understand how to do this?
Following is how my code looks like:
myScript.groovy
def var1 = getVar1()
def var2 = getVar2()
Logger log = Logger.getLogger(getClass())
// #Log4j here gave compilation error
def static void doSomething()
{
// do something
// how to access log from this static method? defining log as static throws compilation error
log.info "trying to access logger from static method"
}
The #Log Annotation must be annotated on a class.
The following example from the docs works
import groovy.util.logging.*
#Log
class Car {
Car() {
log.info 'Car constructed'
}
}
def c = new Car()
If you need your method to be static, and if passing a parameter to the static method isn't a good option, you could have the method get its own reference to the named logger.
def static void doSomething()
{
Logger log = Logger.getLogger(getClass().getName())
// do something
// how to access log from this static method? defining log as static throws compilation error
log.info "trying to access logger from static method"
}

Resources