0

I use this tutorial to connect to Gmail API: https://developers.google.com/gmail/api/quickstart/java I would like to make a keyword in Katalon Studio, which depends on Gmail API. I modified from sample code that line:

InputStream in = GmailQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);

to this:

InputStream ins = new FileInputStream(CREDENTIALS_FILE_PATH);

JAR files are added, project is running and browser window is opened to get token. After successful authorization I got error message:

Caused by: java.lang.NoSuchMethodError: com.google.api.client.http.HttpRequest.setResponseReturnRawInputStream(Z)Lcom/google/api/client/http/HttpRequest;

UPDATE: List of imported dependencies:

commons-codec-1.15.jar
commons-logging-1.2.jar
google-api-client-1.31.3.jar
google-api-client-extensions-1.6.0-beta.jar
google-api-client-jackson2-1.31.3.jar
google-api-client-java6-1.31.3.jar
google-api-services-gmail-v1-rev110-1.25.0.jar
google-http-client-1.39.1.jar
google-http-client-jackson2-1.39.1.jar
google-oauth-client-java6-1.31.4.jar
google-oauth-client-jetty-1.31.4.jar
guava-30.1.1-jre.jar
httpclient-4.5.13.jar
httpcore-4.4.14.jar
j2objc-annotations-1.3.jar
jackson-core-2.12.2.jar
jsr305-3.0.2.jar
plaidshirt
  • 5,189
  • 19
  • 91
  • 181

1 Answers1

1

https://docs.katalon.com/katalon-studio/docs/external-libraries.html#exclude-built-in-libraries

With the ability to remove built-in libraries stored in the .classpath file of a project folder, you can replace a built-in library with an external one for flexible libraries usage in a test project.

Requirements

  • An active Katalon Studio Enterprise license.
  • Katalon Studio version 7.8.

UPD:

i got katalon 7.9.1 and here how i was able to do it:

add the following class into KS project:

include/scripts/groovy/(default package)/GroovyBox.java

import groovy.lang.*;
import java.util.regex.Pattern;
import java.util.Map;
import java.util.List;

/** run groovy script in isolated classloader*/
public class GroovyBox {
    GroovyShell gs;
    
    public GroovyBox(ClassLoader parentCL, Pattern excludeClassPattern ) {
        FilteredCL fcl = new FilteredCL(parentCL, excludeClassPattern);
        gs = new GroovyShell(fcl);
    }
    
    public GroovyBox withClassPath(List<String> classPathList) {
        GroovyClassLoader cl = gs.getClassLoader();
        for(String cp: classPathList) cl.addClasspath(cp);
        return this;
    }
    
    public Script parse(String scriptText) {
        return gs.parse(scriptText);
    }
    
    public static class FilteredCL extends GroovyClassLoader{
        Pattern filterOut;
        
        public FilteredCL(ClassLoader parent,Pattern excludeClassPattern){
            super(parent);
            filterOut = excludeClassPattern;
        }
        
        @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
            if(filterOut.matcher(name).matches())throw new ClassNotFoundException("class not found "+ name);
            return super.loadClass(name, resolve);
        }
    }
}

now add a test case - actually you can move code from test case into a class...

import ... /* all katalon imports here*/

assert method1() == 'HELLO WORLD'

def method1() {
    def gb = new GroovyBox(this.getClass().getClassLoader().getParent(), ~/^com\.google\..*/)
    def script = gb.parse('''
            @Grab(group='com.google.api-client', module='google-api-client', version='1.31.3')
            import com.google.api.client.http.HttpRequest

            def c = HttpRequest.class
            println( "methods execute:: "+c.methods.findAll{it.name=='execute'} )
            println( "methods setResponseReturnRawInputStream:: "+c.methods.findAll{it.name=='setResponseReturnRawInputStream'} )
            println greeting
            return greeting.toUpperCase()
        ''')
    script.setBinding([greeting:'hello world'] as Binding)
    return script.run()
}

options to define external dependencies:

  • @Grab(...) as a first line of parsed script - loads all required dependencies from maven central (by default). for example @Grab(group='com.google.api-client', module='google-api-client', version='1.31.3') corresponds to this artifact.
  • sometimes you need to specify specific maven repository then add @GrabResolver(name='central', root='https://repo1.maven.org/maven2/')
  • if you want to specify local file dependencies then in the code above:
def gb = new GroovyBox(...).withClassPath([
    '/path/to/lib1.jar',
    '/path/to/lib2.jar'
])

enter image description here

daggett
  • 26,404
  • 3
  • 40
  • 56
  • Thanks, but I use free edition of KS, so I can't use this feature. – plaidshirt Apr 05 '21 at 10:44
  • 1
    i've added an idea how to execute script with custom classloader – daggett Apr 05 '21 at 14:19
  • I have got following error message: `Groovy:unexpected token: @` It is for @Grab. – plaidshirt Apr 08 '21 at 08:02
  • seems KS does not support @Grab annotation. remove everything before `< --- end test`, remove `@Grab` from script, add all required libraries in the following way: `gs.getClassLoader().addClasspath​("path\to\lib.jar")` before `script.parse` – daggett Apr 08 '21 at 12:07
  • 1
    downloaded KS - made changes to answer – daggett Apr 08 '21 at 15:06
  • I copied my whole groovy script to be parameter of `parse()` method, but imported classes are not resolved, I get error messages like this during execution: _Script1.groovy: 45: unable to resolve class com.google.api.services.gmail.model.Label_ I am not sure, where to add Drivers folder to classpath. – plaidshirt Apr 09 '21 at 10:13
  • 1
    i've added support to define local libraries and some explanation about grab – daggett Apr 09 '21 at 13:35