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.

Reply via email to