Maintaining state in SWIG Java director class

时间:2016-10-20 19:41:20

标签: java c++ swig

I want to access a Java graph library (Titan) from c++. Doing some research showed that JNI would get the job done. I wrote some JNI code, got it working, but it quickly became tedious, so I looked to an automated solution. I found SWIG, more specifically SWIG directors. I have no problem calling functions, however I have a problem of maintaining state going back and forth from Java and c++ using a SWIG director.

For my SWIG directors I wrote c++ interfaces exposing the functionality I wanted. Below is a sample:

GraphIfc.hpp:

struct GraphIfc {
   virtual ~GraphIfc() {}
   virtual VertexIfc * addVertex(const std::string& label) = 0;
};

VertexIfc.hpp:

struct VertexIfc {
   virtual ~VertexIfc() {}
   virtual EdgeIfc * addEdge(const std::string& label, VertexIfc * v) = 0;
};

EdgeIfc.hpp:

struct EdgeIfc {
   virtual ~EdgeIfc() {}
};

Then I wrote the Java implementation:

JGraph.java:

import com.thinkaurelius.titan.core.TitanGraph;

public class JGraph extends GraphIfc {
  private TitanGraph graph;

  public JGraph(TitanGraph g) {
    graph = g;
  }

  public VertexIfc addVertex(final String label) {
    return new Vertex(graph.addVertex(label));
  }
}

JVertex.java:

import com.thinkaurelius.titan.core.TitanVertex;

public class JVertex extends VertexIfc {
  public TitanVertex vertex;

  public JVertex(TitanVertex v) {
    vertex = v;
  }

  public EdgeIfc addEdge(final String label, VertexIfc inV) {
    Vertex v = (Vertex)inV;
    return new Edge(vertex.addEdge(label, v.vertex));
  }
}

JEdge.java:

import org.apache.tinkerpop.gremlin.structure.Edge;

public class JEdge extends EdgeIfc {
  public Edge edge = null;

  public JEdge(Edge e) { 
    edge = e;
  }
}

And here's my SWIG file:

%module(directors="1") graph

%{
#include "graph.hpp"
#include "vertex.hpp"
#include "edge.hpp"
%}

%feature("director") GraphIfc;
%feature("director") VertexIfc;
%feature("director") EdgeIfc;
SWIG_DIRECTOR_OWNED(GraphIfc)
SWIG_DIRECTOR_OWNED(VertexIfc)
SWIG_DIRECTOR_OWNED(EdgeIfc)

%include "graph.hpp"
%include "vertex.hpp"
%include "edge.hpp"

%pragma(java) jniclasscode=%{
  static {
    try {
      System.loadLibrary("graph");
    } catch (UnsatisfiedLinkError e) {
      System.err.println("Native code library graph failed to load.\n" + e);
      System.exit(1);
    }
  }
%}

All of this produces:

  • Java proxy classes: GraphIfc, VertexIfc, EdgeIfc. These hold the c++ pointer as a long.
  • Intermediary JNI class in Java with functions

such as:

public static long SwigDirector_GraphIfc_addVertex(GraphIfc jself, String label) {
  return VertexIfc.getCPtr(jself.addVertex(label));
}

public static long SwigDirector_VertexIfc_addEdge(VertexIfc jself, String label, long inVertex) {
  return EdgeIfc.getCPtr(jself.addEdge(label, (inVertex == 0) ? null : new VertexIfc(inVertex, false)));
}

There are a two problems with these functions:

  1. The VertexIfc being created by SwigDirector_VertexIfc_addEdge is not of type JVertex, thus my cast within addEdge will fail and throw an exception.
  2. But more importantly, even if the type was a JVertex, the new JVertex would not contain the same value of TitanVertex as set by addVertex. Any state within the derived class (JVertex, JEdge, etc) is loss.

0 个答案:

没有答案