We can do this with SWIG. The tricky part is that as you spotted SWIG is inclined to assume that B* is a pointer to an Object, not the start of some array.
Since the array contains many non-primitive instances each instance is going to require the creation of a Java object that is a proxy for the corresponding B instance in your C array. There are two places you could cause those to be generated. Either you could write some C that creates each Object and sticks it in a jobjectArray, or you could write some Java that takes advantage of the fact that SWIG can trivially be made to generate a specific proxy for any specific member. I think the latter solution is simpler and cleaner so I've made an example using that approach:
%module test
%ignore A_::b; // We will wrap this another way
%typemap(javacode) A %{
public B[] getB() {
B[] ret = new B[getNumBs()];
for (int i = 0; i < ret.length; ++i) {
ret[i] = getB(i);
}
return ret;
}
%}
// Or %include etc.
%inline %{
typedef struct B_ {
/* something */
} B;
typedef struct A_ {
int numBs; /* The count of Bs in the array bellow */
B *b;
} A;
%}
%javamethodmodifiers A_::getB(size_t pos) "private";
%extend A_ {
// This defaults to non-owning, which is exactly what we want
B *getB(size_t pos) {
assert(pos < $self->numBs); // TODO: real error handling
return $self->b+pos;
}
}
The %extend provides one extra method in Java that gets any B in your C array of Bs. Since this is an implementation detail I made it private.
We also told SWIG not to wrap the B *b pointer - we're going to supply our own wrapping for that manually instead. This is provided via the javacode typemap. Inside that typemap we build up our Java array by calling our helper once per item in the array.
With that in place it's now sufficient for you to do:
A a = new A();
B[] b = a.getB();
Crucially because we only ignored the specific member of A it won't interfere with other uses of B *b.
B b = a.getB()instead ofB[] b = a.getB().