0

I want to use already existing C++ code in Apache Spark which runs in Java. I used SWIG to generate the JNI interface which works like a charm as long as I am calling the functions from a simple class like this (MyJavaClass.java):

public class MyJavaClass {
  public static void main(String[] args) {
    System.loadLibrary("mycppcode");
    mycppcode.dostuff();
  }
}

Then I tried to integrate the class into my packaging hierarchie which I need to be able to call it from Spark (MyJavaClass.java):

package com.mycompany.mypackage;

public class MyJavaClass {
  public void MyJavaMethod() {
    System.loadLibrary("mycppcode");
    mycppcode.dostuff();
  }
}

But as soon as I add the package line I am getting the following error when running javac on the file:

MyJavaClass.java:6: error: cannot find symbol
        mycppcode.dostuff();
        ^
  symbol:   variable mycppcode
  location: class MyJavaClass
1 error

I used the following commands to generate the JNI, the libmycppcode.so library and the Java class:

swig -c++ -java -package com.mycompany.mypackage mycppcode.i
g++ -fpic -c mycppcode.cpp mycppcode_wrap.cxx -std=c++17 -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux
g++ -shared mycppcode.o mycppcode.o -o libmycppcode.so
javac MyJavaClass.java

This is the C++ file (mycppcode.cpp):

#include <iostream>
using namespace std;

int dostuff() {
    cout << "Hello World!" << endl;
}

This is the interface file (mycppcode.i):

%module mycppcode
%{
extern int dostuff();
%}
extern int dostuff();

This is the generated JNI file (mycppcodeJNI.java):

package com.mycompany.mypackage

public class mycppcodeJNI {
  public final static native int dostuff();
}

This is the generated Java file (mycppcode.java):

public class mycppcode {
  public static int dostuff() {
    return mycppcodeJNI.dostuff();
  }
}
Stargazer
  • 106
  • 11
  • Where does the `mycppcode` object come from ? – Arnaud Jan 16 '18 at 10:35
  • Did you re-run SWIG after changing the package name? JNI function names must match the fully qualified name of the Java class that declares the corresponding `native` methods. – Michael Jan 16 '18 at 11:39
  • @Berger, Michael: Thanks for answering, I updated the post with the commands and the other files I used. Do you see what I might have done wrong? – Stargazer Jan 16 '18 at 12:07
  • Have you tried adding `-package com.mycompany.mypackage` to the commandline options when running SWIG? – Michael Jan 16 '18 at 13:28
  • @Michael: Before not but now I tried with `swig -c++ -java -package com.mycompany.mypackage mycppcode.i`. The JNI file now contains `package com.mycompany.mypackage` at the top which makes sense. Unfortunately the error still persists (I ran the other commands as well in the same order as above). – Stargazer Jan 16 '18 at 14:23

2 Answers2

1

I just got it to work. Thanks a lot to @Michael for the hint with the -package argument.

The problem seems to be that I tried to run javac from the actual folder of the class file like this:

~/myproject/src/com/mycompany/mypackage$ javac MyJavaClass.java

Instead javac needs to be executed from the root source directory like this:

~/myproject/src$ javac com/mycompany/mypackage/MyJavaClass.java

I am not sure why but this prevents the error.

Stargazer
  • 106
  • 11
0

As explained here, you cannot use class from default package in your com.mycompany.mypackage. MyJavaClass. You should rename mycppcode class:

package com.mycompany.mypackage;

public class mycppcode {
  public static int dostuff() {
    return mycppcodeJNI.dostuff();
  }
}

Actually, it may use any package name, e.g.

package jni;

public class mycppcode {
  public static int dostuff() {
    return mycppcodeJNI.dostuff();
  }
}
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307