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

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


The following commit(s) were added to refs/heads/ignite-13618 by this push:
     new 7e57785  WIP. Minors after review.
7e57785 is described below

commit 7e57785614359f3c0fcef45725305d5b3292968b
Author: Andrew Mashenkov <andrey.mashen...@gmail.com>
AuthorDate: Thu Nov 12 16:23:10 2020 +0300

    WIP. Minors after review.
---
 .../schema/marshaller/BaseTypeMarshaller.java      |  63 --------
 .../schema/marshaller/ClassMarshaller.java         |  91 -----------
 .../internal/schema/marshaller/FieldAccessor.java  |  98 +++++++++++-
 .../internal/schema/marshaller/JavaSerializer.java | 167 +++++++++++++++++++--
 .../internal/schema/marshaller/Marshaller.java     |  91 +++++++++--
 .../schema/marshaller/SerializationException.java  |  13 +-
 .../ignite/internal/util/IgniteUnsafeUtils.java    |  57 +++++++
 .../ignite/internal/schema/SchemaTestSuite.java    |   3 +
 .../schema/marshaller/JavaSerializerTest.java      |  62 ++++++++
 9 files changed, 451 insertions(+), 194 deletions(-)

diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java
deleted file mode 100644
index 7b9d0f4..0000000
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.internal.schema.marshaller;
-
-import java.util.Objects;
-import org.apache.ignite.internal.schema.Tuple;
-import org.apache.ignite.internal.schema.TupleAssembler;
-
-/**
- * (De)serializer handler for object of base types.
- */
-class BaseTypeMarshaller implements Marshaller {
-    /** Write mode. */
-    private final BinaryMode mode;
-
-    /**
-     * Constructor.
-     *
-     * @param mode Binary mode.
-     */
-    public BaseTypeMarshaller(BinaryMode mode) {
-        this.mode = Objects.requireNonNull(mode);
-    }
-
-    /** {@inheritDoc} */
-    @Override public int nonNullVarLenCols(Object obj) {
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Object value(Object obj, int colIdx) {
-        assert colIdx == 0 : "No columns expected for native types.";
-
-        return obj;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Object readObject(Tuple reader) {
-        return JavaSerializer.readRefValue(reader, 0, mode);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void writeObject(Object val, TupleAssembler writer) {
-        Objects.requireNonNull(val, "Null values are not supported."); //TODO: 
Add 'tombstones' (null-values) support.
-
-        JavaSerializer.writeRefObject(val, writer, mode);
-    }
-}
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java
deleted file mode 100644
index 3bc1d76..0000000
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.internal.schema.marshaller;
-
-import org.apache.ignite.internal.schema.Columns;
-import org.apache.ignite.internal.schema.Tuple;
-import org.apache.ignite.internal.schema.TupleAssembler;
-import org.jetbrains.annotations.Unmodifiable;
-
-/**
- * General purpose (de)serializer handler for objects of complex types.
- */
-public class ClassMarshaller<T> implements Marshaller {
-    /** Mapped columns. */
-    private final Columns cols;
-
-    /**
-     * Field accessors for mapped columns.
-     * Array has same size and order as columns.
-     */
-    private final FieldAccessor[] fieldAccessors;
-
-    /** Object factory for class. */
-    private final ObjectFactory<T> factory;
-
-    /**
-     * Constructor.
-     *
-     * @param cols Mapped columns.
-     * @param factory Object factory.
-     * @param fieldAccessors Object field accessors for mapped columns.
-     */
-    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
-    public ClassMarshaller(Columns cols, ObjectFactory<T> factory, 
FieldAccessor[] fieldAccessors) {
-        this.cols = cols;
-        this.fieldAccessors = fieldAccessors;
-        this.factory = factory;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int nonNullVarLenCols(Object obj) throws 
SerializationException {
-        if (obj == null)
-            return 0;
-
-        int cnt = 0;
-
-        for (int fldIdx = cols.firstVarlengthColumn(); fldIdx < cols.length(); 
fldIdx++) {
-            if (fieldAccessors[fldIdx].value(obj) == null)
-                cnt++;
-        }
-
-        return cnt;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Object value(Object obj, int fldIdx) throws 
SerializationException {
-        return fieldAccessors[fldIdx].value(obj);
-    }
-
-    /** {@inheritDoc} */
-    @Override public Object readObject(Tuple reader) throws 
SerializationException {
-        final T obj = factory.newInstance();
-
-        for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
-            fieldAccessors[fldIdx].read(obj, reader);
-
-        return obj;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void writeObject(Object obj, TupleAssembler writer) 
throws SerializationException {
-        for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++) {
-            fieldAccessors[fldIdx].write(obj, writer);
-        }
-    }
-}
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
index 45f79c7..df182bd 100644
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
@@ -18,7 +18,9 @@
 package org.apache.ignite.internal.schema.marshaller;
 
 import java.lang.reflect.Field;
+import java.util.Objects;
 import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
 import org.apache.ignite.internal.schema.Tuple;
 import org.apache.ignite.internal.schema.TupleAssembler;
 import org.jetbrains.annotations.Nullable;
@@ -44,7 +46,11 @@ public abstract class FieldAccessor {
     /** Mode. */
     protected final BinaryMode mode;
 
-    /** Column index. */
+    /**
+     * Mapped column position in schema.
+     *
+     * NODE: Do not mix up with column index in {@link Columns} container.
+     */
     protected final int colIdx;
 
     /**
@@ -52,7 +58,7 @@ public abstract class FieldAccessor {
      *
      * @param field Field.
      * @param col Mapped column.
-     * @param colIdx Column index.
+     * @param colIdx Column index in schema.
      * @return Accessor.
      */
     //TODO: Extract a provider for this factory-method.
@@ -101,6 +107,44 @@ public abstract class FieldAccessor {
     }
 
     /**
+     * Create accessor for the field.
+     *
+     * @param col Column.
+     * @param colIdx Column index.
+     * @param mode Binary mode.
+     * @return Accessor.
+     */
+    static FieldAccessor createIdentityAccessor(Column col, int colIdx, 
BinaryMode mode) {
+        switch (mode) {
+            //  Marshaller read/write object contract methods allowed boxed 
types only.
+            case P_BYTE:
+            case P_SHORT:
+            case P_INT:
+            case P_LONG:
+            case P_FLOAT:
+            case P_DOUBLE:
+                throw new IllegalArgumentException("Primitive key/value types 
are not possible by API contract.");
+
+            case BYTE:
+            case SHORT:
+            case INT:
+            case LONG:
+            case FLOAT:
+            case DOUBLE:
+            case STRING:
+            case UUID:
+            case BYTE_ARR:
+            case BITSET:
+                return new IdentityAccessor(colIdx, mode);
+
+            default:
+                assert false : "Invalid mode " + mode;
+        }
+
+        throw new IllegalArgumentException("Failed to create accessor for 
column [name=" + col.name() + ']');
+    }
+
+    /**
      * Protected constructor.
      *
      * @param field Field.
@@ -108,7 +152,6 @@ public abstract class FieldAccessor {
      * @param mode Binary mode;
      */
     protected FieldAccessor(Field field, int colIdx, BinaryMode mode) {
-        assert field != null;
         assert colIdx >= 0;
         assert mode != null;
 
@@ -116,7 +159,8 @@ public abstract class FieldAccessor {
         this.colIdx = colIdx;
         this.mode = mode;
 
-        field.setAccessible(true);
+        if (field != null)
+            field.setAccessible(true);
     }
 
     /**
@@ -137,7 +181,7 @@ public abstract class FieldAccessor {
      */
     public void write(Object obj, TupleAssembler writer) throws 
SerializationException {
         try {
-            write0(obj, writer);
+            write0(Objects.requireNonNull(obj), writer);
         }
         catch (Exception ex) {
             if (includeSensitive())
@@ -165,7 +209,7 @@ public abstract class FieldAccessor {
      */
     public void read(Object obj, Tuple reader) throws SerializationException {
         try {
-            read0(obj, reader);
+            read0(Objects.requireNonNull(obj), reader);
         }
         catch (Exception ex) {
             if (includeSensitive())
@@ -185,6 +229,16 @@ public abstract class FieldAccessor {
     protected abstract void read0(Object obj, Tuple reader) throws 
IllegalAccessException;
 
     /**
+     * Read value.
+     *
+     * @param reader Tuple reader.
+     * @return Object.
+     */
+    public Object read(Tuple reader) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Reads object field value.
      *
      * @param obj Object.
@@ -193,7 +247,7 @@ public abstract class FieldAccessor {
      */
     @Nullable Object value(Object obj) throws SerializationException {
         try {
-            return field.get(obj);
+            return field.get(Objects.requireNonNull(obj));
         }
         catch (IllegalAccessException ex) {
             if (includeSensitive())
@@ -206,6 +260,36 @@ public abstract class FieldAccessor {
     /**
      * Accessor for field of primitive {@code byte} type.
      */
+    private static class IdentityAccessor extends FieldAccessor {
+        /**
+         * Constructor.
+         *
+         * @param colIdx Column index.
+         * @param mode Binary mode.
+         */
+        public IdentityAccessor(int colIdx, BinaryMode mode) {
+            super(null, colIdx, mode);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            JavaSerializer.writeRefObject(Objects.requireNonNull(obj, "Null 
values are not supported."), writer, mode);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected void read0(Object obj, Tuple reader) {
+            throw new UnsupportedOperationException("Called identity accessor 
for object field.");
+        }
+
+        /** {@inheritDoc} */
+        @Override public Object read(Tuple reader) {
+            return JavaSerializer.readRefValue(reader, colIdx, mode);
+        }
+    }
+
+    /**
+     * Accessor for field of primitive {@code byte} type.
+     */
     private static class BytePrimitiveAccessor extends FieldAccessor {
         /**
          * Constructor.
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
index ebecee9..cff95ef 100644
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
@@ -17,9 +17,13 @@
 
 package org.apache.ignite.internal.schema.marshaller;
 
+import java.lang.reflect.Field;
 import java.util.BitSet;
 import java.util.UUID;
+import org.apache.ignite.internal.schema.ByteBufferTuple;
 import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
 import org.apache.ignite.internal.schema.Tuple;
 import org.apache.ignite.internal.schema.TupleAssembler;
@@ -31,7 +35,6 @@ import org.jetbrains.annotations.NotNull;
  * TODO: Extract interface.
  */
 public class JavaSerializer {
-
     /**
      * Gets binary read/write mode for given class.
      *
@@ -229,7 +232,10 @@ public class JavaSerializer {
     /** Schema. */
     private final SchemaDescriptor schema;
 
+    /** Key class. */
     private final Class<?> keyClass;
+
+    /** Value class. */
     private final Class<?> valClass;
 
     /** Key marshaller. */
@@ -250,32 +256,48 @@ public class JavaSerializer {
         this.keyClass = keyClass;
         this.valClass = valClass;
 
-        keyMarsh = createMarshaller(schema, keyClass);
-        valMarsh = createMarshaller(schema, valClass);
+        keyMarsh = createMarshaller(schema.keyColumns(), 0, keyClass);
+        valMarsh = createMarshaller(schema.valueColumns(), 
schema.keyColumns().length(), valClass);
     }
 
     /**
      * Creates marshaller for class.
      *
-     * @param schema Schema.
+     * @param cols Columns.
+     * @param firstColId First column position in schema.
      * @param aClass Type.
      * @return Marshaller.
      */
-    @NotNull private <T> Marshaller createMarshaller(SchemaDescriptor schema, 
Class<T> aClass) {
+    @NotNull private static Marshaller createMarshaller(Columns cols, int 
firstColId, Class<?> aClass) {
         final BinaryMode mode = mode(aClass);
 
         if (mode != null) {
-            final Column col = schema.keyColumns().column(0);
+            final Column col = cols.column(0);
 
+            assert cols.length() == 1;
             assert mode.typeSpec() == col.type().spec() : "Target type is not 
compatible.";
-            assert aClass.isPrimitive() && col.nullable() : "Non-nullable 
types are not allowed.";
+            assert !aClass.isPrimitive() : "Non-nullable types are not 
allowed.";
 
-            return new BaseTypeMarshaller(mode);
+            return new Marshaller(FieldAccessor.createIdentityAccessor(col, 
firstColId, mode));
         }
 
-        // TODO: Build accessors
+        try {
+            FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
+
+            // Build accessors
+            for (int i = 0; i < cols.length(); i++) {
+                final Column col = cols.column(i);
+                final Field field = aClass.getDeclaredField(col.name());
 
-        return new ClassMarshaller<>(schema.keyColumns(), 
ObjectFactory.classFactory(aClass), null);
+                final int colIdx = firstColId + i; /* Absolute column idx in 
schema. */
+                fieldAccessors[i] = FieldAccessor.create(field, col, colIdx);
+            }
+
+            return new Marshaller(ObjectFactory.classFactory(aClass), 
fieldAccessors);
+        }
+        catch (NoSuchFieldException | SecurityException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     /**
@@ -289,16 +311,129 @@ public class JavaSerializer {
         assert keyClass.isInstance(key);
         assert val == null || valClass.isInstance(val);
 
+        final TupleAssembler asm = createAssembler(key, val);
+
+        keyMarsh.writeObject(key, asm);
+
+        if (val != null)
+            valMarsh.writeObject(val, asm);
+        else
+            assert false; // TODO: add tomstone support and remove assertion.
+
+        return asm.build();
+    }
+
+    /**
+     * Creates TupleAssebler for key-value pair.
+     *
+     * @param key Key object.
+     * @param val Value object.
+     * @return Tuple assembler.
+     * @throws SerializationException If failed.
+     */
+    @NotNull private TupleAssembler createAssembler(Object key, Object val) 
throws SerializationException {
+        ObjectStatistic keyStat = collectObjectStats(schema.keyColumns(), 
keyMarsh, key);
+        ObjectStatistic valStat = collectObjectStats(schema.valueColumns(), 
valMarsh, val);
+
+        int size = TupleAssembler.tupleSize(
+            schema.keyColumns(), keyStat.nonNullFields, 
keyStat.nonNullFieldsSize,
+            schema.valueColumns(), valStat.nonNullFields, 
valStat.nonNullFieldsSize);
+
+        return new TupleAssembler(schema, size, keyStat.nonNullFields, 
valStat.nonNullFields);
+    }
+
+    /**
+     * Object statistic.
+     */
+    private static class ObjectStatistic {
+        /** Non-null fields of varlen type. */
+        int nonNullFields;
+
+        /** Length of all non-null fields of varlen types. */
+        int nonNullFieldsSize;
+
+        /** Constructor. */
+        public ObjectStatistic(int nonNullFields, int nonNullFieldsSize) {
+            this.nonNullFields = nonNullFields;
+            this.nonNullFieldsSize = nonNullFieldsSize;
+        }
+    }
+
+    /**
+     * Reads object fields and gather statistic.
+     *
+     * @param cols Schema columns.
+     * @param marsh Marshaller.
+     * @param obj Object.
+     * @return Object statistic.
+     * @throws SerializationException If failed.
+     */
+    private ObjectStatistic collectObjectStats(Columns cols, Marshaller marsh,
+        Object obj) throws SerializationException {
+        if (obj == null || cols.firstVarlengthColumn() < 0 /* No varlen 
columns */)
+            return new ObjectStatistic(0, 0);
+
+        int cnt = 0;
         int size = 0;
 
-        int nonNullVarLenKeyCols = keyMarsh.nonNullVarLenCols(key);
-        int nonNullVarLenValCols = valMarsh.nonNullVarLenCols(val);
+        for (int i = cols.firstVarlengthColumn(); i < cols.length(); i++) {
+            final Object val = marsh.value(obj, i);
 
-        final TupleAssembler asm = new TupleAssembler(schema, size, 
nonNullVarLenKeyCols, nonNullVarLenValCols);
+            if (val == null || cols.column(i).type().spec().fixedLength())
+                continue;
 
-        keyMarsh.writeObject(key, asm);
-        valMarsh.writeObject(val, asm); // TODO: support tomstones.
+            size += getValueSize(val, cols.column(i).type());
+            cnt++;
+        }
 
-        return asm.build();
+        return new ObjectStatistic(cnt, size);
+    }
+
+    /**
+     * Calculates size for serialized value of varlen type.
+     *
+     * @param val Field value.
+     * @param type Mapped type.
+     * @return Serialized value size.
+     */
+    private int getValueSize(Object val, NativeType type) {
+        switch (type.spec()) {
+            case BYTES:
+                return ((byte[])val).length;
+
+            case STRING:
+                return TupleAssembler.utf8EncodedLength((CharSequence)val);
+
+            default:
+                throw new IllegalStateException("Unsupported test varsize 
type: " + type);
+        }
+    }
+
+    /**
+     * @return Key object.
+     */
+    public Object deserializeKey(byte[] data) throws SerializationException {
+        final Tuple tuple = new ByteBufferTuple(schema, data);
+
+        final Object o = keyMarsh.readObject(tuple);
+
+        assert keyClass.isInstance(o);
+
+        return o;
+    }
+
+    /**
+     * @return Value object.
+     */
+    public Object deserializeValue(byte[] data) throws SerializationException {
+        final Tuple tuple = new ByteBufferTuple(schema, data);
+
+        // TODO: add tomstone support.
+
+        final Object o = valMarsh.readObject(tuple);
+
+        assert valClass.isInstance(o);
+
+        return o;
     }
 }
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
index d1e0a12..eb886c2 100644
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
@@ -15,34 +15,79 @@
  * limitations under the License.
  */
 
+/*
+ * 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.internal.schema.marshaller;
 
+import java.util.Objects;
 import org.apache.ignite.internal.schema.Tuple;
 import org.apache.ignite.internal.schema.TupleAssembler;
 
 /**
- * Marshaller interface.
+ * Marshaller.
  */
-public interface Marshaller {
+public class Marshaller {
     /**
-     * Counts number non-null fields of variable length types.
+     * Field accessors for mapped columns.
+     * Array has same size and order as columns.
+     */
+    private final FieldAccessor[] fieldAccessors;
+
+    /**
+     * Object factory for complex types or {@code null} for basic type.
+     */
+    private final ObjectFactory<?> factory;
+
+    /**
+     * Constructor.
+     * Creates marshaller for complex types.
      *
-     * @param obj Object to analyze.
-     * @return Amount of non-null fields of variable length types.
-     * @throws SerializationException If failed.
+     * @param factory Object factory.
+     * @param fieldAccessors Object field accessors for mapped columns.
      */
-    //TODO: do we really need this to be 'public'? Would package-private in 
abstract class be better?
-    int nonNullVarLenCols(Object obj) throws SerializationException;
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    public Marshaller(ObjectFactory<?> factory, FieldAccessor[] 
fieldAccessors) {
+        this.fieldAccessors = fieldAccessors;
+        this.factory = Objects.requireNonNull(factory);
+    }
 
     /**
-     * Reads object field value mapped to column of given index in schema.
+     * Constructor.
+     * Creates marshaller for basic types.
+     *
+     * @param fieldAccessor Identity field accessor for object of basic type.
+     */
+    public Marshaller(FieldAccessor fieldAccessor) {
+        fieldAccessors = new FieldAccessor[] {fieldAccessor};
+        factory = null;
+    }
+
+    /**
+     * Reads object field.
      *
      * @param obj Object.
-     * @param colIdx Column index.
+     * @param fldIdx Field index.
      * @return Field value.
      * @throws SerializationException If failed.
      */
-    Object value(Object obj, int colIdx) throws SerializationException;
+    public Object value(Object obj, int fldIdx) throws SerializationException {
+        return fieldAccessors[fldIdx].value(obj);
+    }
 
     /**
      * Reads object from tuple.
@@ -51,7 +96,17 @@ public interface Marshaller {
      * @return Object.
      * @throws SerializationException If failed.
      */
-    Object readObject(Tuple reader) throws SerializationException;
+    public Object readObject(Tuple reader) throws SerializationException {
+        if (isBasicMarshaller())
+            return fieldAccessors[0].read(reader);
+
+        final Object obj = factory.newInstance();
+
+        for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
+            fieldAccessors[fldIdx].read(obj, reader);
+
+        return obj;
+    }
 
     /**
      * Write object to tuple.
@@ -60,5 +115,15 @@ public interface Marshaller {
      * @param writer Tuple writer.
      * @throws SerializationException If failed.
      */
-    void writeObject(Object obj, TupleAssembler writer) throws 
SerializationException;
+    public void writeObject(Object obj, TupleAssembler writer) throws 
SerializationException {
+        for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
+            fieldAccessors[fldIdx].write(obj, writer);
+    }
+
+    /**
+     * @return {@code true} if it is marshaller for basic type, {@code false} 
otherwise.
+     */
+    private boolean isBasicMarshaller() {
+        return factory == null;
+    }
 }
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
index 4e3368e..aa8a497 100644
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
@@ -17,12 +17,17 @@
 
 package org.apache.ignite.internal.schema.marshaller;
 
+/**
+ * Serialization exception.
+ */
 public class SerializationException extends Exception {
+    /**
+     * Constructor.
+     *
+     * @param message Message.
+     * @param cause Cause.
+     */
     public SerializationException(String message, Throwable cause) {
         super(message, cause);
     }
-
-    public SerializationException(Throwable cause) {
-        super(cause);
-    }
 }
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java
new file mode 100644
index 0000000..3bce3df
--- /dev/null
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java
@@ -0,0 +1,57 @@
+/*
+ *
+ *  * 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.internal.util;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import sun.misc.Unsafe;
+
+//TODO Move class to 'java-8' profile. Java9+ should use varhandles instead.
+public class IgniteUnsafeUtils {
+    /** Unsafe. */
+    private static final Unsafe UNSAFE = unsafe();
+    /**
+     * @return Instance of Unsafe class.
+     */
+    private static Unsafe unsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        }
+        catch (SecurityException ignored) {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Unsafe>() {
+                        @Override public Unsafe run() throws Exception {
+                            Field f = 
Unsafe.class.getDeclaredField("theUnsafe");
+
+                            f.setAccessible(true);
+
+                            return (Unsafe)f.get(null);
+                        }
+                    });
+            }
+            catch (PrivilegedActionException e) {
+                throw new RuntimeException("Could not initialize intrinsics.", 
e.getCause());
+            }
+        }
+    }
+}
diff --git 
a/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
 
b/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
index 3eded6a..af2106e 100644
--- 
a/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
+++ 
b/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.schema;
 
+import org.apache.ignite.internal.schema.marshaller.JavaSerializerTest;
 import org.junit.platform.runner.JUnitPlatform;
 import org.junit.platform.suite.api.SelectClasses;
 import org.junit.runner.RunWith;
@@ -24,8 +25,10 @@ import org.junit.runner.RunWith;
 /**
  *
  */
+@SuppressWarnings("JUnit5Platform")
 @RunWith(JUnitPlatform.class)
 @SelectClasses({
+    JavaSerializerTest.class,
     NativeTypeTest.class,
     ColumnTest.class,
     ColumnsTest.class,
diff --git 
a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
 
b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
new file mode 100644
index 0000000..e1b4d6c
--- /dev/null
+++ 
b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.internal.schema.marshaller;
+
+import java.util.Random;
+import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.ignite.internal.schema.NativeType.BYTE;
+
+public class JavaSerializerTest {
+    /** */
+    private Random rnd;
+
+    /**
+     *
+     */
+    @BeforeEach
+    public void initRandom() {
+        long seed = System.currentTimeMillis();
+
+        System.out.println("Using seed: " + seed + "L; //");
+
+        rnd = new Random(seed);
+    }
+    @Test
+    public void testBasicTypes() throws Exception {
+        Column[] keyCols = new Column[] {new Column("key", BYTE, false)};
+        Column[] valCols = new Column[] {new Column("val", BYTE, false)};
+
+        final SchemaDescriptor schema = new SchemaDescriptor(1, new 
Columns(keyCols), new Columns(valCols));
+
+        final JavaSerializer serializer = new JavaSerializer(schema, 
Byte.class, Byte.class);
+
+        final Byte key = (byte)rnd.nextInt();
+        final Byte val = (byte)rnd.nextInt();
+
+        final byte[] bytes = serializer.serialize(key, val);
+
+        Assertions.assertEquals(key, serializer.deserializeKey(bytes));
+        Assertions.assertEquals(val, serializer.deserializeValue(bytes));
+    }
+}

Reply via email to