[HowTo] access Java classes when using one's own jars in Sikuli scripts

Asked by Wilson

**** SOLUTION

see comment #9

If you need more java classes, that are referenced from inside java code, you need to use another startup version:

java -cp jar1;jar2;jar3;path-to-sikuli-script.jar org.sikuli.script.SikuliScript path-to-your-script.sikuli

or using the IDE

java -cp jar1;jar2;jar3;path-to-sikuli-script.jar;sikuli-ide.jar org.sikuli.IDE.SikuliIDE - r path-to-your-script.sikuli

If you want to use the IDE GUI this way, you need additional Java options:

java -Xms64M -Xmx512M -Dfile.encoding=UTF-8 -cp jar1;jar2;jar3;path-to-sikuli-script.jar;sikuli-ide.jar org.sikuli.IDE.SikuliIDE

on Mac and Linux the classpath separator is the colon :

------------------------------------------------------------

I want to invoke a web service in Sikuli. And I have done the following things:
*Use Apache Axis2(wsdl2java) to generate Java code from the web service.
*Write my Java code to invoke the generated code by wsdl2java.
*Test my code in Eclipse, pass.
*Test my code in cmd(java -jar xx.jar), pass.

But when I use it in Sikuli, the problem occurs.

Part of the Sikuli code is like:
load('myown.jar')
load('axis2.jar')
load('other.jar')
from mypackage import MyClass
MyClass().method()

The exception is:
at org.apache.axiom.om.OMAbstractFactory.getMetaFactory(OMAbstractFactory.java:170)
at org.apache.axiom.om.OMAbstractFactory.getMetaFactory(OMAbstractFactory.java:135)
at org.apache.axiom.om.OMAbstractFactory.getOMFactory(OMAbstractFactory.java:184)
at org.apache.axis2.description.AxisDescription.(AxisDescription.java:72)
at org.apache.axis2.description.AxisService.(AxisService.java:323)
at org.apache.axis2.description.AxisService.(AxisService.java:394)
at com.wilson.input.InputServiceStub.populateAxisService(InputServiceStub.java:37)
at com.wilson.input.InputServiceStub.(InputServiceStub.java:94)
at com.wilson.input.InputServiceStub.(InputServiceStub.java:83)
at com.wilson.input.InputServiceStub.(InputServiceStub.java:130)
at com.wilson.input.InputServiceStub.(InputServiceStub.java:122)
at com.wilson.input.InputSimulator.type(InputSimulator.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
org.apache.axiom.om.OMException: org.apache.axiom.om.OMException: No meta factory found for feature 'default'; this usually means that axiom-impl.jar is not in the classpath

Seems that the classpath is not set correctly. I tried to modify the Sikuli-IDE-w.bat, adding '-classpath xxx' to the last 'start' line. But it still failed.
So I want to know how to make this running correctly.

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
Last query:
Last reply:
Revision history for this message
RaiMan (raimund-hocke) said :
#1

It seems, that all your generated/prepared stuff is Java code.

If this is right, then these load()'s are not needed. This only makes sense, if you have a .jar, that additionally has a Python layer according to the Sikuli extension structure.

So in your case, make sure, everything is on class path at runtime.

Since you are on Java anyway: Why don't you just stick with Java and use Sikuli's Java API?

If for some reason, you want to use Python scripting:
the -cp section must be inserted before the -jar entry in Sikuli-IDE-w.bat.

If this does not work, try this on command line:
java -cp your-classpath -jar path-to-sikuli-script.jar path-to-your-script.sikuli

Revision history for this message
Wilson (ttt43ttt) said :
#2

Without these load(), it cannot find my class. This may also be caused by the wrong classpath.

With your advice, I tried:
*add -cp myown.jar to Sikuli-IDE-w.bat
*java.exe -cp "myown.jar" -jar "sikuli-script.jar" "test.sikuli"
Neither of these works. It cannot find my java class without load('myown.jar').

Revision history for this message
RaiMan (raimund-hocke) said :
#3

with this command all 3 files
myown.jar
sikuli-script.jar
test.sikuli

must be in the same folder, which I cannot believe.

So supposing you have a regular Sikuli and Java 6 installation on a Windows 32 Bit:

%ProgramFiles%\Sikuli X\libs
%ProgramFiles%\Java\jre6\bin

are on system path

and you are on a command line being in the folder that holds test.sikuli

and your myown.jar is in c:\folder\subfolder

this should work:

java -cp c:\folder\subfolder\myown.jar -jar "%ProgramFiles%\Sikuli X\sikuli-script.jar" test.sikuli

Revision history for this message
Wilson (ttt43ttt) said :
#4

Sorry for my inaccurate statement. Actually I used the full path to those files(all of them are full path). I got the exception saying cannot find module 'wilson' (my java package is com.wilson.input).
The Sikuli and Java is installed through installer, which should be configured properly.
Is there something I still missed?

Revision history for this message
RaiMan (raimund-hocke) said :
#5

ok, then if your structure inside the myown.jar is com.wilson.input
which contains e.g. a MyClass, then in the script it has to be:

import com.wilson.input as cwi

cwi.MyClass.myClassMethod() # for a static method

or

mc = cwi.MyClass() # make an object
mc.myMethod() # for a (non-static) object method

this is just "pythonic" Java ;-)

Revision history for this message
Wilson (ttt43ttt) said :
#6

This is my command:
"C:\Program Files (x86)\Java\jre6\bin\java.exe" -cp "C:\Users\wilson\Desktop\test.sikuli\Input.jar" -jar "D:\Program Files (x86)\auto\Sikuli X\sikuli-script.jar" "C:\Users\wilson\Desktop\test.sikuli"

Content in test.sikuli is simple:
import com.wilson.input

This is the output:
[info] Sikuli vision engine loaded.
[info] Windows utilities loaded.
[info] VDictProxy loaded.
[error] Can't run this Sikuli script: C:\Users\wilson\Desktop\test.sikuli
Traceback (most recent call last):
  File "C:\Users\wilson\Desktop\test.sikuli\test.py", line 1, in <module>
    import com.wilson.input
ImportError: No module named wilson

My OS is win8 x64.

Revision history for this message
RaiMan (raimund-hocke) said :
#7

Ok I guess, this is a know Jython Problem: the top level name com is blocked by the bundled Jython interpreter (same problem exists with driver jar's for RDB access like mySQL, MSSQl, ...).

In your case, you have the choice to use a different package name without the first level com or something else like world ;-)

wilson as top level package name should be sufficient.

Revision history for this message
Wilson (ttt43ttt) said :
#8

Changing package name to org.wilson.input does not take effect.
This is really weird. :-(

Revision history for this message
RaiMan (raimund-hocke) said :
#9

This works:

- Java project:
use a package name, that does not start with any of the often used top-names like org, com, ... (blocked by Jython)
example in your case:
wilson.info

- the jar
-- no load() required
make a jar named wilson.jar
and place it in the your-script.sikuli folder
(other places are possible, but then you have to append this place to sys.path before issuing the import or use a load() with a path)
-- load() required
name the jar as you like and use
load("path-to-your.jar")
before the import

- in the IDE

--- no load: jar named as top level, jar in .sikuli folder
import wilson.info.SomeClass as SomeClass
# the jar will be found and loaded automatically
SomeClass.method()

--- simple load: jar named as top level, jar in same folder as script folder
load("..\\wilson.jar")
import wilson.info.SomeClass as SomeClass
# the jar will be found and loaded automatically
SomeClass.method()

in all other cases you need an adequate load() that specifies the path to the jar (relative or absolute).

--- This was my Java test source:

package raiman.stuff;
public class Case {
 public static void main(String[] args) {
  System.out.println("Hello");
 }
}

The jar for the different tests was named raiman.jar (no load() required is in .sikuli) or xraiman.jar (load() required in all cases)

--- This was my test.sikuli

# load("xraiman.jar") # inside .sikuli
# load("..\\xraiman.jar") # same folder as .sikuli
# load("c:\\folder\\subfolder\\xraiman.jar") # somewhere else

import raiman.stuff.Case as Case
Case.main(("",))
for e in sys.path: print e

Revision history for this message
Wilson (ttt43ttt) said :
#10

OK. What you said at #9 floor is quite right. Thanks for your quick reply very much!!
However, my wilson.jar invoked classes in Apache Axis2 jars. I export these jars from Eclipse to my test.sikuli folder.

The file structure is:
|--test.sikuli
|----wilson.jar
|----wilson_lib
|------axis2-kernel-1.6.2.jar
|------axiom-impl-1.2.13.jar
|------other-axis2-or-so.jar

No matter using load() or adding these jars to sys.path, all the classes can be found.
But it still throws an exception same as my original problem at #1.
The exception is:
org.apache.axiom.om.OMException: org.apache.axiom.om.OMException: No meta factory found for feature 'default'; this usually means that axiom-impl.jar is not in the classpath

This exception is thrown out from axiom's java source code. So maybe the diagnostic content 'axiom-impl.jar is not in the classpath' is wrong.
Hard to solve this, and I use a workaround now.

Revision history for this message
RaiMan (raimund-hocke) said :
#11

ok with this structure the stuff on the Python level works (Sikuli script).
( no need to use load(), since wilson.jar is inside the test.sikuli, where it is found automagically with Sikuli's import)

But I guess there are many places inside the Java stuff, that directly references other Java stuff, and this need the referenced Java stuff in wilson_lib to be in the class path.

The easiest option might be, to have the MANIFEST.MF in wilson.jar to have an adequate classpath entry (easy to make with Ant in Eclipse whe making the jar) pointing to the jars in wilson_lib.

Revision history for this message
Wilson (ttt43ttt) said :
#12

The content in MANIFEST.MF already has that. Part of the content is:
Manifest-Version: 1.0
Class-Path: . wilson_lib/axis2-fastinfoset-1.6.2.jar wilson_lib/axis2-...
...
Main-Class: wilson.input.MyJavaClass

Revision history for this message
RaiMan (raimund-hocke) said :
#13

Ok, I just realized, that this might be the wrong option, since it might be, that the MANIFEST.MF is only processed, if the .jar is loaded by Java directly.

To check it:

after wilson stuff is imported successfully:

for e in java.lang.System.getProperty("java.class.path").split(";"): print e

and check it.

Revision history for this message
Wilson (ttt43ttt) said :
#14

It just has one record - D:\Program Files (x86)\auto\Sikuli X\sikuli-ide.jar

Revision history for this message
RaiMan (raimund-hocke) said :
#15

Ok, that is not enough ;-)

I come back to my previous -cp suggestion:

on commandline or in some batch file:

set BASE=test.sikuli
set MYCP=%BASE%\wilson_lib\axis2-kernel-1.6.2.jar;%BASE%\wilson_lib\axiom-impl-1.2.13.jar;%BASE%\wilson_lib\other-axis2-or-so.jar

java -cp %MYCP% -jar .... (see above)

running this from the folder that contains the test.sikuli should make it.

or you might add this to the Sikuli-IDE-w.bat

In the script, you might check the working dir with:
print java.lang.System.getProperty("user.dir")

Revision history for this message
Wilson (ttt43ttt) said :
#16

I add these jars to -cp as you said.
But the 'print java.lang.System.getProperty("java.class.path")' output is:
D:\Program Files (x86)\auto\Sikuli X\sikuli-script.jar
It always has only this one! :-(

Revision history for this message
Best RaiMan (raimund-hocke) said :
#17

Yiiippppiiiieeee, found the trick:

set BASE=test.sikuli
set MYCP=%BASE%\wilson_lib\axis2-kernel-1.6.2.jar;%BASE%\wilson_lib\axiom-impl-1.2.13.jar;%BASE%\wilson_lib\other-axis2-or-so.jar
set MYCP=%MYCP%;D:\Program Files (x86)\auto\Sikuli X\sikuli-script.jar

java -cp "%MYCP%" org.sikuli.script.SikuliScript test.sikuli

all jars including sikuli-script.jar must be in the class path, no jar is run, but the SikuliScript class instead.

Revision history for this message
Wilson (ttt43ttt) said :
#18

Yes!! It works!!
RaiMan, thank you very much, for your patience and investigation :-)

Revision history for this message
Wilson (ttt43ttt) said :
#19

Thanks RaiMan, that solved my question.

Revision history for this message
RaiMan (raimund-hocke) said :
#20

Thanks for feedback.

This was a fact I wasn't aware before. So I tried to get a solution,to further improve things with the upcoming new version.

So I also thank you, for having walked with me down the road.