SoapUI/Groovy - Class defined but getting NoClassDefFoundError error - groovy

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

Related

GroovyScriptEngine throws MultipleCompilationErrorsException while loading class that uses other class' static inner class

I'm running into a problem with GroovyScriptEngine - it seems not to be able to work with inner classes. Anyone know whether there's some limitation in GroovyScriptEngine or a workaround?
I have a directory with these two files:
// MyClass.groovy
public class MyClass {
MyOuter m1;
MyOuter.MyInner m2;
}
and
// MyOuter.groovy
public class MyOuter {
public static class MyInner {}
}
I have a following test class:
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import groovy.util.GroovyScriptEngine;
public class TestGroovyScriptEngine {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
final File myGroovySourceDir = new File("C:/MyGroovySourceDir");
final URL[] urls = { myGroovySourceDir.toURL() };
GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine(urls,
Thread.currentThread().getContextClassLoader());
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
}
}
When I run it I get the following compilation error:
Exception in thread "main" org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
C:\MyGroovySourceDir\MyClass.groovy: 3: unable to resolve class MyOuter.MyInner
# line 3, column 2.
MyOuter.MyInner m2;
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:311)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:983)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:633)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:582)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:354)
at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:87)
at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:323)
at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:320)
at org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache.getAndPut(ConcurrentCommonCache.java:147)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:318)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.doParseClass(GroovyScriptEngine.java:248)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.parseClass(GroovyScriptEngine.java:235)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:307)
at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:811)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:767)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:836)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:824)
I would have expected a "clean compile", but the inner class seems to be causing problems.
My groovy classes compile fine at the command line using groovyc, or in Eclipse.
You have faced an edge case here. To clarify what happens let's define the initial conditions:
you have a Java (or Groovy) class that gets executed inside JVM
you have two Groovy classes that get loaded outside of the JVM
The problem you have described does not exist if you put these two Groovy classes inside the same path you execute your Java class from - in this case IDE takes care to compile these Groovy classes and put them to the classpath of a JVM that gets started to run your Java test class.
But this is not your case and you are trying to load these two Groovy classes outside the running JVM using GroovyClassLoader (which extends URLClassLoader btw). I will try to explain in the simplest possible words what happened that adding field of type MyOuter does not throw any compilation error, but MyOuter.MyInner does.
When you execute:
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
Groovy class loader goes to script file lookup part, because it was not able to find MyClass in the current classpath. This is the part responsible for it:
// at this point the loading from a parent loader failed
// and we want to recompile if needed.
if (lookupScriptFiles) {
// try groovy file
try {
// check if recompilation already happened.
final Class classCacheEntry = getClassCacheEntry(name);
if (classCacheEntry != cls) return classCacheEntry;
URL source = resourceLoader.loadGroovySource(name);
// if recompilation fails, we want cls==null
Class oldClass = cls;
cls = null;
cls = recompile(source, name, oldClass);
} catch (IOException ioe) {
last = new ClassNotFoundException("IOException while opening groovy source: " + name, ioe);
} finally {
if (cls == null) {
removeClassCacheEntry(name);
} else {
setClassCacheEntry(cls);
}
}
}
Source: src/main/groovy/lang/GroovyClassLoader.java#L733-L753
Here URL source = resourceLoader.loadGroovySource(name); it loads the full file URL to the source file and here cls = recompile(source, name, oldClass); it executes class compilation.
There are several phases involved in Groovy class compilation. One of them is Phase.SEMANTIC_ANALYSIS which analyses class fields and their types for instance. At this point ClassCodeVisitorSupport executes visitClass(ClassNode node) for MyClass class and following line
node.visitContents(this);
starts class contents processing. If we take a look at the source code of this method:
public void visitContents(GroovyClassVisitor visitor) {
// now let's visit the contents of the class
for (PropertyNode pn : getProperties()) {
visitor.visitProperty(pn);
}
for (FieldNode fn : getFields()) {
visitor.visitField(fn);
}
for (ConstructorNode cn : getDeclaredConstructors()) {
visitor.visitConstructor(cn);
}
for (MethodNode mn : getMethods()) {
visitor.visitMethod(mn);
}
}
Source: src/main/org/codehaus/groovy/ast/ClassNode.java#L1066-L108
we will see that it analyses and process class properties, fields, constructors and methods. At this phase it resolves all types defined for these elements. It sees that there are two properties m1 and m2 with types MyOuter and MyOuter.MyInner accordingly, and it executes visitor.visitProperty(pn); for them. This method executes the one we are looking for - resolve()
private boolean resolve(ClassNode type, boolean testModuleImports, boolean testDefaultImports, boolean testStaticInnerClasses) {
resolveGenericsTypes(type.getGenericsTypes());
if (type.isResolved() || type.isPrimaryClassNode()) return true;
if (type.isArray()) {
ClassNode element = type.getComponentType();
boolean resolved = resolve(element, testModuleImports, testDefaultImports, testStaticInnerClasses);
if (resolved) {
ClassNode cn = element.makeArray();
type.setRedirect(cn);
}
return resolved;
}
// test if vanilla name is current class name
if (currentClass == type) return true;
String typeName = type.getName();
if (genericParameterNames.get(typeName) != null) {
GenericsType gt = genericParameterNames.get(typeName);
type.setRedirect(gt.getType());
type.setGenericsTypes(new GenericsType[]{ gt });
type.setGenericsPlaceHolder(true);
return true;
}
if (currentClass.getNameWithoutPackage().equals(typeName)) {
type.setRedirect(currentClass);
return true;
}
return resolveNestedClass(type) ||
resolveFromModule(type, testModuleImports) ||
resolveFromCompileUnit(type) ||
resolveFromDefaultImports(type, testDefaultImports) ||
resolveFromStaticInnerClasses(type, testStaticInnerClasses) ||
resolveToOuter(type);
}
Source: src/main/org/codehaus/groovy/control/ResolveVisitor.java#L343-L378
This method gets executed for both MyOuter and MyOuter.MyInner classes. It is worth mentioning that class resolving mechanism only checks if given class is available in the classpath and it does not load or parse any classes. That is why MyOuter gets recognized when this method reaches resolveToOuter(type). If we take a quick look at its source code we will understand why it works for this class:
private boolean resolveToOuter(ClassNode type) {
String name = type.getName();
// We do not need to check instances of LowerCaseClass
// to be a Class, because unless there was an import for
// for this we do not lookup these cases. This was a decision
// made on the mailing list. To ensure we will not visit this
// method again we set a NO_CLASS for this name
if (type instanceof LowerCaseClass) {
classNodeResolver.cacheClass(name, ClassNodeResolver.NO_CLASS);
return false;
}
if (currentClass.getModule().hasPackageName() && name.indexOf('.') == -1) return false;
LookupResult lr = null;
lr = classNodeResolver.resolveName(name, compilationUnit);
if (lr!=null) {
if (lr.isSourceUnit()) {
SourceUnit su = lr.getSourceUnit();
currentClass.getCompileUnit().addClassNodeToCompile(type, su);
} else {
type.setRedirect(lr.getClassNode());
}
return true;
}
return false;
}
Source: src/main/org/codehaus/groovy/control/ResolveVisitor.java#L725-L751
When Groovy class loader tries to resolve MyOuter type name it reaches
lr = classNodeResolver.resolveName(name, compilationUnit);
which locates script with a name MyOuter.groovy and it creates a SourceUnit object associated with this script file name. It is simply something like saying "OK, this class is not in my classpath at the moment, but there is a source file I can see that once compiled it will provide a valid type of name MyOuter". This is why it finally reaches:
currentClass.getCompileUnit().addClassNodeToCompile(type, su);
where currentClass is an object associated with MyClass type - it adds this source unit to MyClass compilation unit, so it gets compiled with the MyClass class. And this is the point where resolving
MyOuter m1
class property ends.
In the next step it picks MyOuter.MyInner m2 property and it tries to resolve its type. Keep in mind - MyOuter got resolved correctly, but it didn't get loaded to the classpath, so it's static inner class does not exist in any scope, yet. It goes through the same resolving strategies as MyOuter, but any of them works for MyOuter.MyInner class. And this is why ResolveVisitor.resolveOrFail() eventually throws this compilation exception.
Workaround
OK, so we know what happens, but is there anything we can do about it? Luckily, there is a workaround for this problem. You can run your program and load MyClass successfully only if you load MyOuter class to Groovy script engine first:
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import groovy.util.GroovyScriptEngine;
public class TestGroovyScriptEngine {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
final File myGroovySourceDir = new File("C:/MyGroovySourceDir");
final URL[] urls = { myGroovySourceDir.toURL() };
GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine(urls,
Thread.currentThread().getContextClassLoader());
groovyScriptEngine.getGroovyClassLoader().loadClass("MyOuter");
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
}
}
Why does it work? Well, semantic analysis of MyOuter class does not cause any problems, because all types are known at this stage. This is why loading MyOuter class succeeds and it results in Groovy script engine instance knows what MyOuter and MyOuter.MyInner types are. So when you next load MyClass from the same Groovy script engine it will apply different resolving strategy - it will find both classes available to the current compilation unit and it wont have to resolve MyOuter class based on its Groovy script file.
Debugging
If you want to examine this use case better it is worth to run a debugger and see analyze what happens at the runtime. You can create a breakpoint at line 357 of ResolveVisitor.java file for instance, to see described scenario in action. Keep in mind one thing though - resolveFromDefaultImports(type, testDefaultImports) will try to lookup MyClass and MyOuter classes by applying default packages like java.util, java.io, groovy.lang etc. This resolve strategy kicks in before resolveToOuter(type) so you have to patiently jump through them. But it is worth it to see and get a better understanding about how things work. Hope it helps!

Groovy: #Immutable results in Setters

I'm having trouble with (or I'm confused about) using #Immutability.
Given this class:
#Immutable
class TestField {
String key
}
I would expect I could not set a key on an instance like:
class TestFieldSpec extends Specification {
def 'do stuff'() {
when:
def t = new TestField('a')
println t
t.key = 'b'
println t
then:
t
}
}
However, when I run the test, I do not see a ReadOnlyPropertyException:
Running TestFieldSpec
TestField(a)
TestField(b)
This has been the case for me using both the groovy-eclipse-compiler and gmaven-plus with Maven.
Groovy version 2.4.7.
If I run javap on the class file created by both, I see:
public final void setKey(java.lang.String);
When I do the same in GroovyConsole though, things work how I'd expect them to.
#groovy.transform.Immutable
class TestField {
String key
}
def f = new TestField('a')
f.key = 'b'
Produces:
Exception thrown
groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: key for class: TestField
at TestField.setProperty(ConsoleScript1)
at ConsoleScript1.run(ConsoleScript1:7)
In the Groovy AST Browser, at Phase Finalization, I do not see the setter.
Any insight would be greatly appreciated.
Thanks!

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"
}

Not able to dynamically add method to Groovy using metaClass from within instance

I'm afraid I'm a beginner in Groovy so this might be very silly. (using groovy 2.3.4)
I have the following code:
class Test {
public void method() {
def methodName = "dynamicMethodName"
this.metaClass."$methodName" = {->}
this."${methodName}"()
}
}
new Test().method()
Running this will throw the following error:
Caught: groovy.lang.MissingPropertyException: No such property: dynamicMethodName for class: groovy.lang.MetaClassImpl
groovy.lang.MissingPropertyException: No such property: dynamicMethodName for class: groovy.lang.MetaClassImpl
at Test.method(what.groovy:5)
at Test$method.call(Unknown Source)
at what.run(what.groovy:10)
Can someone help me figure out what I am doing wrong? I also tried not being 'too dynamic' and altered the code like so:
class Test {
public void method() {
this.metaClass.dynamicMethodName = {->}
this.dynamicMethodName()
}
}
new Test().method()
But I still get the same error
UPDATE
It seems that if I add the method outside the class by using an instance reference instead of using this, it works.
Is there no way to dynamically add methods for an instance from within the instance itself?
It turns out, if the class extends the class Expando, it works.
Answer found here: https://stackoverflow.com/a/7079038/56242

Unable to create a mock object of a class in a different project

I am trying to create a mock object of a class which is in a different project but I am unable to do so.
I have tried mocking it with PowerMock,PowerMockito and EasyMock.
It gives me java.lang.reflect.InvocationTargetException exception.
In my test method of Class A
#Test
public void doTestMethod(){
XYZ mockXYZ=PowerMock.createMock(XYZ.class);
Once this is created I have to mock the execute Method inside the XYZ class.
}
my Class XYZ looks like this
Class XYZ
{
private XYZ(){
some initialization of variables;
}
public parameterizaed constructor(parameters){
}
public void execute(){
}
}
This XYZ class in a different project
Actually the error was resolved it was basically adding the other project in the pom.xml of my project so that at run time it would load the class that I want.

Resources