Groovy Error: Unable to resolve class internal.GlobalVariable

Hey, listen, don’t for one second think what you have to say is falling on deaf ears - the Katalon devs pay attention to what we say here. The rapid take-up of the suggestions posted here are a testament to that. It’s just frustrating as hell when a quirky bug seems to sit around unattended for so long.

Also, there might be the germ of an idea in what you’ve reported… so you did the right thing sticking to your guns (and almost getting me to shut up) :rofl:

It clearly shows the CustomKeywords are parsed and compiled before the GlobalVariables .

For me, the solution was to use the ‘Ctrl-Shift-O’ magic every time I write a custom keyword.
That will get rid of any unused import in the given script/class.
And since I never use GlobalVariables in a custom keyword (if i really have to use a global i will pass it as a parameter to the method from the actual running script) all such ‘cannot resolve’ errors disappeared, no matter if i am running from docker or not.
But could be just me doing that … I have suggested long time ago that using this import into the generated template has no real benefit. It won’t solve the issue for already made projects, but can solve it for new projects.

However, for some reason this was just ignored and still at the latest version the template is adding the internal.GlobalVariables import for any new keyword class generated. Why? only asgards may say … or i am too dumb to figure out why somebody will need to use it in a Keyword class

LE: i am not suggesting that import of Globals are useless.
Just make no sense in the custom keyword classes.
If one will really need it there, perhaps he/she may have to reconsider the project approach.
In the test scripts yeah… nice to have it already there, just in case you forgot to add it.
just saying … please don’t shoot me …

also, to be noticed by the katalon dev teams that, always, the docker hub is behind the actual release by at least one version (sometime two).
e.g. as per today writing the latest katalon studio release is 6.x as per changelog:
https://docs.katalon.com/katalon-studio/new/version-60.html

but the latest docker hub image is 5.10.1

this is not good and you guys have no excuse to do such trivial mistakes.

@Kelly_Ferrone1, @miguel.acosta My apology for this issue. We will release an update next week to resolve it - and to include more debug information in case it still happens. This issue will be our key focus in upcoming releases.

Russ,

I tried to reproduce your problem on my side. Let me explain what I have done.

I made a new project with Katalon Studio 5.10.1. It has an Execution Profile named default, which contains a GlobalVariable with name $FOO and with value bar as the following screenshot shows.

I found /Libs/internal/GlobalVariable.groovy file, of which content is as follows:

package internal

import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.testobject.ObjectRepository as ObjectRepository
import com.kms.katalon.core.testdata.TestDataFactory as TestDataFactory
import com.kms.katalon.core.testcase.TestCaseFactory as TestCaseFactory
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase

/**
 * This class is generated automatically by Katalon Studio and should not be modified or deleted.
 */
public class GlobalVariable {

    /**
     * <p></p>
     */
    public static Object $FOO


    static {
        def allVariables = [:]
        allVariables.put('default', ['$FOO' : 'bar'])

        String profileName = RunConfiguration.getExecutionProfile()
        def selectedVariables = allVariables[profileName]

		for(object in selectedVariables){
			String overridingGlobalVariable = RunConfiguration.getOverridingGlobalVariable(object.key)
			if(overridingGlobalVariable != null){
				selectedVariables.put(object.key, overridingGlobalVariable)
			}
		}

        $FOO = selectedVariables["$FOO"]

    }
}

In the above code, I noticed the following line looks problematic.

        $FOO = selectedVariables["$FOO"]

The portion "$FOO" will be regarded as an instance of GString. Groovy lang will try to find a variable named FOO and interpolate the FOO value with $FOO portion inside the pair of double quotes. But no FOO variable will be found. Therefore a compilation problem will occur, I would expect.

I wrote a test case:

When I ran this test case, I got the following log.

2019-02-24 22:23:41.721 INFO  c.k.katalon.core.main.TestCaseExecutor   - --------------------
2019-02-24 22:23:41.730 INFO  c.k.katalon.core.main.TestCaseExecutor   - START Test Cases/TC1
2019-02-24 22:23:42.635 ERROR c.k.katalon.core.main.TestCaseExecutor   - ❌ Test Cases/TC1 FAILED.
Reason:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
file:/Users/urayamakazuaki/katalon-workspace/GlobalVariableTest/Scripts/TC1/Script1551013468989.groovy: 4: unable to resolve class internal.GlobalVariable
 @ line 4, column 1.
   import internal.GlobalVariable as GlobalVariable
   ^

1 error

	at com.kms.katalon.core.main.ScriptEngine.getScript(ScriptEngine.java:199)
	at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
	at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
	at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:328)
	at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:319)
	at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:298)
	at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:290)
	at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:224)
	at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:106)
	at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:97)
	at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
	at TempTestCase1551014615998.run(TempTestCase1551014615998.groovy:22)

2019-02-24 22:23:42.651 INFO  c.k.katalon.core.main.TestCaseExecutor   - END Test Cases/TC1

@Russ_Thomas,

Could you tell me if I successfully reproduced your problem in the above case? Or is your problem different?

It’s interesting to see; if Katalon Studio generates the following code:

$FOO = selectedVariables['$FOO']

It’s OK. The code works.

I find no reason why Katalon Studio generates "$FOO" , rather than '$FOO' . It looks to be a unfortunate mistake.

Yes, I think you did. Here’s the dump from my groovy file

Yep. 5.4.x certainly does produce ‘$x’.

@devalex88 suspects someone altered a build template incorrectly.

I remember what.

At Version 5.4.0, Katalon Studio introduced “Execution Profile”. See the release note.
https://docs.katalon.com/katalon-studio/new/version-540.html#test-execution

Prior to 5.4.0, all we had was the term “Global Variable” and we did not have the term “Execution Profile”. In other words, we had a single Execution Profile, what we call “default” now, but we could not have multiple sets of global variables. In order to support multiple sets of global variables, Katalon Studio significantly changed the code format of <projectDir>/Libs/internal/GlobalVariable.groovy. I am quite sure that the following code fragment newly appeared at that time.

        $FOO = selectedVariables["$FOO"]

Why do I remember this so clearly? Well, the following post of mine at March 2018 motivated, I believe, Katalon team to introduce the “Execution Profile” concept: multiple sets of global variables.

@devalex88

Now I believe you see what you should do. Too simple, isn’t it?

But I’m on 5.4.2 and I have multiple profiles and I have a working ‘$WE_ACTIVE’ variable.

Ah, certainly your case seems to be a bit more complexed as the Exception you got was

java.lang.NoClassDefFoundError: Could not initialize class internal.GlobalVariable
	at com.xxxxxx.basePage.<init>(basePage.groovy:50)
	at com.xxxxxx.home.<init>(home.groovy)
	at Test Access The Big Four.run(Test Access The Big Four:110)
	at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
        ...

This is not a simple compilation error. There seems to be more factors to investigate.

What is com.xxxxxx.basePage? Is it a custom Page Object class you made, Russ?

Could you please let us have a look at the lines around basePage.groovy:50?

Is it in a static method or a static block? I am asking this because jar - java.lang.NoClassDefFoundError: Could not initialize class XXX - Stack Overflow tells me that java.lang.NoClassDefFoundError: Could not initialize class xxxx is related to something about ClassLoader.

You are getting a java.lang.NoClassDefFoundError which does NOT mean that your class is missing (in that case you’d get a java.lang.ClassNotFoundException ). The ClassLoader ran into an error while reading the class definition when trying to read the class.

My thought: if you Libs/internal/GlobalVariable.grooy has the following code:

      $WE_ACTIVE = selectedVariables["$WE_ACTIVE"]

then, Groovy lang will try to find a property named WE_ACTIVE somewhere in the internal.GlobalVariable class. Groovy lang will try to find WE_ACTIVE as an instance property as well as an static property. If com.xxxxxx.basePage.&lt;init&gt;(basePage.groovy:50) tries to load the internal.GlobalVarialbe class in a static block, then I presume that the ClassLoader may fail to load it and throw NoClassDefFoundError, because the classloader can not find an instance property named WE_ACTIVE.

I do not see what you mean by saying this. Could you elaborate it?


@Russ_Thomas,

Could you try one thing for me?

Your ./Libs/internal/GlobalVariable.groovy file has a line of

$WE_ACTIVE = selectedVariables["$WE_ACTIVE"]

as the following screenshot shows, which you previously attached.

Please edit the file with your favorite text editor as follows:

$WE_ACTIVE = selectedVariables['$WE_ACTIVE']

I mean, enclose $WE_ACTIVE with a pair of single quotes, rather than double quites. Save the change, then try running your test. I guess it would run successful. I want to see if this is the case or not.

I meant, in 5.4 Katalon produces that reference (single quotes) and it works fine. In 5.10+ it generates the same line with double-quotes and shoots itself in the foot.

But that’s the point, Kaz, if I edit the file, once it’s edited and I run a test, Katalon will overwrite it and break it again (at least, I’m assuming it would, I’ve never actually tried).

Yes. In Katalon parlance, it’s a “keyword class”, so public class basePage. My Test Cases extend a specific page class, the page class extends basePage.

Line 50 is literally the basePage constructor:

basePage() { ...

The lines before it are field definitions for the class. IOW, nothing weird.

No, it’s not a static block.

Kaz, I really appreciate your forensic analysis – it’s quite extraordinary. However, you don’t need to look further than the error as depicted in the screenshot. When I double-click the error in the Problems panel, Katalon takes me to the GlobalVariable.groovy file and highlights the $WE_ACTIVE just like the screenshot shows (IOW, I didn’t make it blue, that’s Katalon doing that!) And notice it does not include the $ in the highlight… because it thinks $ is the placeholder marker and the problem is the reference it cannot resolve. Well it’s not a reference, it’s the damn name!

To cut this short, there is an alternative to editing the GV file and changing the quotes - I could change the name to be WE_ACTIVE (i.e. get rid of the $). And guess what - that works. No issues. While @devalex88 and I were looking at it, that worked just fine.

The unfortunate thing is, I have good reason to need the $ in the name (it’s meaningful in the AUT and meaningful to reflect it correctly in the Tests).

However, pragmatism will rule the day - if this cannot be fixed in the next “proper” release of Katalon (6.0.4 is not proper in my view) I will alter the name and remove the $.

Thanks for the research, Kaz. It’s much appreciated! :sunglasses:

No. Once I have ever tried it in my “$FOO” sample project. Katalon did not overwrite the GlobalVariable.groovy source file which I manually edited "$FOO" to '$FOO' when I run my tests. My test once failed but after edit the GlobalVariable.groovy source it turned to succeed. In order to let it fail again, I had to edit it back to "$FOO" and delete the <projectDir>/bin directory so that Katalon Studio compiles the GlobalVariable.groovy source file.

Yes, I understand it.

The point is clear now to everyone who read this thread.

Wow. That’s really surprising.

Not surprising to me.

In <projectDir>/Profiles directory, you will find default.glbl and other *.glbl files. For example, let me show a default.glbl of an example project.

<?xml version="1.0" encoding="UTF-8"?>
<GlobalVariableEntities>
   <description></description>
   <name>default</name>
   <tag></tag>
   <defaultProfile>true</defaultProfile>
   <GlobalVariableEntity>
      <description></description>
      <initValue>'bar'</initValue>
      <name>$FOO</name>
   </GlobalVariableEntity>
</GlobalVariableEntities>

When you edit a Execution Profile ‘default’ using Katalon Studio’s GUI, the edit result will be saved into this ‘global.glbl’ file in XML format.

After then, when a test runs, Katalon Studio reads all of the <projectDir>/Profiles/*.glbl files and generates a single <projectDir>/bin/internal/GlobalVariable.grooy source file, and compiles it into an executable *.class file.

GUI -> XML -> *.groovy -> *.class

This is the way Katalon Studio works, I suppose.

You have a chance to edit manually the GlobalVariable.groovy file which will not be overwritten by Katalon Studio as far as *.glbl XML files stay the same.

4 Likes

Perfect explanation, Kaz. Thank you very much.

The root cause of our problem ('$WE_ACTIVE' or "$WE_ACTIVE") resides in this code generation processing, I believe.