I wrote a set of C++ classes and created a DLL that exports one of these C++ classes. I need to instantiate the exported C++ class in a Java class. Is that possible?
I searched the web for a possible solution, but all I have found where solutions using JNA or JNI that import C++ functions only.
Yes, you can instantiate a C++ class from Java.
One way is with SWIG, which can generate Java wrappers for C++ classes.
For example, given a C++ class like this:
class MyClass {
public:
MyClass();
int myMethod( int arg );
}
SWIG allows you to write Java code like this:
MyClass myclass = new MyClass();
int val = myClass.myMethod( 42 );
If you want to instantiate a C++ class from Java, you'll have to write a little glue code (in C++) that instantiates the desired object. Further, you'll need a Java class that corresponds to the C++ class, and you need to have the glue code convert the C++ object into an object of the Java class aforementioned, and keeps them together (i.e., changes to the C++ object should reflect to the Java object, and the other way around).
This tutorial seems to have some pointers how you could do that. Specifically, it tells you how to instantiate a Java object, which is what you will need for the above approach.
Related
I have a third-party VB.Net dll that I want to call from Java.
The VB.Net dll has the following signature (pseudo code, but feels like Java...):
class MyClass1 {
public Object method1(StringRef arg1, StringRef arg2) {
// do something here...
return someResult;
}
}
class MyClass2 {
public Object method2(StringRef arg1, StringRef arg2) {
// do something here...
return someOtherResult;
}
}
Note: StringRef is my way of saying the method expects me to pass in strings by reference.
I am trying to call this dll object from within Java. Using JNA, I have the following:
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface DllName extends Library {
DllName INSTANCE = (DllName)Native.loadLibrary("DllName", DllName.class);
public static interface MyClass1 {
public Object method1(String arg1, String arg2);
}
public static interface MyClass2 {
public Object method2(String arg1, String arg2);
}
}
The INSTANCE object here loads just fine. However, I cannot figure out what structure the body of DllName should take to map to the dll's class, method signature. Also, I have not seen how I might call Native in a way that would load the object directly. For example, if I do:
DllName INSTANCE = (DllName)Native.loadLibrary("DllName.MyClass1", DllName.class);
This results in an UnsatisfiedLinkError since the dll is named DllName. Making this call requires a different interface than shown above.
Questions:
Is this even possible? E.g. Can I call a VB.Net dll from Java using JNA given the structure above.
What structure does DllName need to have to properly map to the class MyClass1 and MyClass2? This is my core question here.
In the DllName.MyClass1 call above, is there some alternative way?
Did I miss anything with any of the alternative items mentioned below? Perhaps some other solution I missed?
I have explored the following alternatives:
Reviewed this article, but did not see an example that matches my structure. I also looked at the unit tests referenced on the bottom.
Creating a C++ wrapper, as suggested here /questions/1556421/use-jni-instead-of-jna-to-call-native-code (I'd post as a link, but not enough reputation with SO...). I haven't actually tried this, as I am not familiar with C++. I would expect too-much head-banging, when I think some change to my Java code would suffice.
JNI: This seems like it is only for C/C++ type dlls.
javOnet: Almost works, but the VB.Net methods expect strings by reference, which is not currently supported by javOnet. I reported the issue to them, and I expect a fix. Even if it did work, it seems like a JNA solution should work. There is also a cost issue with that solution.
jni4net: This does not work for me since this is a third-party dll. jni4net expects some hook on the .Net side.
Please let me know if you would like me to add any additional color here.
javOnet already provides support for arguments passed by ref or out since version 1.2. You can read more at:
http://www.javonet.com/quick-start-guide/#Passing_arguments_by_reference_with_ref_and_out_keywrods
You must wrap you JAVA type in "AtomicReference" so it can be updated within the method call and your JAVA variable let's say integer will be automatically modified on .NET side. You can see the usage sample below:
NObject refEx = Javonet.New("RefExample");
//Wrap Java integer in AtomicReference to allow passing by reference
AtomicReference<Integer> myInt = new AtomicReference<Integer>(10);
refEx.invoke("Method",new NRef(myInt));
System.out.println(myInt.get());
//Output will display number "55" because int passed by reference has been modified within the method body.
With SWIG am able to create simple bindings for my C++ code.
My question here is for multiple inheritance.
Our C++ codebase has a iClass as base class, which acts as interface. Also we have classes that are derived from two classes, one of which is this interface class.
Now my question is can we use SWIG to create bindings for such a codebase, assuming that we can put our class iClass as an Interface in Java.
It is still multiple inheritance but a very specific case of it and is analogous with interface concept of java.
The case with SWIG is that it indeed will only extend the first base class you list (in the code example below that would be I1) and omit the rest. Interestingly, the C++ compiled code WILL include all the base methods, they are just not available to the Java JNI wrapper.
Multiple inheritance is another paradigm than interfacing, making it hard to cast / interpret an Object in Java as belonging to a particular interface.
What you can do though - which does feel a tad fugly - is to add a compiler directive to the header file of the class which is inheriting from multiple classes. Like so:
class Foo : public I1, I2
{
public:
Foo();
~Foo();
#ifdef SWIG
void aI2Method();
double aI2Property;
#endif
protected:
void bar();
}
When compiling with SWIG, property SWIG is defined. As such the method "aI2Method" and public property "aI2Property" (which for the sake of argument, we assume are defined in base class I2) are used by SWIG and defined in the JNI wrapper for this class "Foo". Just add the public methods / properties in between the conditional directive.
In Java you can then invoke "aI2Method" on Foo or get/set the public "aI2Property"-property, and the native compiled code will invoke these on the I2 base class. Note that this means you don't need to add the same directive including the definitions or function bodies of these methods in the .cpp file of "Foo", as placing it in the header file will suffice. This way, at least the .cpp files remain clean.
I am trying to create a Java wrapper for my C++ library using SWIG.
In order to get all the features I need within a Java programming environment, I need directors.
More specifically, I need Java users to be able to inherit from my C++ classes and implement certain methods.
In particular, one of the method that needs to be implemented is some sort of clone() method.
In C++, the user implementation provides an object pointer Base*. This pointer is then managed by the library itself.
Base* Derived::clone() {
return new Derived(*this);
}
The problem I have with the Java wrapper is that the Java proxy class for Base acquires the management of the corresponding C++ director class SwigDirector_Base, by default.
This is certainly suitable in the general case, but not in this particular user-defined clone() function.
My personal constraint is that the Java wrapper for my C++ library uses no Java-specific code, so the user implementation should look like:
class Derived {
...
Base clone() {
return new Derived(this);
}
}
So far, to make it work and avoid garbage collection of the copied Java instance, I have used the trick mentioned in http://www.swig.org/Doc2.0/SWIGDocumentation.html#CSharp_memory_management_member_variables.
And to make sure that the Java Derived class never deletes the corresponding C++ director class SwigDirector_Base, I have used %typemap(directorout) to set the value of the Java cMemOwn flag of the copied instance from the C++ wrapper code, that is in method SwigDirector_Base::clone().
I am not so happy with this solution as it applies to all methods returning a pointer to the Base class, whether it is a copy method or not...
Any idea on how to do this on a function-specific way? Or in any other way?
I'm using SWIG to generated Java classes and I have 3 different classes that one dependant on the others.
SWIG makes pointers to this classes because it didn't know about it, I need that SWIG uses the Java classes that created and not the pointers that SWIG creates.
How can I do this?
I have c++ function like this:
bool foo(class1& parm);
Now I use SWIG to create class1 in Java and I want to make SWIG to wrap foo in Java with the parameter class1 that it created and not SWIG_P_class1. I don't have any way to do this.
Swig hides away details like the actual classes or objects used. If you want to access the real Java objects and class I suggest you use JNI (which gives you access to everything and is likely to be faster)
For types that SWIG knows nothing about (i.e. hasn't seen anything more than a forward declaration) the best wrapper it can generate roughly mirrors what you can do with a forward declared class in C++ - it gets wrapped as something that behaves like an opaque pointer. This is the SWIG_P_class1 you're seeing. You can do sensible things with this, e.g. if you have a method that returns references or pointers to instances you could call that to get an object to pass to foo.
However you probably don't want to use that much in real interfaces, so given a header file we want to wrap that looks like:
class class1;
bool foo(class1& parm);
You can wrap it sensibly by giving SWIG a partial (or complete if you prefer) definition of the class1, e.g.:
%module test
class class1 {
};
%include "test.hh"
will cause a sensible class1 and foo to be exposed on the Java side, so you could use them in Java as in:
test.foo(new class1());
exactly as you'd hope.
You will of course need to provide the generated C++ sufficient knowledge of the class1 class, exactly as you would with any other C++ code. The easiest way to do that is to make your SWIG interface look something like:
%module test
%{
#include "class1_defined_here.hh"
%}
class class1 {
};
%include "test.hh"
How to declare and call a native method in c containing pointers using java?
please it is urgent.Because there is no concept of pointers in java i am getting error.
Use JNI(Java Native Interfaces) to call native methods in java. Use this JNI specification pdf as a reference "java.sun.com/docs/books/jni/download/jni.pdf".
There is even a easier approach to the subject, if you or your boss are willing to pay 50$!
Is called eXcelsior xFunction. Try the evaluation version.
Works very well and is simple to use.
The only thing xFunction library does not do have is implementation of address arithmetic in Java, which i assume you will possibly never need.
From their site:
With xFunction, you no longer need to implement those ugly native methods. Instead, you extend and instantiate xFunction classes to create conventional Java objects representing external functions, data structures, pointers, and callbacks. All necessary data conversions and external function calls are done seamlessly by the xFunction library:
import com.excelsior.xFunction.*;
...
/* Call Beep() from KERNEL32.DLL */
xFunction f =
new xFunction( "kernel32",
"int Beep(int,int)" );
f.invoke( new Argument(1770),
new Argument(100) );