2014-01-28 00:52:49 +00:00
|
|
|
# Use in Java
|
|
|
|
|
2014-07-31 18:39:40 +00:00
|
|
|
FlatBuffers supports reading and writing binary FlatBuffers in Java. Generate code
|
2014-01-28 00:52:49 +00:00
|
|
|
for Java with the `-j` option to `flatc`.
|
|
|
|
|
|
|
|
See `javaTest.java` for an example. Essentially, you read a FlatBuffer binary
|
|
|
|
file into a `byte[]`, which you then turn into a `ByteBuffer`, which you pass to
|
2014-07-31 18:39:40 +00:00
|
|
|
the `getRootAsMyRootType` function:
|
2014-01-28 00:52:49 +00:00
|
|
|
|
|
|
|
ByteBuffer bb = ByteBuffer.wrap(data);
|
|
|
|
Monster monster = Monster.getRootAsMonster(bb);
|
|
|
|
|
|
|
|
Now you can access values much like C++:
|
|
|
|
|
|
|
|
short hp = monster.hp();
|
|
|
|
Vec3 pos = monster.pos();
|
|
|
|
|
|
|
|
Note that whenever you access a new object like in the `pos` example above,
|
|
|
|
a new temporary accessor object gets created. If your code is very performance
|
|
|
|
sensitive (you iterate through a lot of objects), there's a second `pos()`
|
|
|
|
method to which you can pass a `Vec3` object you've already created. This allows
|
|
|
|
you to reuse it across many calls and reduce the amount of object allocation (and
|
|
|
|
thus garbage collection) your program does.
|
|
|
|
|
2014-06-23 20:33:34 +00:00
|
|
|
Java does not support unsigned scalars. This means that any unsigned types you
|
|
|
|
use in your schema will actually be represented as a signed value. This means
|
|
|
|
all bits are still present, but may represent a negative value when used.
|
|
|
|
For example, to read a `byte b` as an unsigned number, you can do:
|
|
|
|
`(short)(b & 0xFF)`
|
|
|
|
|
2014-01-28 00:52:49 +00:00
|
|
|
Sadly the string accessors currently always create a new string when accessed,
|
|
|
|
since FlatBuffer's UTF-8 strings can't be read in-place by Java.
|
|
|
|
|
|
|
|
Vector access is also a bit different from C++: you pass an extra index
|
|
|
|
to the vector field accessor. Then a second method with the same name
|
2014-07-31 18:39:40 +00:00
|
|
|
suffixed by `Length` let's you know the number of elements you can access:
|
2014-01-28 00:52:49 +00:00
|
|
|
|
2014-07-31 18:39:40 +00:00
|
|
|
for (int i = 0; i < monster.inventoryLength(); i++)
|
2014-01-28 00:52:49 +00:00
|
|
|
monster.inventory(i); // do something here
|
|
|
|
|
2014-09-04 23:31:44 +00:00
|
|
|
If you specified a file_indentifier in the schema, you can query if the
|
|
|
|
buffer is of the desired type before accessing it using:
|
|
|
|
|
|
|
|
if (Monster.MonsterBufferHasIdentifier(bb, start)) ...
|
|
|
|
|
|
|
|
|
|
|
|
## Buffer construction in Java
|
|
|
|
|
2014-01-28 00:52:49 +00:00
|
|
|
You can also construct these buffers in Java using the static methods found
|
|
|
|
in the generated code, and the FlatBufferBuilder class:
|
|
|
|
|
|
|
|
FlatBufferBuilder fbb = new FlatBufferBuilder();
|
|
|
|
|
|
|
|
Create strings:
|
|
|
|
|
|
|
|
int str = fbb.createString("MyMonster");
|
|
|
|
|
|
|
|
Create a table with a struct contained therein:
|
|
|
|
|
|
|
|
Monster.startMonster(fbb);
|
|
|
|
Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, (byte)4, (short)5, (byte)6));
|
|
|
|
Monster.addHp(fbb, (short)80);
|
|
|
|
Monster.addName(fbb, str);
|
|
|
|
Monster.addInventory(fbb, inv);
|
|
|
|
Monster.addTest_type(fbb, (byte)1);
|
|
|
|
Monster.addTest(fbb, mon2);
|
|
|
|
Monster.addTest4(fbb, test4s);
|
|
|
|
int mon = Monster.endMonster(fbb);
|
|
|
|
|
|
|
|
As you can see, the Java code for tables does not use a convenient
|
|
|
|
`createMonster` call like the C++ code. This is to create the buffer without
|
2014-07-31 18:39:40 +00:00
|
|
|
using temporary object allocation.
|
|
|
|
|
|
|
|
It's important to understand that fields that are structs are inline (like
|
|
|
|
`Vec3` above), and MUST thus be created between the start and end calls of
|
|
|
|
a table. Everything else (other tables, strings, vectors) MUST be created
|
|
|
|
before the start of the table they are referenced in.
|
|
|
|
|
2014-01-28 00:52:49 +00:00
|
|
|
Structs do have convenient methods that even have arguments for nested structs.
|
|
|
|
|
2014-07-31 18:39:40 +00:00
|
|
|
As you can see, references to other objects (e.g. the string above) are simple
|
|
|
|
ints, and thus do not have the type-safety of the Offset type in C++. Extra
|
|
|
|
case must thus be taken that you set the right offset on the right field.
|
|
|
|
|
2014-01-28 00:52:49 +00:00
|
|
|
Vectors also use this start/end pattern to allow vectors of both scalar types
|
|
|
|
and structs:
|
|
|
|
|
|
|
|
Monster.startInventoryVector(fbb, 5);
|
|
|
|
for (byte i = 4; i >=0; i--) fbb.addByte(i);
|
|
|
|
int inv = fbb.endVector();
|
|
|
|
|
|
|
|
You can use the generated method `startInventoryVector` to conveniently call
|
|
|
|
`startVector` with the right element size. You pass the number of
|
|
|
|
elements you want to write. You write the elements backwards since the buffer
|
|
|
|
is being constructed back to front.
|
|
|
|
|
2014-06-23 20:33:34 +00:00
|
|
|
There are `add` functions for all the scalar types. You use `addOffset` for
|
|
|
|
any previously constructed objects (such as other tables, strings, vectors).
|
|
|
|
For structs, you use the appropriate `create` function in-line, as shown
|
|
|
|
above in the `Monster` example.
|
|
|
|
|
2014-09-04 23:31:44 +00:00
|
|
|
To finish the buffer, call:
|
|
|
|
|
|
|
|
Monster.finishMonsterBuffer(fbb, mon);
|
|
|
|
|
|
|
|
The buffer is now ready to be transmitted. It is contained in the `ByteBuffer`
|
|
|
|
which you can obtain from `fbb.dataBuffer()`. Importantly, the valid data does
|
|
|
|
not start from offset 0 in this buffer, but from `fbb.dataStart()` (this is
|
|
|
|
because the data was built backwards in memory). It ends at `fbb,capacity()`.
|
|
|
|
|
|
|
|
|
2014-01-28 00:52:49 +00:00
|
|
|
## Text Parsing
|
|
|
|
|
|
|
|
There currently is no support for parsing text (Schema's and JSON) directly
|
|
|
|
from Java, though you could use the C++ parser through JNI. Please see the
|
|
|
|
C++ documentation for more on text parsing.
|