This is an automated email from the ASF dual-hosted git repository.
ipolyzos pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fluss.git
The following commit(s) were added to refs/heads/main by this push:
new f7062eae1 [Docs] Document the TypedAPI #2230 (#2261)
f7062eae1 is described below
commit f7062eae19be72e5c8dd70373d43cf1f8d283d07
Author: Prajwal banakar <[email protected]>
AuthorDate: Sun Dec 28 22:48:31 2025 +0530
[Docs] Document the TypedAPI #2230 (#2261)
* This commit adds documentation for the new Typed API, which allows users
to work directly with POJOs. It includes examples for writing, reading, and
performing lookups, as well as a note on performance considerations.
* refactor(docs): Merge Typed API docs into Java Client page
---
website/docs/apis/java-client.md | 173 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 170 insertions(+), 3 deletions(-)
diff --git a/website/docs/apis/java-client.md b/website/docs/apis/java-client.md
index 8de648e97..3238137df 100644
--- a/website/docs/apis/java-client.md
+++ b/website/docs/apis/java-client.md
@@ -170,8 +170,7 @@ List<User> users = List.of(
);
```
-**Note:** Currently data in Fluss is written in the form of `rows`, so we need
to convert our POJO to `GenericRow`, while the Fluss community is working to
provide
-a more user-friendly API for writing data.
+**Note:** Currently data in Fluss is written in the form of `rows`, so we need
to convert our POJO to `GenericRow`. For a more user-friendly API for writing
data, please refer to the [Java Typed API](#java-typed-api) section below.
```java
Table table = connection.getTable(tablePath);
@@ -244,4 +243,172 @@ LookupResult prefixLookup = table.newLookup()
.createLookuper()
.lookup(rowKey)
.get();
-```
\ No newline at end of file
+```
+
+## Java Typed API
+
+Fluss provides a Typed API that allows you to work directly with Java POJOs
(Plain Old Java Objects) instead of `InternalRow` objects. This simplifies
development by automatically mapping your Java classes to Fluss table schemas.
+
+:::info
+The Typed API provides a more user-friendly experience but comes with a
performance cost due to the overhead of converting between POJOs and internal
row formats. For high-performance use cases, consider using the lower-level
`InternalRow` API.
+:::
+
+### Defining POJOs
+
+To use the Typed API, define a Java class where the field names and types
match your Fluss table schema.
+
+```java
+public class User {
+ public Integer id;
+ public String name;
+ public Integer age;
+
+ public User() {}
+
+ public User(Integer id, String name, Integer age) {
+ this.id = id;
+ this.name = name;
+ this.age = age;
+ }
+
+ // Getters, setters, equals, hashCode, toString...
+}
+```
+
+The supported type mappings are:
+
+| Fluss Type | Java Type |
+|---|---|
+| INT | Integer |
+| BIGINT | Long |
+| STRING | String |
+| BOOLEAN | Boolean |
+| FLOAT | Float |
+| DOUBLE | Double |
+| DECIMAL | BigDecimal |
+| DATE | LocalDate |
+| TIME | LocalTime |
+| TIMESTAMP | LocalDateTime |
+| TIMESTAMP_LTZ | Instant |
+| BINARY / BYTES | byte[] |
+
+### Writing Data
+
+#### Append Writer
+
+For append-only tables (Log tables), use `TypedAppendWriter`.
+
+```java
+TablePath path = TablePath.of("my_db", "users_log");
+try (Table table = conn.getTable(path)) {
+ TypedAppendWriter<User> writer =
table.newAppend().createTypedWriter(User.class);
+
+ writer.append(new User(1, "Alice", 30));
+ writer.append(new User(2, "Bob", 25));
+
+ writer.flush();
+}
+```
+
+#### Upsert Writer
+
+For primary key tables, use `TypedUpsertWriter`.
+
+```java
+TablePath path = TablePath.of("my_db", "users_pk");
+try (Table table = conn.getTable(path)) {
+ TypedUpsertWriter<User> writer =
table.newUpsert().createTypedWriter(User.class);
+
+ // Insert or Update
+ writer.upsert(new User(1, "Alice", 31));
+
+ // Delete
+ writer.delete(new User(1, null, null)); // Only PK fields are needed for
delete
+
+ writer.flush();
+}
+```
+
+#### Partial Updates
+
+You can perform partial updates by specifying the columns to update.
+
+```java
+// Update only 'name' and 'age' for the user with id 1
+Upsert upsert = table.newUpsert().partialUpdate("name", "age");
+TypedUpsertWriter<User> writer = upsert.createTypedWriter(User.class);
+
+User partialUser = new User();
+partialUser.id = 1;
+partialUser.name = "Alice Updated";
+partialUser.age = 32;
+
+writer.upsert(partialUser);
+writer.flush();
+```
+
+### Reading Data
+
+Use `TypedLogScanner` to read data as POJOs.
+
+```java
+Scan scan = table.newScan();
+TypedLogScanner<User> scanner = scan.createTypedLogScanner(User.class);
+
+try (CloseableIterator<TypedScanRecord<User>> iterator =
scanner.subscribeFromBeginning()) {
+ while (iterator.hasNext()) {
+ TypedScanRecord<User> record = iterator.next();
+ ChangeType changeType = record.getChangeType();
+ User user = record.getValue();
+
+ System.out.println(changeType + ": " + user);
+ }
+}
+```
+
+#### Projections
+
+You can also use projections with the Typed API. The POJO fields that are not
part of the projection will be null.
+
+```java
+// Only read 'id' and 'name'
+TypedLogScanner<User> scanner = table.newScan()
+ .project("id", "name")
+ .createTypedLogScanner(User.class);
+```
+
+### Lookups
+
+For primary key tables, you can perform lookups using a POJO that represents
the primary key.
+
+```java
+// Define a POJO for the key
+public class UserId {
+ public Integer id;
+
+ public UserId(Integer id) { this.id = id; }
+}
+
+// Create a TypedLookuper
+TypedLookuper<UserId> lookuper =
table.newLookup().createTypedLookuper(UserId.class);
+
+// Perform lookup
+CompletableFuture<LookupResult> resultFuture = lookuper.lookup(new UserId(1));
+LookupResult result = resultFuture.get();
+
+if (result != null) {
+ // Convert the result row back to a User POJO if needed
+ // Note: You might need a RowToPojoConverter for this part if you want the
full User object
+ // or you can access fields from the InternalRow directly.
+}
+```
+
+### Performance Considerations
+
+While the Typed API offers convenience and type safety, it involves an
additional layer of conversion between your POJOs and Fluss's internal binary
row format (`InternalRow`). This conversion process (serialization and
deserialization) introduces CPU overhead.
+
+Benchmarks indicate that using the Typed API can be roughly **2x slower** than
using the `InternalRow` API directly for both writing and reading operations.
+
+**Recommendation:**
+* Use the **Typed API** for ease of use, rapid development, and when type
safety is preferred over raw performance.
+* Use the **InternalRow API** for high-throughput, latency-sensitive
applications where performance is critical.