well, I finally found a way to solve this:
The key is: I MUST use pointers (in my case boost::shared:ptr).
So my Messages (messages.h) now look like this:
typedef boost::shared_ptr<CoreMessage> CoreMessagePtr;
public class CoreMessage {
...
}
typedef boost::shared_ptr<StatusMessage> StatusMessagePtr;
public class StatusMessage extends CoreMessage {
...
}
typedef boost::shared_ptr<DebugMessage> DebugMessagePtr;
public class DebugMessage extends CoreMessage {
...
}
And the functions also need to be changed to these Pointers:
CoreMessagePtr waitForNextMessage();
void processMessage(CoreMessagePtr m);
Then, I had to tell Swig about the shared_ptr using the included template for boost smart-pointers:
%module myapi
%include <boost_shared_ptr.i> // Tells Swig what to do with boost::shared_ptr
%header %{ // Tells Swig to add includes to the header of the wrapper
#include <boost/shared_ptr.hpp>
#include "messages.h"
%}
// Now here is the magic: Tell Swig that we want to use smart-Pointers for
// these classes. It makes Swig generate all necessary functions and wrap
// away all the de-referencing.
%shared_ptr(CoreMessage)
%shared_ptr(StatusMessage)
%shared_ptr(DebugMessage)
%include "message.h" // Finally: Tell Swig which interfaces it should create
Well, what we now get: Swig generates Java classes which look very similar to the ones we had before. But there is one small thing which makes the difference: The constructors now look like this:
protected StatusMessage(long cPtr, boolean cMemoryOwn) {
super(tscoreapiJNI.StatusMessage_SWIGSmartPtrUpcast(cPtr), true);
swigCMemOwnDerived = cMemoryOwn;
swigCPtr = cPtr;
}
and the magic line is super(tscoreapiJNI.StatusMessage_SWIGSmartPtrUpcast(cPtr), true); This line wraps an dynamic cast of the pointer which enables casting your object from Java.
But: It is not as easy as it might be (perhaps I just didn´t find a solution?!)
You cannot use Java casting to do the work like this [Java Code]:
CoreMessage m = waitForMessage(); // Returns a StatusMessage
StatusMessage mm = (StatusMessage) m; // Throws ClassCaseException
This is because java cannot do the dynamic cast which is necessary but needs the C++ code for that. My solution looks like this and uses a function template:
I added this template to messages.h
template <class T>
static boost::shared_ptr<T> cast(TsCoreMessagePtr coreMsg) {
return boost::dynamic_pointer_cast<T>(coreMsg);
}
Now tell Swig how to handle this template [added to the end of interface.i]:
%template(castStatusMessage) cast<StatusMessage>;
%template(castDebugMessage) cast<DebugMessage>;
What happens is: Swig adds these two functions to myapi.java:
public static StatusMessage castStatusMessage(CoreMessage coreMsg) {
long cPtr = myapiJNI.castStatusMessage(CoreMessage.getCPtr(coreMsg), coreMsg);
return (cPtr == 0) ? null : new StatusMessage(cPtr, true);
}
public static DebugMessage castDebugMessage(CoreMessage coreMsg) {
long cPtr = myapiJNI.castDebugMessage(CoreMessage.getCPtr(coreMsg), coreMsg);
return (cPtr == 0) ? null : new DebugMessage(cPtr, true);
}
And finally you can use it like this in your java code:
CoreMessage m = waitForMessage(); // Returns a StatusMessage
StatusMessage mm = myapi.cast(m);