6

I try to generate java code with SWIG

In MyList.h I declared a custom list object called _list

List<T*> _list;

and this List class inherits from vector

class List : public vector<T>

In a business class (in C++) I return a List of custom objects

List<MyObject> getMyList(){
   ....
   return list;
}

so I want to generate java code where I can retrieve this C++ List as java.util.List or java.util.Vector.

in my swig.i file I couldn't manage how to embody

%typemap(jstype) List "java.util.Vector"
namespace std {
   %template(CustomVector) vector<MyObject>;
}

any kind help how to configure this swig.i template file or some sample code to generate a java.util.List / Vector returning function will be appreciated.

Thank you.

  • Please have a look at http://stackoverflow.com/questions/1854335/how-to-create-a-java-class-similar-to-a-c-template-class and http://stackoverflow.com/questions/462297/how-to-use-classt-in-java – phantasmagoria May 15 '12 at 07:35
  • 2
    Concerning the `std::vector` inheritance, have a look at [this question](http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector). – juanchopanza May 15 '12 at 07:38
  • OK let's say I won't use/return a std::vector then how can I transfer a list of objects from c++ layer to my java layer. –  May 15 '12 at 07:55
  • possible duplicate of [SWIG (v1.3.29) generated C++ to Java Vector class not acting properly](http://stackoverflow.com/questions/8145605/swig-v1-3-29-generated-c-to-java-vector-class-not-acting-properly) – Flexo May 15 '12 at 08:50
  • I think my answer on that question covers `std::vector` -> Java `Collection` in sufficient detail. If it's not let me know and I'll take a look later this week. – Flexo May 15 '12 at 08:52
  • thanks awoodland actually your answer is great,helpful.But i got a little confused when I try to do the same with generic types –  May 15 '12 at 09:03
  • @BeratOnurErsen ok, that makes sense. I'll write a generalisation of that up as an answer at some point. – Flexo May 15 '12 at 09:34

1 Answers1

10

You don't really want to be touching java.util.Vector with your wrapped interfaces because you will end up duplicating storage or making large numbers of copy operations every time you pass it in/out of a function. (Note also that in general in C++ inhering from containers is odd design).

Instead in Java the "right" thing to do is to inherit from java.util.AbstractList. This answer is a more generic version of my older answer to a similar question.

It works for all std::vector types, not just a fixed type and handles primitives which need to be accessed via Objects using an "autobox" custom type map. It's missing support for the specialized std::vector<bool>, but that should be simple to add if you need it.

%{
#include <vector>
#include <stdexcept>
%}

%include <stdint.i>
%include <std_except.i>

namespace std {

    template<class T> class vector {
      public:
        typedef size_t size_type;
        typedef T value_type;
        typedef const value_type& const_reference;
        vector();
        vector(size_type n);
        vector(const vector& o);
        size_type capacity() const;
        void reserve(size_type n);
        %rename(isEmpty) empty;
        bool empty() const;
        void clear();
        void push_back(const value_type& x);
        %extend {
            const_reference get(int i) const throw (std::out_of_range) {
                return $self->at(i);
            }
            value_type set(int i, const value_type& VECTOR_VALUE_IN) throw (std::out_of_range) {
                const T old = $self->at(i);
                $self->at(i) = VECTOR_VALUE_IN;
                return old;
            }
            int32_t size() const {
              return $self->size();
            }
            void removeRange(int32_t from, int32_t to) {
              $self->erase($self->begin()+from, $self->begin()+to);
            }
        }
    };
}

// Java typemaps for autoboxing in return types of generics
%define AUTOBOX(CTYPE, JTYPE)
%typemap(autobox) CTYPE, const CTYPE&, CTYPE& "JTYPE"
%enddef
AUTOBOX(double, Double)
AUTOBOX(float, Float)
AUTOBOX(boolean, Boolean)
AUTOBOX(signed char, Byte)
AUTOBOX(short, Short)
AUTOBOX(int, Integer)
AUTOBOX(long, Long)
AUTOBOX(SWIGTYPE, $typemap(jstype,$1_basetype))

%typemap(javabase) std::vector "java.util.AbstractList<$typemap(autobox,$1_basetype::value_type)>"
%typemap(javainterface) std::vector "java.util.RandomAccess"
%typemap(jstype) std::vector get "$typemap(autobox,$1_basetype)"
%typemap(jstype) std::vector set "$typemap(autobox,$1_basetype)"
%typemap(jstype) std::vector &VECTOR_VALUE_IN "$typemap(autobox,$1_basetype)"
%typemap(javacode) std::vector %{
  $javaclassname(java.util.Collection<$typemap(autobox,$1_basetype::value_type)> e) {
    this.reserve(e.size());
    for($typemap(autobox,$1_basetype::value_type) value: e) {
      this.push_back(value);
    }
  }
%}

Most of this is fairly similar to the default std_vector.i that SWIG currently provides, the new bits are the renaming, extending and typemaps that extend AbstractList and implement RandomAccess. It also adds a constructor that takes other Collections - this is recommended by the Java documentation and easy enough to do. (There's an overload for other std::vector types which is much faster).

I tested this vector wrapping within another SWIG interface:

%module test

%include "vector.i"

%template(DblVec) std::vector<double>;
%template(ByteVec) std::vector<signed char>;
%include <std_string.i>
%template(StringVec) std::vector<std::string>;

%inline %{
struct foo {};
%}

%template(FooVec) std::vector<foo>;

Which I was able to compile and run with:

public class run {
  public static void main(String argv[]) {
    System.loadLibrary("test");
    DblVec dv = new DblVec(100);
    for (int i = 0; i < 100; ++i) {
      dv.set(i,(double)i);
    }
    FooVec fv = new FooVec(1);
    fv.set(0, new foo());
    for (double d: dv) {
      System.out.println(d);
    }
  }
}
Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • Hi. Would you still recommend using this wrapper instead of SWIG's `std_vector.i` implementation? I just need to exchange primitive array data in my case. Thanks! – Jesús Zazueta Apr 05 '15 at 23:30
  • @JesúsZazueta if it's just an array of primitives I'd probably just use the JNI arrays interface to do it and take the hit on a copy or two. (Or re-work the code so that it can use a borrowed buffer from Java and share the same memory). – Flexo Apr 06 '15 at 09:58
  • @Flexo you are the SWIG GOD ! Thx! – flaviussn Sep 02 '15 at 10:47
  • FYI this functionality is likely to get included in SWIG 3.1 when released. – Flexo Nov 07 '17 at 20:00
  • Typemapping autoboxed types seems not to work any more on 3.0. It may no longer match the pattern. Trying this code verbatim does not work. – Jason Carr Nov 27 '18 at 05:18
  • @jason I'd skip to SWIG 3.1 if you can and use that. It should all just work there out the box now, because a variant of the same idea got merged into it: https://github.com/swig/swig/blob/master/Lib/java/std_vector.i, which uses the new jboxtype typemap: https://github.com/swig/swig/search?utf8=%E2%9C%93&q=jboxtype&type= – Flexo Nov 27 '18 at 08:16