Java implementation of FlatBuffers providing type-safe access to FlatBuffer data with integration into Java's memory model and garbage collection system. The Java binding maintains zero-copy deserialization benefits while providing idiomatic Java APIs.
Add FlatBuffers to your Java project using Maven or Gradle.
<!-- Maven dependency -->
<dependency>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
<version>25.2.10</version>
</dependency>// Gradle dependency
implementation 'com.google.flatbuffers:flatbuffers-java:25.2.10'// Core imports
import com.google.flatbuffers.FlatBufferBuilder;
import com.google.flatbuffers.Table;
import com.google.flatbuffers.Struct;
// Utility imports
import java.nio.ByteBuffer;
import java.nio.ByteOrder;Main builder class for constructing FlatBuffer data in Java applications.
public class FlatBufferBuilder {
/**
* Create a FlatBufferBuilder with default initial size
*/
public FlatBufferBuilder();
/**
* Create a FlatBufferBuilder with specified initial size
* @param initialSize Initial buffer size in bytes
*/
public FlatBufferBuilder(int initialSize);
/**
* Create a FlatBufferBuilder with custom ByteBuffer
* @param bb Custom ByteBuffer to use
* @param file_identifier Optional 4-character file identifier
*/
public FlatBufferBuilder(ByteBuffer bb, String file_identifier);
/**
* Reset the builder for reuse
*/
public void clear();
/**
* Get current buffer size
* @return Size in bytes
*/
public int offset();
/**
* Create string and return its offset
* @param s String to store
* @return Offset to string
*/
public int createString(CharSequence s);
public int createString(ByteBuffer s);
/**
* Create vector of bytes
* @param arr Byte array to store
* @return Offset to vector
*/
public int createByteVector(byte[] arr);
/**
* Create vector of shorts
* @param arr Short array to store
* @return Offset to vector
*/
public int createShortVector(short[] arr);
/**
* Create vector of ints
* @param arr Integer array to store
* @return Offset to vector
*/
public int createIntVector(int[] arr);
/**
* Create vector of longs
* @param arr Long array to store
* @return Offset to vector
*/
public int createLongVector(long[] arr);
/**
* Create vector of floats
* @param arr Float array to store
* @return Offset to vector
*/
public int createFloatVector(float[] arr);
/**
* Create vector of doubles
* @param arr Double array to store
* @return Offset to vector
*/
public int createDoubleVector(double[] arr);
/**
* Start building a vector manually
* @param elemSize Size of each element in bytes
* @param numElems Number of elements
* @param alignment Required alignment
*/
public void startVector(int elemSize, int numElems, int alignment);
/**
* End vector construction
* @return Offset to completed vector
*/
public int endVector();
/**
* Start building a table
* @param numFields Number of fields in table
*/
public void startTable(int numFields);
/**
* Add byte field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addByte(int o, byte x, byte d);
/**
* Add short field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addShort(int o, short x, short d);
/**
* Add int field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addInt(int o, int x, int d);
/**
* Add long field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addLong(int o, long x, long d);
/**
* Add float field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addFloat(int o, float x, float d);
/**
* Add double field to current table
* @param o Field offset in vtable
* @param x Value to store
* @param d Default value
*/
public void addDouble(int o, double x, double d);
/**
* Add offset field to current table
* @param o Field offset in vtable
* @param x Offset value
* @param d Default offset
*/
public void addOffset(int o, int x, int d);
/**
* Add struct field to current table
* @param o Field offset in vtable
* @param x Struct offset
* @param d Default offset
*/
public void addStruct(int o, int x, int d);
/**
* End table construction
* @return Offset to completed table
*/
public int endTable();
/**
* Finish buffer with root table
* @param rootTable Offset to root table
*/
public void finish(int rootTable);
/**
* Finish buffer with root table and file identifier
* @param rootTable Offset to root table
* @param file_identifier 4-character identifier
*/
public void finish(int rootTable, String file_identifier);
/**
* Finish buffer with size prefix
* @param rootTable Offset to root table
*/
public void finishSizePrefixed(int rootTable);
/**
* Get the underlying ByteBuffer
* @return ByteBuffer containing data
*/
public ByteBuffer dataBuffer();
/**
* Get buffer data as byte array
* @return Byte array copy of buffer
*/
public byte[] sizedByteArray();
/**
* Get buffer data as byte array with specific range
* @param start Start position
* @param length Length to copy
* @return Byte array copy of specified range
*/
public byte[] sizedByteArray(int start, int length);
}Usage Example:
import com.google.flatbuffers.FlatBufferBuilder;
// Create builder
FlatBufferBuilder builder = new FlatBufferBuilder(1024);
// Create string
int nameOffset = builder.createString("Player");
// Create vector
int[] scores = {100, 200, 300, 400, 500};
int scoresOffset = builder.createIntVector(scores);
// Create table
builder.startTable(3);
builder.addOffset(0, nameOffset, 0); // name field
builder.addInt(1, 42, 0); // level field
builder.addOffset(2, scoresOffset, 0); // scores field
int player = builder.endTable();
// Finish buffer
builder.finish(player);
// Get binary data
byte[] buffer = builder.sizedByteArray();
ByteBuffer bb = builder.dataBuffer();Base class for accessing FlatBuffer table data with type-safe field access.
public class Table {
/** ByteBuffer containing the table data */
protected ByteBuffer bb;
/** Position of this table in the buffer */
protected int bb_pos;
/**
* Get field offset from vtable
* @param vtableOffset Offset in vtable
* @return Field offset or 0 if not present
*/
protected int __offset(int vtableOffset);
/**
* Get indirect offset (for tables, vectors, strings)
* @param offset Field offset
* @return Indirect offset
*/
protected int __indirect(int offset);
/**
* Get string at offset
* @param offset String offset
* @return String value or null
*/
protected String __string(int offset);
/**
* Get string at offset with encoding
* @param offset String offset
* @param encoding Character encoding
* @return String value or null
*/
protected String __string(int offset, String encoding);
/**
* Get vector length at offset
* @param offset Vector offset
* @return Vector length
*/
protected int __vector_len(int offset);
/**
* Get vector starting position
* @param offset Vector offset
* @return Position of first element
*/
protected int __vector(int offset);
/**
* Get vector element at index
* @param offset Vector offset
* @param j Element index
* @param elem_size Size of each element
* @return Element position
*/
protected int __element(int offset, int j, int elem_size);
/**
* Get union table at offset
* @param offset Union offset
* @return Table instance or null
*/
protected Table __union(int offset);
/**
* Get ByteBuffer as byte array
* @return Byte array copy of buffer
*/
protected byte[] __vector_as_bytebuffer(int offset);
/**
* Get ByteBuffer starting at vector
* @param offset Vector offset
* @param elem_size Size of each element
* @return ByteBuffer view of vector data
*/
protected ByteBuffer __vector_as_bytebuffer(int offset, int elem_size);
}When using flatc --java, the compiler generates Java classes following these patterns.
// Example generated Java (from monster.fbs):
import com.google.flatbuffers.*;
import java.nio.ByteBuffer;
public final class Vec3 extends Struct {
public Vec3 __assign(int _i, ByteBuffer _bb) {
__init(_i, _bb);
return this;
}
public float x() {
return bb.getFloat(bb_pos + 0);
}
public float y() {
return bb.getFloat(bb_pos + 4);
}
public float z() {
return bb.getFloat(bb_pos + 8);
}
public static int pack(FlatBufferBuilder builder, float x, float y, float z) {
builder.prep(4, 12);
builder.putFloat(z);
builder.putFloat(y);
builder.putFloat(x);
return builder.offset();
}
}
public final class Monster extends Table {
public static void ValidateVersion() {
Constants.FLATBUFFERS_25_2_10();
}
public static Monster getRootAs(ByteBuffer _bb) {
return getRootAs(_bb, new Monster());
}
public static Monster getRootAs(ByteBuffer _bb, Monster obj) {
_bb.order(ByteOrder.LITTLE_ENDIAN);
return obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb);
}
public void __init(int _i, ByteBuffer _bb) {
__reset(_i, _bb);
}
public Monster __assign(int _i, ByteBuffer _bb) {
__init(_i, _bb);
return this;
}
public Vec3 pos() {
return pos(new Vec3());
}
public Vec3 pos(Vec3 obj) {
int o = __offset(4);
return o != 0 ? obj.__assign(bb_pos + o, bb) : null;
}
public short mana() {
int o = __offset(6);
return o != 0 ? bb.getShort(o + bb_pos) : 150;
}
public short hp() {
int o = __offset(8);
return o != 0 ? bb.getShort(o + bb_pos) : 100;
}
public String name() {
int o = __offset(10);
return o != 0 ? __string(o + bb_pos) : null;
}
public int inventory(int j) {
int o = __offset(14);
return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0;
}
public int inventoryLength() {
int o = __offset(14);
return o != 0 ? __vector_len(o) : 0;
}
public ByteBuffer inventoryAsByteBuffer() {
return __vector_as_bytebuffer(14, 1);
}
public ByteBuffer inventoryInByteBuffer(ByteBuffer _bb) {
return __vector_in_bytebuffer(_bb, 14, 1);
}
public static int createMonster(FlatBufferBuilder builder,
int pos,
short mana,
short hp,
int name,
int inventory) {
builder.startTable(6);
Monster.addInventory(builder, inventory);
Monster.addName(builder, name);
Monster.addPos(builder, pos);
Monster.addHp(builder, hp);
Monster.addMana(builder, mana);
return Monster.endMonster(builder);
}
public static void startMonster(FlatBufferBuilder builder) {
builder.startTable(6);
}
public static void addPos(FlatBufferBuilder builder, int pos) {
builder.addStruct(0, pos, 0);
}
public static void addMana(FlatBufferBuilder builder, short mana) {
builder.addShort(1, mana, 150);
}
public static void addHp(FlatBufferBuilder builder, short hp) {
builder.addShort(2, hp, 100);
}
public static void addName(FlatBufferBuilder builder, int name) {
builder.addOffset(3, name, 0);
}
public static void addInventory(FlatBufferBuilder builder, int inventory) {
builder.addOffset(5, inventory, 0);
}
public static int createInventoryVector(FlatBufferBuilder builder, byte[] data) {
return builder.createByteVector(data);
}
public static void startInventoryVector(FlatBufferBuilder builder, int numElems) {
builder.startVector(1, numElems, 1);
}
public static int endMonster(FlatBufferBuilder builder) {
int o = builder.endTable();
return o;
}
}FlatBuffers Java integrates seamlessly with Java NIO ByteBuffer for efficient memory management.
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.google.flatbuffers.FlatBufferBuilder;
// Working with ByteBuffers
public class ByteBufferUtils {
/**
* Create FlatBufferBuilder from existing ByteBuffer
* @param bb Existing ByteBuffer
* @return FlatBufferBuilder using the buffer
*/
public static FlatBufferBuilder fromByteBuffer(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
return new FlatBufferBuilder(bb);
}
/**
* Read FlatBuffer from ByteBuffer
* @param bb ByteBuffer containing FlatBuffer data
* @return Root table position
*/
public static int getRootOffset(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
return bb.getInt(bb.position()) + bb.position();
}
/**
* Create read-only view of buffer data
* @param builder Completed FlatBufferBuilder
* @return Read-only ByteBuffer
*/
public static ByteBuffer asReadOnlyBuffer(FlatBufferBuilder builder) {
return builder.dataBuffer().asReadOnlyBuffer();
}
}Working with files and streams in Java.
import java.io.*;
import java.nio.file.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FlatBufferIO {
/**
* Save FlatBuffer to file
* @param builder Completed FlatBufferBuilder
* @param filename Output file path
* @throws IOException If write fails
*/
public static void saveToFile(FlatBufferBuilder builder, String filename) throws IOException {
byte[] data = builder.sizedByteArray();
Files.write(Paths.get(filename), data);
}
/**
* Load FlatBuffer from file
* @param filename Input file path
* @return ByteBuffer containing data
* @throws IOException If read fails
*/
public static ByteBuffer loadFromFile(String filename) throws IOException {
byte[] data = Files.readAllBytes(Paths.get(filename));
ByteBuffer bb = ByteBuffer.wrap(data);
bb.order(ByteOrder.LITTLE_ENDIAN);
return bb;
}
/**
* Save FlatBuffer using FileChannel for large files
* @param builder Completed FlatBufferBuilder
* @param filename Output file path
* @throws IOException If write fails
*/
public static void saveWithChannel(FlatBufferBuilder builder, String filename) throws IOException {
try (FileChannel channel = FileChannel.open(Paths.get(filename),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING)) {
ByteBuffer buffer = builder.dataBuffer();
channel.write(buffer);
}
}
/**
* Write FlatBuffer to OutputStream
* @param builder Completed FlatBufferBuilder
* @param out Output stream
* @throws IOException If write fails
*/
public static void writeToStream(FlatBufferBuilder builder, OutputStream out) throws IOException {
byte[] data = builder.sizedByteArray();
out.write(data);
}
/**
* Read FlatBuffer from InputStream
* @param in Input stream
* @return ByteBuffer containing data
* @throws IOException If read fails
*/
public static ByteBuffer readFromStream(InputStream in) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] chunk = new byte[8192];
int bytesRead;
while ((bytesRead = in.read(chunk)) != -1) {
buffer.write(chunk, 0, bytesRead);
}
ByteBuffer bb = ByteBuffer.wrap(buffer.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
return bb;
}
}Complete Usage Example:
import com.google.flatbuffers.*;
import java.nio.ByteBuffer;
import java.io.IOException;
// Import generated classes
import MyGame.Sample.Monster;
import MyGame.Sample.Vec3;
public class FlatBufferExample {
public static void main(String[] args) throws IOException {
// Create monster
FlatBufferBuilder builder = new FlatBufferBuilder(1024);
// Create components
int name = builder.createString("Dragon");
int pos = Vec3.pack(builder, 1.0f, 2.0f, 3.0f);
byte[] inventoryData = {1, 2, 3, 4, 5};
int inventory = builder.createByteVector(inventoryData);
// Build monster
int monster = Monster.createMonster(builder, pos, (short)200, (short)150, name, inventory);
// Finish buffer
builder.finish(monster);
// Get binary data
byte[] buffer = builder.sizedByteArray();
// Read the data back
ByteBuffer bb = ByteBuffer.wrap(buffer);
Monster readMonster = Monster.getRootAs(bb);
System.out.println("Name: " + readMonster.name());
System.out.println("HP: " + readMonster.hp());
System.out.println("Mana: " + readMonster.mana());
Vec3 position = readMonster.pos();
if (position != null) {
System.out.println("Position: " + position.x() + ", " + position.y() + ", " + position.z());
}
System.out.println("Inventory size: " + readMonster.inventoryLength());
for (int i = 0; i < readMonster.inventoryLength(); i++) {
System.out.println("Item " + i + ": " + readMonster.inventory(i));
}
// Save to file
FlatBufferIO.saveToFile(builder, "monster.bin");
// Load from file
ByteBuffer loadedBuffer = FlatBufferIO.loadFromFile("monster.bin");
Monster loadedMonster = Monster.getRootAs(loadedBuffer);
System.out.println("Loaded name: " + loadedMonster.name());
}
}