bytedeco / javacpp

The missing bridge between Java and native C++
Other
4.47k stars 582 forks source link

How should the @ByRef annotation be used? #597

Closed benshiffman closed 2 years ago

benshiffman commented 2 years ago

I'm having some trouble with some @StdVector annotated types. Array data is not being passed with my getters/setters, and I believe the reason is that I'm missing @ByRef annotation for these functions.

How should I go about infoMapping?

saudet commented 2 years ago

Do you have an example of what you need to do? FYI, @StdVector is pretty limited in what it can do. You may need to map the template instance: https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes#defining-wrappers-for-basic-c-containers

benshiffman commented 2 years ago

Here's my program. I've altered some of the names in the following code since I am working with controlled information. The gist of what I'm trying to do is pass data to the main generated class, "MainClass", to another class, "HelperClass".

The first two code blocks, except for variable name changes, have been unmodified from the version built by javacpp.jar.

MainClass relevant members/methods:

        public native @StdVector HelperClass m_data(); public native MainClass m_data(HelperClass setter);
        public native @StdVector HelperClass get_data();
        public native void set_data(@StdVector HelperClass data);

HelperClass definition:

    @Namespace("LIBRARY") public static class HelperClass extends Pointer {
        static { Loader.load(); }
        /** Default native constructor. */
        public HelperClass() { super((Pointer)null); allocate(); }
        /** Native array allocator. Access with {@link Pointer#position(long)}. */
        public HelperClass(long size) { super((Pointer)null); allocateArray(size); }
        /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
        public HelperClass(Pointer p) { super(p); }
        private native void allocate();
        private native void allocateArray(long size);
        @Override public HelperClass position(long position) {
            return (HelperClass)super.position(position);
        }
        @Override public HelperClass getPointer(long i) {
            return new HelperClass((Pointer)this).offsetAddress(i);
        }

        public native @StdVector DoublePointer m_some_data(); public native HelperClass m_some_data(DoublePointer setter);
        public native @StdVector DoublePointer get_some_data();
        public native void set_some_data(@StdVector DoublePointer some_data);
        public native void set_some_data(@StdVector DoubleBuffer some_data);
        public native void set_some_data(@StdVector double[] some_data);

    }

Code I'm trying to execute:

        double[] data_array = {0, 100};
        mainClassInstance.set_data(new HelperClass(data_array.length));
        for (int i = 0; i < data_array.length; i++) {
            mainClassInstance.get_data().position(i).set_some_data(data_array);
        }

Running calculations with the mainClassInstance later on results in an exception: Exception in thread "main" java.lang.RuntimeException: m_data[].m_some_data cannot be empty

Does anything stand out to you here?

saudet commented 2 years ago

Right, that's the kind of thing that might not work well with adapters like @StdVector. Using an instance like HelperClassVector should work much better.

benshiffman commented 2 years ago

The method in Mapping Recipes you sent worked like magic. Thank you!