You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2021/01/22 10:56:52 UTC

[ignite-3] 01/01: Table access API. Draft. Simple examples added.

This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch ignite-14035
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit 528cfdec2de83ea3b87cd3ef03234aa78b05bec9
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Fri Jan 22 13:01:57 2021 +0300

    Table access API. Draft.
    Simple examples added.
---
 modules/commons/pom.xml                            |  58 ++++
 .../java/org/apache/ignite/storage/KVView.java     |  29 ++
 .../main/java/org/apache/ignite/storage/Row.java   |  31 ++
 .../main/java/org/apache/ignite/storage/Table.java |  46 +++
 .../java/org/apache/ignite/storage/TableView.java  |  29 ++
 .../apache/ignite/storage/binary/BinaryObject.java |  25 ++
 .../ignite/storage/binary/BinaryObjects.java       |  27 ++
 .../apache/ignite/storage/mapper/KeyMapper.java    |  24 ++
 .../org/apache/ignite/storage/mapper/Mappers.java  |  43 +++
 .../apache/ignite/storage/mapper/RowMapper.java    |  32 ++
 .../apache/ignite/storage/mapper/ValueMapper.java  |  33 ++
 .../java/org/apache/ignite/storage/Example.java    | 335 +++++++++++++++++++++
 pom.xml                                            |   3 +-
 13 files changed, 714 insertions(+), 1 deletion(-)

diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml
new file mode 100644
index 0000000..5ea7ce9
--- /dev/null
+++ b/modules/commons/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>apache-ignite</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-commons</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>${jetbrains.annotations.version}</version>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit.jupiter.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <version>${junit.jupiter.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/KVView.java b/modules/commons/src/main/java/org/apache/ignite/storage/KVView.java
new file mode 100644
index 0000000..f093f75
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/KVView.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage;
+
+/**
+ *
+ */
+public interface KVView<K, V> {
+    public V get(K key);
+
+    public V put(K key, V val);
+
+    public boolean putIfAbsent(K key, V val);
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/Row.java b/modules/commons/src/main/java/org/apache/ignite/storage/Row.java
new file mode 100644
index 0000000..06f5800
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/Row.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage;
+
+import org.apache.ignite.storage.binary.BinaryObject;
+
+/**
+ *
+ */
+public interface Row {
+    public <T> T field(String name);
+
+    public BinaryObject binaryObjectField(String fieldName);
+
+    int intField(String fieldName);
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/Table.java b/modules/commons/src/main/java/org/apache/ignite/storage/Table.java
new file mode 100644
index 0000000..2e0a36d
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/Table.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage;
+
+import org.apache.ignite.storage.mapper.KeyMapper;
+import org.apache.ignite.storage.mapper.Mappers;
+import org.apache.ignite.storage.mapper.RowMapper;
+import org.apache.ignite.storage.mapper.ValueMapper;
+
+/**
+ *
+ */
+public interface Table {
+    public <R> TableView<R> tableView(RowMapper<R> rowMapper);
+
+    public <K, V> KVView<K, V> kvView(KeyMapper<K> keyMapper, ValueMapper<V> valMapper);
+
+    public default <K, V> KVView<K, V> kvView(Class<K> kCls, Class<V> vCls) {
+        return kvView(Mappers.ofKeyClass(kCls), Mappers.ofValueClass(vCls));
+    }
+
+    public Row get(Row keyRow);
+
+    public Iterable<Row> find(Row template);
+
+    public boolean upsert(Row row);
+
+    public boolean insert(Row row);
+
+    Row createSearchRow(Object... args);
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/TableView.java b/modules/commons/src/main/java/org/apache/ignite/storage/TableView.java
new file mode 100644
index 0000000..4ded1e6
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/TableView.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage;
+
+/**
+ *
+ */
+public interface TableView<T> {
+    public T get(T keyRow);
+
+    public boolean upsert(T row);
+
+    public boolean insert(T row);
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObject.java b/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObject.java
new file mode 100644
index 0000000..8257bf5
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObject.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.binary;
+
+/**
+ *
+ */
+public interface BinaryObject {
+    Object deserialize(Class<?> targetCls);
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObjects.java b/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObjects.java
new file mode 100644
index 0000000..d4d3424
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/binary/BinaryObjects.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.binary;
+
+/**
+ *
+ */
+public class BinaryObjects {
+    public static BinaryObject wrap(byte[] objData) {
+        return null;
+    }
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/mapper/KeyMapper.java b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/KeyMapper.java
new file mode 100644
index 0000000..588da5f
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/KeyMapper.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.mapper;
+
+/**
+ *
+ */
+public interface KeyMapper<T> {
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/mapper/Mappers.java b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/Mappers.java
new file mode 100644
index 0000000..60db61c
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/Mappers.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.mapper;
+
+/**
+ *
+ */
+public class Mappers {
+    public static <K> KeyMapper<K> ofKeyClass(Class<K> keyCls) {
+        return null;
+    }
+
+    public static <V> ValueMapper<V> ofValueClass(Class<V> keyCls) {
+        return null;
+    }
+
+    public static <V> ValueMapper.Builder<V> ofValueClassBuilder(Class<V> valCls) {
+        return null;
+    }
+
+    public static <R> RowMapper<R> ofRowClass(Class<R> rowCls) {
+        return null;
+    }
+
+    public static <R> RowMapper.Builder<R> ofRowClassBuilder(Class<R> targetClass) {
+        return null;
+    }
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/mapper/RowMapper.java b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/RowMapper.java
new file mode 100644
index 0000000..0a4bdd2
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/RowMapper.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.mapper;
+
+import java.util.function.Function;
+import org.apache.ignite.storage.Row;
+
+/**
+ *
+ */
+public interface RowMapper<R> {
+    public interface Builder<R> {
+        public Builder<R> deserializing(String fieldName, Class<?> targetClass);
+        public Builder<R> map(String fieldName, Function<Row, Object> mapping);
+        public <R> RowMapper<R> build();
+    }
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/storage/mapper/ValueMapper.java b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/ValueMapper.java
new file mode 100644
index 0000000..b8e7139
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/storage/mapper/ValueMapper.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage.mapper;
+
+import java.util.function.Function;
+import org.apache.ignite.storage.Row;
+
+/**
+ *
+ */
+public interface ValueMapper<V> {
+    public interface Builder<V> {
+        public Builder<V> deserializing(String fieldName, Class<?> cls);
+        public Builder<V> map(String fieldName, Function<Row, Object> mapper);
+
+        public ValueMapper<V> build();
+    }
+}
diff --git a/modules/commons/src/test/java/org/apache/ignite/storage/Example.java b/modules/commons/src/test/java/org/apache/ignite/storage/Example.java
new file mode 100644
index 0000000..7b91c65
--- /dev/null
+++ b/modules/commons/src/test/java/org/apache/ignite/storage/Example.java
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.storage;
+
+import java.math.BigDecimal;
+import org.apache.ignite.storage.binary.BinaryObject;
+import org.apache.ignite.storage.binary.BinaryObjects;
+import org.apache.ignite.storage.mapper.Mappers;
+
+/**
+ *
+ */
+@SuppressWarnings({"unused", "UnusedAssignment"})
+public class Example {
+    /**
+     * Use case 1: a simple one. The table has the structure
+     * [
+     * [id int, orgId int] // key
+     * [name varchar, lastName varchar, decimal salary, int department] // value
+     * ]
+     * We show how to use the raw TableRow and a mapped class.
+     */
+    public void useCase1(Table t) {
+        // Search row will allow nulls even in non-null columns.
+        Row res = t.get(t.createSearchRow(1, 1));
+
+        String name = res.field("name");
+        String lastName = res.field("latName");
+        BigDecimal salary = res.field("salary");
+        Integer department = res.field("department");
+
+        // We may have primitive-returning methods if needed.
+        int departmentPrimitive = res.intField("department");
+
+        // Note that schema itself already defined which fields are key field.
+        class Employee {
+            final int id;
+            final int orgId;
+
+            String name;
+            String lastName;
+            BigDecimal salary;
+            int department;
+
+            Employee(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        TableView<Employee> employeeView = t.tableView(Mappers.ofRowClass(Employee.class));
+
+        Employee e = employeeView.get(new Employee(1, 1));
+
+        // As described in the IEP, we can have a truncated mapping.
+        class TruncatedEmployee {
+            final int id;
+            final int orgId;
+
+            String name;
+            String lastName;
+
+            TruncatedEmployee(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        TableView<TruncatedEmployee> truncatedEmployeeView = t.tableView(Mappers.ofRowClass(TruncatedEmployee.class));
+
+        // salary and department will not be sent over the network during this call.
+        TruncatedEmployee te = truncatedEmployeeView.get(new TruncatedEmployee(1, 1));
+    }
+
+    /**
+     * Use case 2: using simple KV mappings
+     * The table has structure is
+     * [
+     * [id int, orgId int] // key
+     * [name varchar, lastName varchar, decimal salary, int department] // value
+     * ]
+     */
+    public void useCase2(Table t) {
+        class EmployeeKey {
+            final int id;
+            final int orgId;
+
+            EmployeeKey(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        class Employee {
+            String name;
+            String lastName;
+            BigDecimal salary;
+            int department;
+        }
+
+        KVView<EmployeeKey, Employee> employeeKv = t.kvView(
+            Mappers.ofKeyClass(EmployeeKey.class),
+            Mappers.ofValueClass(Employee.class));
+
+        employeeKv.get(new EmployeeKey(1, 1));
+
+        // As described in the IEP, we can have a truncated KV mapping.
+        class TruncatedEmployee {
+            String name;
+            String lastName;
+        }
+
+        KVView<EmployeeKey, TruncatedEmployee> truncatedEmployeeKv = t.kvView(
+            Mappers.ofKeyClass(EmployeeKey.class),
+            Mappers.ofValueClass(TruncatedEmployee.class));
+
+        TruncatedEmployee te = truncatedEmployeeKv.get(new EmployeeKey(1, 1));
+    }
+
+    /**
+     * Use case 3: Single table strategy for inherited objects.
+     * The table has structure is
+     * [
+     * [id long] // key
+     * [owner varchar, cardNumber long, expYear int, expMonth int, accountNum long, bankName varchar] // value
+     * ]
+     */
+    public void useCase3(Table t) {
+        class BillingDetails {
+            String owner;
+        }
+
+        class CreditCard extends BillingDetails {
+            long cardNumber;
+            int expYear;
+            int expMonth;
+        }
+
+        class BankAccount extends BillingDetails {
+            long account;
+            String bankName;
+        }
+
+        KVView<Long, CreditCard> credCardKvView = t.kvView(
+            Mappers.ofKeyClass(Long.class),
+            Mappers.ofValueClass(CreditCard.class));
+
+        CreditCard cred = credCardKvView.get(1L);
+
+        KVView<Long, BankAccount> backAccKvView = t.kvView(
+            Mappers.ofKeyClass(Long.class),
+            Mappers.ofValueClass(BankAccount.class));
+
+        BankAccount ewd = backAccKvView.get(2L);
+    }
+
+    /**
+     * Use case 4: Conditional serialization.
+     * The table has structure is
+     * [
+     * [id int, orgId int] // key
+     * [owner varchar, type int, conditionalDetails byte[]] // value
+     * ]
+     */
+    public void useCase4(Table t) {
+        class OrderKey {
+            final int id;
+            final int orgId;
+
+            OrderKey(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        class OrderValue {
+            String owner;
+            int type;
+            Object billingDetails;
+        }
+
+        class CreditCard {
+            long cardNumber;
+            int expYear;
+            int expMonth;
+        }
+
+        class BankAccount {
+            long account;
+            String bankName;
+        }
+
+        KVView<OrderKey, OrderValue> orderKvView = t.kvView(Mappers.ofKeyClass(OrderKey.class),
+            Mappers.ofValueClassBuilder(OrderValue.class)
+                .map("billingDetails", (row) -> {
+                    BinaryObject bobj = row.binaryObjectField("conditionalDetails");
+                    int type = row.intField("type");
+
+                    return bobj.deserialize(type == 0 ? CreditCard.class : BankAccount.class);
+                }).build());
+
+        OrderValue ov = orderKvView.get(new OrderKey(1, 1));
+
+        // Same with RecordAPI.
+        Row res = t.get(t.createSearchRow(1, 1));
+
+        byte[] objData = res.field("billingDetails");
+        BinaryObject binObj = BinaryObjects.wrap(objData);
+        // Work with the binary object as in Ignite 2.x
+
+        // Additionally, we may have a shortcut similar to primitive methods.
+        binObj = res.binaryObjectField("billingDetails");
+
+        class OrderRecord {
+            final int id;
+            final int orgId;
+
+            String owner;
+            int type;
+            BinaryObject billingDetails;
+
+            OrderRecord(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        final TableView<OrderRecord> orderRecView = t.tableView(Mappers.ofRowClass(OrderRecord.class));
+
+        OrderRecord orderRecord = orderRecView.get(new OrderRecord(1, 1));
+        binObj = orderRecord.billingDetails;
+
+        // Manual deserialization.
+        Object billingDetails = orderRecord.type == 0 ?
+            binObj.deserialize(CreditCard.class) :
+            binObj.deserialize(BankAccount.class) ;
+    }
+
+    /**
+     * Use case 5: using byte[] and binary objects in columns.
+     * The table has structure
+     * [
+     * [id int, orgId int] // key
+     * [originalObject byte[], upgradedObject byte[], int department] // value
+     * ]
+     * Where {@code originalObject} is some value that was originally put to the column,
+     * {@code upgradedObject} is a version 2 of the object, and department is extracted field.
+     */
+    public void useCase5(Table t) {
+        Row res = t.get(t.createSearchRow(1, 1));
+
+        byte[] objData = res.field("originalObject");
+        BinaryObject binObj = BinaryObjects.wrap(objData);
+        // Work with the binary object as in Ignite 2.x
+
+        // Additionally, we may have a shortcut similar to primitive methods.
+        binObj = res.binaryObjectField("upgradedObject");
+
+        // Plain byte[] and BinaryObject fields in a class are straightforward.
+        class Record {
+            final int id;
+            final int orgId;
+
+            byte[] originalObject;
+            BinaryObject upgradedObject;
+            int department;
+
+            Record(int id, int orgId) {
+                this.id = id;
+                this.orgId = orgId;
+            }
+        }
+
+        TableView<Record> recordView = t.tableView(Mappers.ofRowClass(Record.class));
+
+        // Similarly work with the binary objects.
+        Record rec = recordView.get(new Record(1, 1));
+
+        // Now assume that we have some POJO classes to deserialize the binary objects.
+        class JavaPerson {
+            String name;
+            String lastName;
+        }
+
+        class JavaPersonV2 extends JavaPerson {
+            int department;
+        }
+
+        // We can have a compound record deserializing the whole tuple automatically.
+        class JavaPersonRecord {
+            JavaPerson originalObject;
+            JavaPersonV2 upgradedObject;
+            int department;
+        }
+
+        TableView<JavaPersonRecord> personRecordView = t.tableView(Mappers.ofRowClass(JavaPersonRecord.class));
+
+        // Or we can have an arbitrary record with custom class selection.
+        class TruncatedRecord {
+            JavaPerson upgradedObject;
+            int department;
+        }
+
+        TableView<TruncatedRecord> truncatedView = t.tableView(
+            Mappers.ofRowClassBuilder(TruncatedRecord.class)
+                .deserializing("upgradedObject", JavaPersonV2.class).build());
+
+        // Or we can have a custom conditional type selection.
+        TableView<TruncatedRecord> truncatedView2 = t.tableView(
+            Mappers.ofRowClassBuilder(TruncatedRecord.class)
+                .map("upgradedObject", (row) -> {
+                    BinaryObject bobj = row.binaryObjectField("upgradedObject");
+                    int dept = row.intField("department");
+
+                    return dept == 0 ? bobj.deserialize(JavaPerson.class) : bobj.deserialize(JavaPersonV2.class);
+                }).build());
+    }
+}
+
+
diff --git a/pom.xml b/pom.xml
index 0e6b050..e129595 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,11 +36,12 @@
     <modules>
         <module>modules/cli</module>
         <module>modules/cli-common</module>
+        <module>modules/commons</module>
         <module>modules/configuration</module>
         <module>modules/configuration-annotation-processor</module>
         <module>modules/ignite-runner</module>
     </modules>
-    
+
     <build>
         <plugins>
             <!--