[Kde-java] QtJava rewritten as a SMOKE adaptor?

Richard Dale Richard_Dale at tipitina.demon.co.uk
Thu Aug 7 18:27:10 CEST 2003


I've spent the last month or so implementing QtRuby, which interfaces with 
Ashley Winter's language independent SMOKE bindings for Qt. It went really 
well, and already QtRuby can do things that QtJava can't - such as override 
all virtual methods, rather than just some of them. The advantage of using 
SMOKE is that you only need to write a relatively simple 'adaptor' for a new 
language. You don't have to start all over everytime and generate all the 
'bridge' C++ classes that actually call the Qt C++ methods, and do virtual 
method callbacks to the target language - that's all in the SMOKE library.

The existing QtJava/Koala java bindings work well enough, but are quite hard 
to extend for things like adding all the missing virtual method callbacks, 
java serialization or dynamic DCOP support. 

So I've been thinking about how to implement the same thing for QtJava for the 
past couple of days, and can see how it might work now. At the moment each Qt 
C++ method has a corresponding java native method, and the code in the JNI 
method calls the C++ one like this:

In QApplication.java:

	public native int exec();

In QApplication.cpp:

JNIEXPORT jint JNICALL
Java_org_kde_qt_QApplication_exec(JNIEnv *env, jobject obj)
{
	return (jint) ((QApplication*) QtSupport::getQt(env, obj))->exec();
}

The getQt() call just gets the corresponding C++ instance for the java one, 
and calls QApplication::exec() with it.

The new SMOKE approach will do away with the need to generate all the C++ JNI 
based sources like QApplication.cpp/QApplication.h and so on - a BIG plus. 
The current 90000 lines of C++ code in the project will drop to about 3000.

Instead, exec() in QApplication.java will look like this:

public int exec() {
	return proxy.exec().intValue();
}

Rather than directly use a native JNI method, the call to exec is handed off 
to a java.lang.reflect.Proxy instance - 'proxy'. Java Proxies only implement 
one method to do anything, called invoke(), and the exec() call is translated 
into an invoke() one via reflection machinery in Proxy.

public Object invoke(Object proxy, Method method, Object[] args);

invoke() will then call a single global JNI function which actually marshalls 
the java argument values onto the C++ smoke stack, and invokes the target C++ 
method via the SMOKE runtime.

The 'proxy' instance variables will need to be created in the constructors. 
Every Qt class like QApplication.java will need to have a corresponding 
interface QApplicationInterface.java so that all the methods the proxy 
expects to handle can be given via an array of these interface classes (for 
the current class and its parents).

QApplicationInterface proxy;
...

proxy = (QApplicationInterface) Proxy.newProxyInstance(
						QApplication.class.getClassLoader(),
						new Class[] { QApplicationInterface.class },
						new QtProxy() );

I don't know if this makes sense, but I thought it would be a good idea to at 
least start discussing what to do about QtJava/Koala for KDE 3.2.

-- Richard



More information about the Kde-java mailing list