I would like to use foreign function interface from project panama to access C library from Java19. The C interface is quite simple:
typedef struct {
int len;
char name[100];
} ent;
ent* foo();
When called, function foo returns pointer to struct ent, where len tells the size of the string name.
The corresponding Java side is:
private static final MemoryLayout ENT_LAYOUT = MemoryLayout.structLayout(
JAVA_INT.withName("len"),
MemoryLayout.sequenceLayout(100, ValueLayout.JAVA_BYTE).withName("name")
);
For ease of access I would like use VarHandle:
private static final VarHandle VH_ENT_LEN = ENT_LAYOUT.varHandle(groupElement("len"));
and later on
int len = (int)VH_ENT_LEN.get(segment);
String name = segment.asSlice(ENT_LAYOUT.byteOffset(groupElement("name")), len).getUtf8String(0);
Which is still a bit messy.
My naive expectation ware, that the solution should be something like:
private static final VarHandle VH_ENT_NAME = ENT_LAYOUT.varHandle(groupElement("name"), sequenceElement());
byte[] nameRaw = (byte[])VH_ENT_NAME.get(segment);
However I get:
java.lang.RuntimeException: java.lang.invoke.WrongMethodTypeException:
cannot convert MethodHandle(VarHandle,MemorySegment,long)byte to (VarHandle,MemorySegment)byte[]
So, the question is: is there an elegant solution to access arrays from java foreign API, or we should stick to mix of VarHandle and slice.
VarHandles, at their root, are only for accessing memory that can fit in a primitive type, andchar[100]does not fit in a primitive.What you get when doing:
Is a
VarHandlethat selects a singlebytefrom the array, for which the index is supplied dynamically:Yes,
sliceis needed to access anything that's too big for a primitive. It is essentially the same as doing this in C:You can use
MemoryLayout::sliceHandleas well to get aMethodHandlethat embeds the offset computations:Method handles can also be combined further (just like varhandles), to create one that directly gets the string from the segment:
Though, it is often simpler just to define a
statichelper method that does the above: