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 2020/12/15 14:09:52 UTC

[ignite-3] 03/03: WIP.

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

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

commit c688848462841423ba6102188e6eeb88eb6881fd
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Tue Dec 15 17:09:29 2020 +0300

    WIP.
---
 .../apache/ignite/internal/schema/NativeType.java  |   8 +
 .../internal/schema/marshaller/MarshallerUtil.java | 239 ++++++++++-
 .../generator/FieldAccessExprGenerator.java        | 360 ----------------
 .../IdentityObjectMarshallerExprGenerator.java     |  35 +-
 .../generator/JaninoSerializerGenerator.java       | 451 +++++----------------
 .../generator/MarshallerExprGenerator.java         | 114 +++---
 .../marshaller/generator/TupleAccessorExpr.java    | 134 +++---
 .../benchmarks/SerializerBenchmarkTest.java        |  43 +-
 .../schema/marshaller/JavaSerializerTest.java      |  88 +++-
 9 files changed, 612 insertions(+), 860 deletions(-)

diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
index 211a1e1..e5d40c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
@@ -133,4 +133,12 @@ public class NativeType implements Comparable<NativeType> {
 
         return typeSpec.name().compareTo(o.typeSpec.name());
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "NativeType{" +
+            "typeSpec=" + typeSpec +
+            ", len=" + len +
+            '}';
+    }
 }
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
index f43f9b5..d799ad8 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
@@ -17,11 +17,40 @@
 
 package org.apache.ignite.internal.schema.marshaller;
 
+import com.squareup.javapoet.JavaFile;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
 import java.util.BitSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.UUID;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
 import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.schema.TupleAssembler;
 import org.apache.ignite.internal.util.ObjectFactory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static javax.tools.StandardLocation.CLASS_PATH;
 
 /**
  * Marshaller utility class.
@@ -97,7 +126,7 @@ public final class MarshallerUtil {
         return null;
     }
 
-    public static  <T> ObjectFactory<T> factoryForClass(Class<T> type) {
+    public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
         if (mode(type) == null)
             return new ObjectFactory<>(type);
         else
@@ -109,4 +138,212 @@ public final class MarshallerUtil {
      */
     private MarshallerUtil() {
     }
+
+    public static ClassLoader compileCode(JavaFile javafile) {
+        return compileCode(javafile, null);
+    }
+
+    public static ClassLoader compileCode(JavaFile javafile, Map<String, byte[]> classes) {
+        final JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();
+
+        final Map<String, byte[]> classes0 = classes == null ? new HashMap<>() : classes;
+
+        try (final MemoryJavaFileManager fileManager = new MemoryJavaFileManager(cmp.getStandardFileManager(null, null, null), classes0)) {
+            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
+
+            JavaCompiler.CompilationTask task = cmp.getTask(null, fileManager, diagnostics, null, null, Collections.singletonList(javafile.toJavaFileObject()));
+
+            final MemoryClassLoader loader = new MemoryClassLoader(fileManager.getClasses(), ClassLoader.getSystemClassLoader());
+
+            if (task.call())
+                return loader;
+
+            // TODO: write to log.
+            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
+                System.out.println(diagnostic.getCode());
+                System.out.println(diagnostic.getKind());
+                System.out.println(diagnostic.getPosition());
+                System.out.println(diagnostic.getStartPosition());
+                System.out.println(diagnostic.getEndPosition());
+                System.out.println(diagnostic.getSource());
+                System.out.println(diagnostic.getMessage(null));
+            }
+
+            throw new IllegalStateException("Failed to compile code:\n" + javafile.toString());
+        }
+        catch (IOException ex) {
+            throw new IllegalStateException("Failed to compile code.", ex);
+        }
+    }
+
+    private static class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+        private final Map<String, byte[]> classes;
+
+        public MemoryJavaFileManager(JavaFileManager fileManager, Map<String, byte[]> classes) {
+            super(fileManager);
+
+            this.classes = classes;
+        }
+
+        Map<String, byte[]> getClasses() {
+            return classes;
+        }
+
+        /**
+         * A file object that stores Java bytecode into the classBytes map.
+         */
+        private class ClassOutputBuffer extends SimpleJavaFileObject {
+            private final String classname;
+
+            ClassOutputBuffer(String classname) {
+                super(URI.create(classname), Kind.CLASS);
+                this.classname = classname;
+            }
+
+            @Override public OutputStream openOutputStream() {
+                return new ByteArrayOutputStream() {
+                    @Override public void close() throws IOException {
+                        super.close();
+
+                        classes.put(classname, toByteArray());
+                    }
+                };
+            }
+        }
+
+        @Override public ClassLoader getClassLoader(Location location) {
+            return new MemoryClassLoader(classes,  super.getClassLoader(location));
+        }
+        /*
+        @Override
+        public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds,
+            boolean recurse) throws IOException {
+            final Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse);
+
+            if (location == CLASS_PATH) {
+                assert kinds.contains(JavaFileObject.Kind.CLASS);
+
+                Iterable<JavaFileObject> localClasses = new Iterable<>() {
+                    @NotNull @Override public Iterator<JavaFileObject> iterator() {
+                        return classes.keySet().stream().map(cn -> getJavaFileObjectByName(cn)).iterator();
+                    }
+                };
+
+                return concat(localClasses, it);
+            }
+            else
+                return it;
+        }*/
+
+
+        @Override public boolean contains(Location location, FileObject fo) throws IOException {
+            return super.contains(location, fo);
+        }
+
+        @Override public JavaFileObject getJavaFileForInput(Location location, String className,
+            JavaFileObject.Kind kind) throws IOException {
+            if (location == StandardLocation.CLASS_OUTPUT) {
+                JavaFileObject javaFileObject = getJavaFileObjectByName(className);
+
+                if (javaFileObject != null)
+                    return javaFileObject;
+            }
+
+            return fileManager.getJavaFileForInput(location, className, kind);
+        }
+
+        @Nullable private JavaFileObject getJavaFileObjectByName(String className) {
+            final byte[] bytes = classes.get(className);
+
+            if (bytes != null) {
+                return new SimpleJavaFileObject(URI.create(className), JavaFileObject.Kind.OTHER) {
+                    @Override public InputStream openInputStream() {
+                        return new ByteArrayInputStream(bytes);
+                    }
+                };
+            }
+            return null;
+        }
+
+        @Override public JavaFileObject getJavaFileForOutput(Location location,
+            String className,
+            JavaFileObject.Kind kind,
+            FileObject sibling) throws IOException {
+            if (kind == JavaFileObject.Kind.CLASS)
+                return new ClassOutputBuffer(className);
+            else
+                return super.getJavaFileForOutput(location, className, kind, sibling);
+        }
+    }
+
+    private static final class MemoryClassLoader extends URLClassLoader {
+        private static final URL[] EMPTY_URLS = new URL[0];
+
+        private final Map<String, byte[]> classBytes;
+
+        public MemoryClassLoader(Map<String, byte[]> classBytes, ClassLoader parent) {
+            super(EMPTY_URLS, parent);
+
+            this.classBytes = classBytes;
+        }
+
+        @Override protected Class<?> findClass(String className) throws ClassNotFoundException {
+            byte[] buf = classBytes.get(className); // clear the bytes in map -- we don't need it anymore
+
+            if (buf != null)
+                return defineClass(className, buf, 0, buf.length);
+            else
+                return super.findClass(className);
+        }
+
+        @Override public Class<?> loadClass(String name) throws ClassNotFoundException {
+            return super.loadClass(name);
+        }
+    }
+
+    public static <E> Iterable<E> concat(
+        Iterable<? extends E> i1,
+        Iterable<? extends E> i2) {
+        return new Iterable<E>() {
+            @Override public Iterator<E> iterator() {
+                return new Iterator<E>() {
+                    Iterator<? extends E> listIterator = i1.iterator();
+                    Boolean checkedHasNext;
+                    E nextValue;
+                    private boolean startTheSecond;
+
+                    void theNext() {
+                        if (listIterator.hasNext()) {
+                            checkedHasNext = true;
+                            nextValue = listIterator.next();
+                        }
+                        else if (startTheSecond)
+                            checkedHasNext = false;
+                        else {
+                            startTheSecond = true;
+                            listIterator = i2.iterator();
+                            theNext();
+                        }
+                    }
+
+                    @Override public boolean hasNext() {
+                        if (checkedHasNext == null)
+                            theNext();
+                        return checkedHasNext;
+                    }
+
+                    @Override public E next() {
+                        if (!hasNext())
+                            throw new NoSuchElementException();
+                        checkedHasNext = null;
+                        return nextValue;
+                    }
+
+                    @Override public void remove() {
+                        listIterator.remove();
+                    }
+                };
+            }
+        };
+    }
 }
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
deleted file mode 100644
index fb3736a..0000000
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
+++ /dev/null
@@ -1,360 +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.generator;
-
-import org.apache.ignite.internal.schema.marshaller.BinaryMode;
-import org.jetbrains.annotations.Nullable;
-
-import static org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator.LF;
-
-/**
- * Object field access expression generators.
- */
-class FieldAccessExprGenerator {
-    /** Append null expression. */
-    private static final String WRITE_NULL_EXPR = "asm.appendNull();";
-
-    /**
-     * Created object access expressions generator.
-     *
-     * @param mode Field access binary mode.
-     * @param colIdx Column absolute index in schema.
-     * @return Object field access expressions generator.
-     */
-    static FieldAccessExprGenerator createIdentityAccessor(BinaryMode mode, int colIdx) {
-        return createAccessor(mode, colIdx, -1L);
-    }
-
-    /**
-     * Created object field access expressions generator.
-     *
-     * @param mode Field access binary mode.
-     * @param colIdx Column absolute index in schema.
-     * @param offset Object field offset.
-     * @return Object field access expressions generator.
-     */
-    static FieldAccessExprGenerator createAccessor(BinaryMode mode, int colIdx, long offset) {
-        switch (mode) {
-            case BYTE:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Byte",
-                    "tuple.byteValueBoxed",
-                    "asm.appendByte",
-                    offset);
-
-            case P_BYTE:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.byteValue",
-                    "asm.appendByte",
-                    offset,
-                    "IgniteUnsafeUtils.getByteField",
-                    "IgniteUnsafeUtils.putByteField"
-                );
-
-            case SHORT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Short",
-                    "tuple.shortValueBoxed",
-                    "asm.appendShort",
-                    offset);
-
-            case P_SHORT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.shortValue",
-                    "asm.appendShort",
-                    offset,
-                    "IgniteUnsafeUtils.getShortField",
-                    "IgniteUnsafeUtils.putShortField"
-                );
-
-            case INT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Integer",
-                    "tuple.intValueBoxed",
-                    "asm.appendInt",
-                    offset);
-
-            case P_INT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.intValue",
-                    "asm.appendInt",
-                    offset,
-                    "IgniteUnsafeUtils.getIntField",
-                    "IgniteUnsafeUtils.putIntField"
-                );
-
-            case LONG:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Long",
-                    "tuple.longValueBoxed",
-                    "asm.appendLong",
-                    offset);
-
-            case P_LONG:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.longValue",
-                    "asm.appendLong",
-                    offset,
-                    "IgniteUnsafeUtils.getLongField",
-                    "IgniteUnsafeUtils.putLongField"
-                );
-
-            case FLOAT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Float",
-                    "tuple.floatValueBoxed",
-                    "asm.appendFloat",
-                    offset);
-
-            case P_FLOAT:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.floatValue",
-                    "asm.appendFloat",
-                    offset,
-                    "IgniteUnsafeUtils.getFloatField",
-                    "IgniteUnsafeUtils.putFloatField"
-                );
-
-            case DOUBLE:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "Double",
-                    "tuple.doubleValueBoxed",
-                    "asm.appendDouble",
-                    offset);
-
-            case P_DOUBLE:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "tuple.doubleValue",
-                    "asm.appendDouble",
-                    offset,
-                    "IgniteUnsafeUtils.getDoubleField",
-                    "IgniteUnsafeUtils.putDoubleField"
-                );
-
-            case UUID:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "UUID",
-                    "tuple.uuidValue", "asm.appendUuid",
-                    offset);
-
-            case BITSET:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "BitSet",
-                    "tuple.bitmaskValue", "asm.appendBitmask",
-                    offset);
-
-            case STRING:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "String",
-                    "tuple.stringValue", "asm.appendString",
-                    offset);
-
-            case BYTE_ARR:
-                return new FieldAccessExprGenerator(
-                    colIdx,
-                    "byte[]",
-                    "tuple.bytesValue", "asm.appendBytes",
-                    offset);
-            default:
-                throw new IllegalStateException("Unsupportd binary mode");
-        }
-    }
-
-    /** Object field offset or {@code -1} for identity accessor. */
-    private final long offset;
-
-    /** Absolute schema index. */
-    private final int colIdx;
-
-    /** Class cast expression. */
-    private final String classExpr;
-
-    /** Write column value expression. */
-    private final String writeColMethod;
-
-    /** Read column value expression. */
-    private final String readColMethod;
-
-    /** Read object field expression. */
-    private final String getFieldMethod;
-
-    /** Write object field expression. */
-    private final String putFieldMethod;
-
-    /**
-     * Constructor.
-     *
-     * @param colIdx Absolute schema index in schema.
-     * @param castClassExpr Class cast expression
-     * @param readColMethod Read column value expression.
-     * @param writeColMethod Write column value expression.
-     * @param offset Field offset or {@code -1} for identity accessor.
-     */
-    private FieldAccessExprGenerator(
-        int colIdx,
-        String castClassExpr,
-        String readColMethod,
-        String writeColMethod,
-        long offset
-    ) {
-        this(colIdx, castClassExpr, readColMethod, writeColMethod, offset,
-            "IgniteUnsafeUtils.getObjectField", "IgniteUnsafeUtils.putObjectField");
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param colIdx Absolute schema index in schema.
-     * @param readColMethod Read column value expression.
-     * @param writeColMethod Write column value expression.
-     * @param offset Field offset or {@code -1} for identity accessor.
-     * @param getFieldMethod Read object field expression.
-     * @param putFieldMethod Read object field expression.
-     */
-    public FieldAccessExprGenerator(
-        int colIdx,
-        String readColMethod,
-        String writeColMethod,
-        long offset,
-        String getFieldMethod,
-        String putFieldMethod
-    ) {
-        this(colIdx, null /* primitive type */, readColMethod, writeColMethod, offset, getFieldMethod, putFieldMethod);
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param colIdx Absolute schema index in schema.
-     * @param castClassExpr Class cast expression or {@code null} if not applicable.
-     * @param readColMethod Read column value expression.
-     * @param writeColMethod Write column value expression.
-     * @param offset Field offset or {@code -1} for identity accessor.
-     * @param getFieldMethod Read object field expression.
-     * @param putFieldMethod Read object field expression.
-     */
-    private FieldAccessExprGenerator(
-        int colIdx,
-        @Nullable String castClassExpr,
-        String readColMethod,
-        String writeColMethod,
-        long offset,
-        String getFieldMethod,
-        String putFieldMethod
-    ) {
-        this.offset = offset;
-        this.colIdx = colIdx;
-        this.classExpr = castClassExpr;
-        this.putFieldMethod = putFieldMethod;
-        this.getFieldMethod = getFieldMethod;
-        this.writeColMethod = writeColMethod;
-        this.readColMethod = readColMethod;
-    }
-
-    /**
-     * @return {@code true} if it is primitive typed field accessor, {@code false} otherwise.
-     */
-    private boolean isPrimitive() {
-        return classExpr == null;
-    }
-
-    /**
-     * @return {@code true} if is identity accessor, {@code false} otherwise.
-     */
-    private boolean isIdentityAccessor() {
-        return offset == -1;
-    }
-
-    /**
-     * @return Object field value access expression or object value expression for simple types.
-     */
-    public String getFieldExpr() {
-        if (isIdentityAccessor())
-            return "obj"; // Identity accessor.
-
-        return getFieldMethod + "(obj, " + offset + ')';
-    }
-
-    /**
-     * Appends write value to field expression.
-     *
-     * @param sb String bulder.
-     * @param valueExpression Value expression.
-     * @param indent Line indentation.
-     */
-    public final void appendPutFieldExpr(StringBuilder sb, String valueExpression, String indent) {
-        sb.append(indent).append(putFieldMethod).append("(obj, ").append(offset).append(", ").append(valueExpression).append(')');
-        sb.append(";" + LF);
-    }
-
-    /**
-     * Appends write value to column expression.
-     *
-     * @param sb String bulder.
-     * @param valueExpr Value expression.
-     * @param indent Line indentation.
-     */
-    public final void appendWriteColumnExpr(StringBuilder sb, String valueExpr, String indent) {
-        if (isPrimitive() || isIdentityAccessor()) {
-            // Translate to:
-            // asm.appendX((T) %value%);
-            // or for primitive value:
-            // asm.appendX(%value%);
-            sb.append(indent).append(writeColMethod).append('(');
-
-            if (classExpr != null)
-                sb.append("(").append(classExpr).append(")");
-
-            sb.append(valueExpr).append(");" + LF);
-
-            return;
-        }
-
-        assert classExpr != null;
-
-        // Translate to:
-        // { T fVal = (T)%value%;
-        //  if (fVal == null) asm.appendNull() else asm.appendX(fVal); }
-        sb.append(indent).append("{ ").append(classExpr).append(" fVal = (").append(classExpr).append(')').append(valueExpr).append(";" + LF);
-        sb.append(indent).append("if (fVal == null) " + WRITE_NULL_EXPR + LF);
-        sb.append(indent).append("else ").append(writeColMethod).append("(fVal); }" + LF);
-
-    }
-
-    /**
-     * @return Column value read expression.
-     */
-    public String readColumnExpr() {
-        return readColMethod + "(" + colIdx + ")";
-    }
-}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
index f86bc0b..9d292c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.schema.marshaller.generator;
 
 import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeSpec;
 import org.apache.ignite.internal.schema.marshaller.Serializer;
 
 /**
@@ -27,37 +28,37 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator {
     /**
      * Constructor.
      *
-     * @param accessor Object field access expression generators.
-     * @param tupleAccessorGen
+     * @param aClass
+     * @param tupleAccessorGen Object field access expression generators.
      */
-    IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor,
-        TupleAccessorExpr tupleAccessorGen) {
-        super(
-            null /* no instantiation needed */,
-            new FieldAccessExprGenerator[] {accessor},
-            new TupleAccessorExpr[] {tupleAccessorGen}
-        );
-
+    IdentityObjectMarshallerExprGenerator(Class<?> aClass, TupleAccessorExpr tupleAccessorGen) {
+        super(aClass, null /* no instantiation needed */, new TupleAccessorExpr[] {tupleAccessorGen});
     }
 
     /** {@inheritDoc} */
-    @Override public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
-        for (int i = 0; i < accessors.length; i++)
-            accessors[i].appendWriteColumnExpr(sb, "obj", indent);
+    @Override boolean isSimpleType() {
+        return true;
     }
 
     /** {@inheritDoc} */
-    @Override public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
-        sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF);
-    }
-
     @Override public CodeBlock unmarshallObjectCode(String tupleExpr) {
         return CodeBlock.builder()
             .add("return ").addStatement(tupleAccessors[0].read(tupleExpr))
             .build();
     }
 
+    /** {@inheritDoc} */
     @Override public CodeBlock marshallObjectCode(String asm, String objVar) {
         return tupleAccessors[0].write(asm, objVar);
     }
+
+    /** {@inheritDoc} */
+    @Override public CodeBlock getValueCode(String objVar, int colIdx) {
+        return CodeBlock.of(objVar);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+
+    }
 }
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
index a45a8be..9de4011 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
@@ -24,15 +24,13 @@ import com.squareup.javapoet.JavaFile;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
-import java.lang.invoke.VarHandle;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
+import java.util.Map;
 import javax.annotation.processing.Generated;
 import javax.lang.model.element.Modifier;
-import javax.tools.JavaCompiler;
 import javax.tools.JavaFileManager;
-import javax.tools.ToolProvider;
 import org.apache.ignite.internal.schema.ByteBufferTuple;
 import org.apache.ignite.internal.schema.Columns;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
@@ -44,16 +42,9 @@ import org.apache.ignite.internal.schema.marshaller.SerializationException;
 import org.apache.ignite.internal.schema.marshaller.Serializer;
 import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
 import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
-import org.codehaus.janino.ClassLoaderIClassLoader;
-import org.codehaus.janino.Compiler;
-import org.codehaus.janino.util.ResourceFinderClassLoader;
-import org.codehaus.janino.util.resource.MapResourceCreator;
-import org.codehaus.janino.util.resource.MapResourceFinder;
-import org.codehaus.janino.util.resource.Resource;
-import org.codehaus.janino.util.resource.StringResource;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
 
 /**
  * {@link Serializer} code generator backed with Janino.
@@ -64,17 +55,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
 
     public static final String SERIALIZER_CLASS_NAME_PREFIX = "JaninoSerializerForSchema_";
 
-    /** Tabulate. */
-    static final String TAB = "    ";
-
-    /** Line feed. */
-    static final char LF = '\n';
-
-    /** String buffer initial size. */
-    public static final int INITIAL_BUFFER_SIZE = 8 * 1024;
-
-    /** Debug flag. */
-    private static final boolean enabledDebug = true;
+    private Map<String, byte[]> classes;
 
     /** {@inheritDoc} */
     @Override public Serializer create(
@@ -85,52 +66,31 @@ public class JaninoSerializerGenerator implements SerializerFactory {
         // Generate Serializer code.
         final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
 
-        String code = generateSerializerClassCode(className, schema, keyClass, valClass);
+        JavaFile javaFile = generateSerializerClassCode(className, schema, keyClass, valClass);
 
         //TODO: pass code to logger on trace level.
+        System.out.println(javaFile.toString());
 
-        final HashMap<String, byte[]> classes = new HashMap<>();
-        final Compiler cmp = new Compiler(
-            new MapResourceFinder(classes),
-            new ClassLoaderIClassLoader(getClass().getClassLoader())
-        );
-
-        cmp.setClassFileCreator(new MapResourceCreator(classes));
-
-        if (enabledDebug) {
-            cmp.setDebugSource(true);
-            cmp.setDebugLines(true);
-            cmp.setDebugVars(true);
-            cmp.setVerbose(true);
-
-            System.out.print(code);
-        }
-
-        try {  // Compile code.
-            cmp.compile(new Resource[] {
-                new StringResource("file", code)});
-
-            ClassLoader cl = new ResourceFinderClassLoader(
-                new MapResourceFinder(classes),
-                getClass().getClassLoader()
-            );
+        final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
 
-            // Load class and create instance.
-            final Class<?> aClass = cl.loadClass(SERIALIZER_PACKAGE_NAME + '.' + className);
+        try {
+            final Class<?> aClass = loader.loadClass(javaFile.packageName + '.' + className);
 
-            final Constructor<Serializer> ctor = (Constructor<Serializer>)aClass
-                .getDeclaredConstructor(schema.getClass(), Class.class, Class.class);
+            return (Serializer)aClass
+                .getDeclaredConstructor(SchemaDescriptor.class, Class.class, Class.class)
+                .newInstance(schema, keyClass, valClass);
 
-            return ctor.newInstance(schema, keyClass, valClass);
         }
-        catch (Throwable ex) {
-            if (enabledDebug)
-                throw new IllegalStateException("Failed to compile generated Serializer code:\n" + code, ex);
-            else
-                throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+        catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            throw new IllegalStateException(e);
         }
     }
 
+    @TestOnly
+    public void setClasses(Map<String, byte[]> classes) {
+        this.classes = classes;
+    }
+
     /**
      * Generates serializer code.
      *
@@ -138,50 +98,46 @@ public class JaninoSerializerGenerator implements SerializerFactory {
      * @param valClass Value class.
      * @return Generated class code.
      */
-    private String generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
+    private JavaFile generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
         Class<?> valClass) {
         try {
-            final StringBuilder sb = new StringBuilder();
-
             // Build field accessor generators.
-            final MarshallerExprGenerator keyMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-            final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
-            JavaFile
-                .builder(
-                    SERIALIZER_PACKAGE_NAME,
-                    TypeSpec.classBuilder(className)
-                        .addSuperinterface(Serializer.class)
+            final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
+            final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.valueColumns().length());
+
+            final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className)
+                .addSuperinterface(Serializer.class)
+                .addModifiers(Modifier.PUBLIC)
+                .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", "$S", getClass().getCanonicalName()).build());
+
+            initFieldHandlers(keyMarsh, valMarsh, classBuilder);
+
+            classBuilder.addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
+                .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
+                .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
+                .addMethod(
+                    MethodSpec.constructorBuilder()
                         .addModifiers(Modifier.PUBLIC)
-                        .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", getClass().getCanonicalName()).build())
-                        .addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
-                        .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
-                        .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
-                        .addField(ArrayTypeName.of(VarHandle.class), "fieldAccessors", Modifier.PRIVATE, Modifier.FINAL)
-                        .addMethod(
-                            MethodSpec.constructorBuilder()
-                                .addModifiers(Modifier.PUBLIC)
-                                .addParameter(SchemaDescriptor.class, "schema")
-                                .addParameter(Class.class, "keyClass")
-                                .addParameter(Class.class, "valClass")
-                                .addStatement("this.schema = schema")
-                                .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
-                                .addStatement("this.valFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
-                                .addStatement("this.fieldAccessors = null")
-                                .build()
-                        )
-                        .addMethod(generateHelpersMetod(schema))
-                        .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
-                        .addMethod(generateDeserializeKeyMethod(keyMarsh))
-                        .addMethod(generateDeserializeValueMethod())
+                        .addParameter(SchemaDescriptor.class, "schema")
+                        .addParameter(Class.class, "keyClass")
+                        .addParameter(Class.class, "valClass")
+                        .addStatement("this.schema = schema")
+                        .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
+                        .addStatement("this.valFactory = $T.factoryForClass(valClass)", MarshallerUtil.class)
                         .build()
                 )
+                .addMethod(generateHelpersMetod(schema, keyMarsh, valMarsh))
+                .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
+                .addMethod(generateDeserializeKeyMethod(keyMarsh))
+                .addMethod(generateDeserializeValueMethod(valMarsh));
+
+            return JavaFile
+                .builder(SERIALIZER_PACKAGE_NAME, classBuilder.build())
+                .addStaticImport(TupleAccessorExpr.class, "*")
+                .addStaticImport(MethodHandles.class, "Lookup")
                 .skipJavaLangImports(true)
-                .indent(TAB)
-                .build()
-                .writeTo(sb);
-
-            return sb.toString();
+                .indent("    ")
+                .build();
         }
         catch (Exception ex) {
             //TODO: fallback to java serializer?
@@ -189,7 +145,33 @@ public class JaninoSerializerGenerator implements SerializerFactory {
         }
     }
 
-    private MethodSpec generateHelpersMetod(SchemaDescriptor schema) {
+    private void initFieldHandlers(MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh,
+        TypeSpec.Builder classBuilder) {
+        if (keyMarsh.isSimpleType() && valMarsh.isSimpleType())
+            return;
+
+        final CodeBlock.Builder staticInitBuilder = CodeBlock.builder()
+            .addStatement("$T.Lookup lookup", MethodHandles.class)
+            .beginControlFlow("try");
+
+        if (!keyMarsh.isSimpleType()) {
+            staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, keyMarsh.getClazz(), MethodHandles.class);
+            keyMarsh.staticHandlers(classBuilder, staticInitBuilder);
+        }
+
+        if (!valMarsh.isSimpleType()) {
+            staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, valMarsh.getClazz(), MethodHandles.class);
+            valMarsh.staticHandlers(classBuilder, staticInitBuilder);
+        }
+
+        staticInitBuilder.nextControlFlow("catch ($T | $T ex)", ReflectiveOperationException.class, SecurityException.class)
+            .addStatement("throw new $T(ex)", IllegalStateException.class)
+            .endControlFlow();
+
+        classBuilder.addStaticBlock(staticInitBuilder.build());
+    }
+
+    private MethodSpec generateHelpersMetod(SchemaDescriptor schema, MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh) {
         final MethodSpec.Builder builder = MethodSpec
             .methodBuilder("createAssembler")
             .addModifiers(Modifier.PRIVATE)
@@ -210,9 +192,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
             for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
                 assert !keyCols.column(i).type().spec().fixedLength();
 
-                block.addStatement("assert !keyCols.column($L).type().spec().fixedLength()", i)
-                    .addStatement("fVal = fieldAccessors[$L].get(key)", i)
-                    .beginControlFlow("if (fVal != null)")
+                block.addStatement("fVal = $L", keyMarsh.getValueCode("key", i).toString());
+
+                block.beginControlFlow("if (fVal != null)")
                     .addStatement("nonNullVarlenKeysSize += $T.getValueSize(fVal, keyCols.column($L).type())", MarshallerUtil.class, i)
                     .addStatement("nonNullVarlenKeys++")
                     .endControlFlow();
@@ -225,7 +207,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
                 .addCode("}\n");
         }
 
-        Columns valCols = schema.keyColumns();
+        Columns valCols = schema.valueColumns();
         if (valCols.firstVarlengthColumn() >= 0) {
             final CodeBlock.Builder block = CodeBlock.builder().indent()
                 .addStatement("$T fVal", Object.class);// Temporary vars.
@@ -233,9 +215,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
             for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
                 assert !valCols.column(i).type().spec().fixedLength();
 
-                block.addStatement("assert !valCols.column($L).type().spec().fixedLength()", i)
-                    .addStatement("fVal = fieldAccessors[$L].get(val)", i + schema.keyColumns().length())
-                    .beginControlFlow("if (fVal != null)")
+                block.addStatement("fVal = $L", valMarsh.getValueCode("val", i).toString());
+
+                block.beginControlFlow("if (fVal != null)")
                     .addStatement("nonNullVarlenValuesSize += $T.getValueSize(fVal, valCols.column($L).type())", MarshallerUtil.class, i)
                     .addStatement("nonNullVarlenValues++")
                     .endControlFlow();
@@ -256,7 +238,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
         return builder.build();
     }
 
-    @NotNull private MethodSpec generateDeserializeValueMethod() {
+    @NotNull private MethodSpec generateDeserializeValueMethod(MarshallerExprGenerator valMarsh) {
         return MethodSpec
             .methodBuilder("deserializeValue")
             .addAnnotation(Override.class)
@@ -264,12 +246,18 @@ public class JaninoSerializerGenerator implements SerializerFactory {
             .addParameter(ArrayTypeName.of(TypeName.BYTE), "data")
             .addException(SerializationException.class)
             .returns(TypeName.OBJECT)
-            .addStatement("return null")
-            .build();
+
+            .beginControlFlow("try")
+            .addStatement("$T tuple = new $T(schema, data)", Tuple.class, ByteBufferTuple.class)
+            .addCode(valMarsh.unmarshallObjectCode("tuple"))
+
+            .nextControlFlow("catch($T th)", Throwable.class)
+            .addStatement("throw new $T(th)", SerializationException.class)
+            .endControlFlow().build();
     }
 
     @NotNull private MethodSpec generateDeserializeKeyMethod(MarshallerExprGenerator keyMarsh) {
-        final MethodSpec.Builder builder = MethodSpec
+        return MethodSpec
             .methodBuilder("deserializeKey")
             .addAnnotation(Override.class)
             .addModifiers(Modifier.PUBLIC)
@@ -283,9 +271,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
 
             .nextControlFlow("catch($T th)", Throwable.class)
             .addStatement("throw new $T(th)", SerializationException.class)
-            .endControlFlow();
-
-        return builder.build();
+            .endControlFlow().build();
     }
 
     @NotNull
@@ -297,7 +283,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
             .addParameter(TypeName.OBJECT, "key")
             .addParameter(TypeName.OBJECT, "val")
             .addException(SerializationException.class)
-            .returns(ArrayTypeName.of(TypeName.BYTE.unbox()))
+            .returns(ArrayTypeName.of(TypeName.BYTE))
 
             .beginControlFlow("try")
             .addStatement("$T asm = createAssembler(key, val)", TupleAssembler.class)
@@ -312,74 +298,6 @@ public class JaninoSerializerGenerator implements SerializerFactory {
     }
 
     /**
-     * Generates serializer code.
-     *
-     * @param ce Class body evaluator.
-     * @param schema Schema descriptor.
-     * @param keyClass Key class.
-     * @param valClass Value class.
-     * @return Generated class code.
-     */
-    private String generateSerializerClassCode(
-        IClassBodyEvaluator ce,
-        SchemaDescriptor schema,
-        Class<?> keyClass,
-        Class<?> valClass
-    ) {
-        final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
-
-        // Prerequisites.
-        ce.setClassName(SERIALIZER_PACKAGE_NAME + className);
-        ce.setImplementedInterfaces(new Class[] {Serializer.class});
-        ce.setDefaultImports(
-            "java.util.UUID",
-            "java.util.BitSet",
-
-            "org.apache.ignite.internal.schema.ByteBufferTuple",
-            "org.apache.ignite.internal.schema.Columns",
-            "org.apache.ignite.internal.schema.SchemaDescriptor",
-            "org.apache.ignite.internal.schema.Tuple",
-            "org.apache.ignite.internal.schema.TupleAssembler",
-            "org.apache.ignite.internal.util.IgniteUnsafeUtils",
-            "org.apache.ignite.internal.util.ObjectFactory"
-        );
-
-        // Build field accessor generators.
-        final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
-        final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
-        // Create buffer.
-        final StringBuilder sb = new StringBuilder(INITIAL_BUFFER_SIZE);
-
-        // Append class fields desctiption.
-        sb.append("private final SchemaDescriptor schema;" + LF);
-
-        if (!keyMarsh.isSimpleTypeMarshaller())
-            sb.append("private final ObjectFactory keyFactory;" + LF);
-        if (!valMarsh.isSimpleTypeMarshaller())
-            sb.append("private final ObjectFactory valFactory;" + LF);
-
-        // Append constructor code.
-        sb.append(LF + "public ").append(className).append("(SchemaDescriptor schema, Class kClass, Class vClass) {" + LF);
-        sb.append(TAB + "this.schema = schema; " + LF);
-        if (!keyMarsh.isSimpleTypeMarshaller())
-            sb.append(TAB + "keyFactory = new ObjectFactory(kClass);" + LF);
-        if (!valMarsh.isSimpleTypeMarshaller())
-            sb.append(TAB + "valFactory = new ObjectFactory(vClass);" + LF);
-        sb.append("}" + LF);
-
-        // Generate and append helper-methods.
-        generateTupleFactoryMethod(sb, schema, keyMarsh, valMarsh);
-
-        // Generate and append Serializer interface methods.
-        appendSerializeMethod(sb, keyMarsh, valMarsh);
-        writeDeserializeKeyMethod(sb, keyMarsh);
-        writeDeserializeValueMethod(sb, valMarsh);
-
-        return sb.toString();
-    }
-
-    /**
      * Creates marshal/unmarshall expressions generator for object.
      *
      * @param aClass Object class.
@@ -397,173 +315,8 @@ public class JaninoSerializerGenerator implements SerializerFactory {
         BinaryMode mode = MarshallerUtil.mode(aClass);
 
         if (mode != null)
-            return new IdentityObjectMarshallerExprGenerator(
-                FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx),
-                TupleAccessorExpr.createAccessor(mode, firstColIdx)
-            );
-
-        FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()];
-        TupleAccessorExpr[] tupleAccessorExprs = new TupleAccessorExpr[] {};
-        try {
-            for (int i = 0; i < columns.length(); i++) {
-                final Field field = aClass.getDeclaredField(columns.column(i).name());
-
-                accessors[i] = FieldAccessExprGenerator.createAccessor(
-                    MarshallerUtil.mode(field.getType()),
-                    firstColIdx + i /* schma absolute index. */,
-                    0L);//   IgniteUnsafeUtils.objectFieldOffset(field));
-            }
-        }
-        catch (NoSuchFieldException ex) {
-            throw new IllegalStateException(ex);
-        }
-
-        return new MarshallerExprGenerator(factoryRefExpr, accessors, tupleAccessorExprs);
-    }
-
-    /**
-     * Appends {@link Serializer#serialize(Object, Object)} method code.
-     *
-     * @param sb String buffer to append to.
-     * @param keyMarsh Marshall expression generator for key.
-     * @param valMarsh Marshall expression generator for value.
-     */
-    private void appendSerializeMethod(
-        StringBuilder sb,
-        MarshallerExprGenerator keyMarsh,
-        MarshallerExprGenerator valMarsh
-    ) {
-        // Mehtod signature.
-        sb.append(LF + "@Override public byte[] serialize(Object key, Object val) throws SerializationException {" + LF);
-        sb.append(TAB + "TupleAssembler asm = createAssembler(key, val);" + LF);
-
-        // Key marshal script.
-        sb.append(TAB + "{" + LF);
-        sb.append(TAB + TAB + "Object obj = key;" + LF);
-        keyMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
-        sb.append(TAB + "}" + LF);
-
-        // Value marshal script.
-        sb.append(TAB + " {" + LF);
-        sb.append(TAB + TAB + "Object obj = val;" + LF);
-        valMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
-        sb.append(TAB + "}" + LF);
-
-        // Return statement.
-        sb.append(TAB + "return asm.build();" + LF);
-        sb.append("}" + LF);
-    }
-
-    /**
-     * Appends {@link Serializer#deserializeKey(byte[])} method code.
-     *
-     * @param sb String buffer to append to.
-     * @param keyMarsh Unmarshall expression generator for key.
-     */
-    private void writeDeserializeKeyMethod(StringBuilder sb, MarshallerExprGenerator keyMarsh) {
-        // Mehtod signature.
-        sb.append(LF + "@Override public Object deserializeKey(byte[] data) throws SerializationException {" + LF);
-        sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
-        // Key unmarshal script.
-        keyMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
-        // Return statement.
-        sb.append(TAB + "return obj;" + LF);
-        sb.append("}" + LF);
-    }
-
-    /**
-     * Appends {@link Serializer#deserializeValue(byte[])} method code.
-     *
-     * @param sb String buffer to append to.
-     * @param valMarsh Unmarshall expression generator for value.
-     */
-    private void writeDeserializeValueMethod(StringBuilder sb, MarshallerExprGenerator valMarsh) {
-        // Mehtod signature.
-        sb.append(LF + "@Override public Object deserializeValue(byte[] data) throws SerializationException {" + LF);
-        sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
-        // Key unmarshal script.
-        valMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
-        // Return statement.
-        sb.append(TAB + "return obj;" + LF);
-        sb.append("}" + LF);
-    }
-
-    /**
-     * Appends helper methods code.
-     *
-     * @param sb String buffer to append to.
-     * @param schema Schema descriptor.
-     * @param keyMarsh Marshall expression generator for key.
-     * @param valMarsh Marshall expression generator for value.
-     */
-    private void generateTupleFactoryMethod(
-        StringBuilder sb,
-        SchemaDescriptor schema,
-        MarshallerExprGenerator keyMarsh,
-        MarshallerExprGenerator valMarsh
-    ) {
-        // Method signature.
-        sb.append(LF + "TupleAssembler createAssembler(Object key, Object val) {" + LF);
-        // Local variables.
-        sb.append(TAB + "int nonNullVarlenKeys = 0; int nonNullVarlenValues = 0;" + LF);
-        sb.append(TAB + "int nonNullVarlenKeysSize = 0; int nonNullVarlenValuesSize = 0;" + LF);
-        sb.append(LF);
-        sb.append(TAB + "Columns keyCols = schema.keyColumns();" + LF);
-        sb.append(TAB + "Columns valCols = schema.valueColumns();" + LF);
-        sb.append(LF);
-
-        Columns keyCols = schema.keyColumns();
-        if (keyCols.firstVarlengthColumn() >= 0) {
-            // Appends key analyzer code-block.
-            sb.append(TAB + "{" + LF);
-            sb.append(TAB + TAB + "Object fVal, obj = key;" + LF); // Temporary vars.
-
-            for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
-                assert !keyCols.column(i).type().spec().fixedLength();
-
-                sb.append(TAB + TAB + "assert !keyCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
-                sb.append(TAB + TAB + "fVal = ").append(keyMarsh.accessors[i].getFieldExpr()).append(";" + LF);
-                sb.append(TAB + TAB + "if (fVal != null) {" + LF);
-                sb.append(TAB + TAB + TAB + "nonNullVarlenKeysSize += MarshallerUtil.getValueSize(fVal, keyCols.column(").append(i).append(").type());").append(LF);
-                sb.append(TAB + TAB + TAB + "nonNullVarlenKeys++;" + LF);
-                sb.append(TAB + TAB + "}" + LF);
-            }
-
-            sb.append(TAB + "}" + LF);
-        }
-
-        Columns valCols = schema.valueColumns();
-        if (valCols.firstVarlengthColumn() >= 0) {
-            // Appends value analyzer code-block.
-            sb.append(TAB + "{" + LF);
-            sb.append(TAB + TAB + "Object fVal, obj = val;" + LF); // Temporary vars.
-
-            for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
-                assert !valCols.column(i).type().spec().fixedLength();
-
-                sb.append(TAB + TAB + "assert !valCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
-                sb.append(TAB + TAB + "fVal = ").append(valMarsh.accessors[i].getFieldExpr()).append(";" + LF);
-                sb.append(TAB + TAB + "if (fVal != null) {" + LF);
-                sb.append(TAB + TAB + TAB + "nonNullVarlenValuesSize += MarshallerUtil.getValueSize(fVal, valCols.column(").append(i).append(").type());" + LF);
-                sb.append(TAB + TAB + TAB + "nonNullVarlenValues++;" + LF);
-                sb.append(TAB + TAB + "}" + LF);
-            }
-            sb.append(TAB + "}" + LF);
-        }
-
-        // Calculate tuple size.
-        sb.append(LF);
-        sb.append(TAB + "int size = TupleAssembler.tupleSize(" + LF);
-        sb.append(TAB + TAB + "keyCols, nonNullVarlenKeys, nonNullVarlenKeysSize, " + LF);
-        sb.append(TAB + TAB + "valCols, nonNullVarlenValues, nonNullVarlenValuesSize); " + LF);
-        sb.append(LF);
-
-        // Return statement.
-        sb.append(TAB + "return new TupleAssembler(schema, size, nonNullVarlenKeys, nonNullVarlenValues);" + LF);
-        sb.append("}" + LF);
+            return new IdentityObjectMarshallerExprGenerator(aClass, TupleAccessorExpr.createAccessor(mode, firstColIdx));
+        else
+            return new MarshallerExprGenerator(aClass, factoryRefExpr, columns, firstColIdx);
     }
 }
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
index 8087e2c..53be5ed 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
@@ -18,7 +18,13 @@
 package org.apache.ignite.internal.schema.marshaller.generator;
 
 import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeSpec;
 import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import javax.lang.model.element.Modifier;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
 import org.apache.ignite.internal.schema.marshaller.Serializer;
 
 /**
@@ -28,93 +34,91 @@ class MarshallerExprGenerator {
     /** Object factory regerence expression. */
     private final String factoryRefExpr;
 
+    private final Class<?> tClass;
+
+    private final Columns columns;
+
     /** Object field access expression generators. */
-    protected FieldAccessExprGenerator[] accessors;
     protected TupleAccessorExpr[] tupleAccessors;
 
     /**
      * Constructor.
      *
+     * @param tClass
      * @param factoryRefExpr Object factory regerence expression.
-     * @param accessors Object field access expression generators.
      */
-    public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors,
-        TupleAccessorExpr[] tupleAccessors) {
-        this.accessors = accessors;
+    public MarshallerExprGenerator(Class<?> tClass, String factoryRefExpr, Columns columns, int firstColIdx) {
         this.factoryRefExpr = factoryRefExpr;
-        this.tupleAccessors = tupleAccessors;
+        this.tClass = tClass;
+
+        this.columns = columns;
+        tupleAccessors = new TupleAccessorExpr[this.columns.length()];
+        try {
+            for (int i = 0; i < columns.length(); i++) {
+                final Field field = tClass.getDeclaredField(columns.column(i).name());
+
+                tupleAccessors[i] = TupleAccessorExpr.createAccessor(MarshallerUtil.mode(field.getType()), i + firstColIdx);
+            }
+        }
+        catch (NoSuchFieldException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
-    /**
-     * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
-     */
-    boolean isSimpleTypeMarshaller() {
-        return factoryRefExpr == null;
+    public MarshallerExprGenerator(Class<?> tClass, Object expr, TupleAccessorExpr[] tupleAccessorExprs) {
+        this.factoryRefExpr = null;
+        this.tClass = tClass;
+        columns = null;
+        this.tupleAccessors = tupleAccessorExprs;
     }
 
     /**
-     * Appends unmashall object code to string builder.
-     *
-     * @param sb String builder.
-     * @param indent Line indentation.
+     * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
      */
-    public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
-        assert factoryRefExpr != null;
-
-        sb.append(indent).append("Object obj;" + JaninoSerializerGenerator.LF);
-        // Try.
-        sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
-        sb.append(indent).append(JaninoSerializerGenerator.TAB + "obj = ").append(factoryRefExpr).append(".create();" + JaninoSerializerGenerator.LF);
-
-        // Read column from tuple to object field.
-        for (int i = 0; i < accessors.length; i++)
-            accessors[i].appendPutFieldExpr(sb, accessors[i].readColumnExpr(), indent + JaninoSerializerGenerator.TAB);
-
-        // Catch and rethrow wrapped exeption.
-        sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
-        sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(\"Failed to instantiate object: \" + ")
-            .append(factoryRefExpr).append(".getClazz().getName(), ex);").append(JaninoSerializerGenerator.LF);
-        sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+    boolean isSimpleType() {
+        return false;
     }
 
-    /**
-     * Appends mashall object code to string builder.
-     *
-     * @param sb String builder.
-     * @param indent Line indentation.
-     */
-    public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
-        // Try.
-        sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
-
-        // Write object field to tuple assembler.
-        for (int i = 0; i < accessors.length; i++)
-            accessors[i].appendWriteColumnExpr(sb, accessors[i].getFieldExpr(), indent + JaninoSerializerGenerator.TAB);
-
-        // Catch and rethrow wrapped exeption.
-        sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
-        sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(ex);").append(JaninoSerializerGenerator.LF);
-        sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+    Class<?> getClazz() {
+        return tClass;
     }
 
     public CodeBlock unmarshallObjectCode(String tupleExpr) {
         final CodeBlock.Builder builder = CodeBlock.builder()
             .add("Object obj = ").add(factoryRefExpr).addStatement(".create()");
 
-        for (int i = 0; i < tupleAccessors.length; i++) {
-            builder.addStatement("fieldAccessor[$L].set(obj, $L)", i, tupleAccessors[i].read(tupleExpr).toString());
-        }
+        for (int i = 0; i < tupleAccessors.length; i++)
+            builder.addStatement("FIELD_HANDLE_$L.set(obj, $L)", tupleAccessors[i].colIdx, tupleAccessors[i].read(tupleExpr).toString());
 
-            builder.addStatement("return obj");
+        builder.addStatement("return obj");
         return builder.build();
     }
 
+    public CodeBlock getValueCode(String objVar, int i) {
+        return CodeBlock.of("FIELD_HANDLE_$L.get($L)", tupleAccessors[i].colIdx, objVar);
+    }
+
     public CodeBlock marshallObjectCode(String asm, String objVar) {
         final CodeBlock.Builder builder = CodeBlock.builder();
 
         for (int i = 0; i < tupleAccessors.length; i++)
-            builder.addStatement(tupleAccessors[i].write(asm, CodeBlock.of("fieldAccessor[$L].get($L)", i, objVar).toString()));
+            builder.addStatement(tupleAccessors[i].write(asm, getValueCode(objVar, i).toString()).toString());
 
         return builder.build();
     }
+
+    public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+        for (int i = 0; i < tupleAccessors.length; i++) {
+            builder.addField(FieldSpec.builder(
+                VarHandle.class,
+                CodeBlock.of("FIELD_HANDLE_$L", tupleAccessors[i].colIdx).toString(),
+                Modifier.PRIVATE,
+                Modifier.FINAL,
+                Modifier.STATIC)
+                .build());
+
+            staticBuilder.addStatement("FIELD_HANDLE_$L = lookup.unreflectVarHandle($T.class.getDeclaredField($S))",
+                tupleAccessors[i].colIdx, tClass, columns.column(i).name());
+        }
+    }
 }
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
index e1b782d..ccca864 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
@@ -21,6 +21,8 @@ import com.squareup.javapoet.CodeBlock;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.BitSet;
+import java.util.UUID;
 import org.apache.ignite.internal.schema.Tuple;
 import org.apache.ignite.internal.schema.TupleAssembler;
 import org.apache.ignite.internal.schema.marshaller.BinaryMode;
@@ -29,52 +31,68 @@ import org.apache.ignite.internal.schema.marshaller.BinaryMode;
  * Object field access expression generators.
  */
 public class TupleAccessorExpr {
-    public static final MethodHandle BYTE_READ;
-    public static final MethodHandle SHORT_READ;
-    public static final MethodHandle INT_READ;
-    public static final MethodHandle LONG_READ;
-    public static final MethodHandle FLOAT_READ;
-    public static final MethodHandle DOUBLE_READ;
-    public static final MethodHandle BYTE_BOXED_READ;
-    public static final MethodHandle SHORT_BOXED_READ;
-    public static final MethodHandle INT_BOXED_READ;
-    public static final MethodHandle LONG_BOXED_READ;
-    public static final MethodHandle FLOAT_BOXED_READ;
-    public static final MethodHandle DOUBLE_BOXED_READ;
+    public static final MethodHandle READ_BYTE;
+    public static final MethodHandle READ_SHORT;
+    public static final MethodHandle READ_INT;
+    public static final MethodHandle READ_LONG;
+    public static final MethodHandle READ_FLOAT;
+    public static final MethodHandle READ_DOUBLE;
+    public static final MethodHandle READ_BYTE_BOXED;
+    public static final MethodHandle READ_SHORT_BOXED;
+    public static final MethodHandle READ_INT_BOXED;
+    public static final MethodHandle READ_LONG_BOXED;
+    public static final MethodHandle READ_FLOAT_BOXED;
+    public static final MethodHandle READ_DOUBLE_BOXED;
+    public static final MethodHandle READ_UUID;
+    public static final MethodHandle READ_BITSET;
+    public static final MethodHandle READ_STRING;
+    public static final MethodHandle READ_BYTE_ARR;
 
-    public static final MethodHandle BYTE_WRITE;
-    public static final MethodHandle SHORT_WRITE;
-    public static final MethodHandle INT_WRITE;
-    public static final MethodHandle LONG_WRITE;
-    public static final MethodHandle FLOAT_WRITE;
-    public static final MethodHandle DOUBLE_WRITE;
-    public static final MethodHandle NULL_WRITE;
+    public static final MethodHandle WRITE_NULL;
+    public static final MethodHandle WRITE_BYTE;
+    public static final MethodHandle WRITE_SHORT;
+    public static final MethodHandle WRITE_INT;
+    public static final MethodHandle WRITE_LONG;
+    public static final MethodHandle WRITE_FLOAT;
+    public static final MethodHandle WRITE_DOUBLE;
+    public static final MethodHandle WRITE_UUID;
+    public static final MethodHandle WRITE_BITSET;
+    public static final MethodHandle WRITE_STRING;
+    public static final MethodHandle WRITE_BYTE_ARR;
 
     static {
         try {
-            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class,MethodHandles.lookup());
+            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class, MethodHandles.lookup());
 
-            BYTE_READ = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
-            SHORT_READ = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
-            INT_READ = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
-            LONG_READ = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
-            FLOAT_READ = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
-            DOUBLE_READ = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
-            BYTE_BOXED_READ = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
-            SHORT_BOXED_READ = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
-            INT_BOXED_READ = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
-            LONG_BOXED_READ = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
-            FLOAT_BOXED_READ = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
-            DOUBLE_BOXED_READ = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+            READ_BYTE = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
+            READ_SHORT = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
+            READ_INT = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
+            READ_LONG = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
+            READ_FLOAT = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
+            READ_DOUBLE = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
+            READ_BYTE_BOXED = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
+            READ_SHORT_BOXED = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
+            READ_INT_BOXED = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
+            READ_LONG_BOXED = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
+            READ_FLOAT_BOXED = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
+            READ_DOUBLE_BOXED = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+            READ_UUID = lookup.findVirtual(Tuple.class, "uuidValue", MethodType.methodType(UUID.class, int.class));
+            READ_BITSET = lookup.findVirtual(Tuple.class, "bitmaskValue", MethodType.methodType(BitSet.class, int.class));
+            READ_STRING = lookup.findVirtual(Tuple.class, "stringValue", MethodType.methodType(String.class, int.class));
+            READ_BYTE_ARR = lookup.findVirtual(Tuple.class, "bytesValue", MethodType.methodType(byte[].class, int.class));
 
-            lookup = MethodHandles.privateLookupIn(TupleAssembler.class,MethodHandles.lookup());
-            NULL_WRITE = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
-            BYTE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
-            SHORT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
-            INT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
-            LONG_WRITE = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
-            FLOAT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
-            DOUBLE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+            lookup = MethodHandles.privateLookupIn(TupleAssembler.class, MethodHandles.lookup());
+            WRITE_NULL = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
+            WRITE_BYTE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
+            WRITE_SHORT = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
+            WRITE_INT = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
+            WRITE_LONG = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
+            WRITE_FLOAT = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
+            WRITE_DOUBLE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+            WRITE_UUID = lookup.findVirtual(TupleAssembler.class, "appendUuid", MethodType.methodType(void.class, UUID.class));
+            WRITE_BITSET = lookup.findVirtual(TupleAssembler.class, "appendBitmask", MethodType.methodType(void.class, BitSet.class));
+            WRITE_STRING = lookup.findVirtual(TupleAssembler.class, "appendString", MethodType.methodType(void.class, String.class));
+            WRITE_BYTE_ARR = lookup.findVirtual(TupleAssembler.class, "appendBytes", MethodType.methodType(void.class, byte[].class));
         }
         catch (NoSuchMethodException | IllegalAccessException e) {
             throw new IllegalStateException(e);
@@ -87,37 +105,37 @@ public class TupleAccessorExpr {
     static TupleAccessorExpr createAccessor(BinaryMode mode, int colIdx) {
         switch (mode) {
             case P_BYTE:
-                return new TupleAccessorExpr("BYTE_READ", "BYTE_WRITE", byte.class, colIdx);
+                return new TupleAccessorExpr("READ_BYTE", "WRITE_BYTE", byte.class, colIdx);
             case P_SHORT:
-                break;
+                return new TupleAccessorExpr("READ_SHORT", "WRITE_SHORT", short.class, colIdx);
             case P_INT:
-                break;
+                return new TupleAccessorExpr("READ_INT", "WRITE_INT", int.class, colIdx);
             case P_LONG:
-                break;
+                return new TupleAccessorExpr("READ_LONG", "WRITE_LONG", long.class, colIdx);
             case P_FLOAT:
-                break;
+                return new TupleAccessorExpr("READ_FLOAT", "WRITE_FLOAT", float.class, colIdx);
             case P_DOUBLE:
-                break;
+                return new TupleAccessorExpr("READ_DOUBLE", "WRITE_DOUBLE", double.class, colIdx);
             case BYTE:
-                return new TupleAccessorExpr("BYTE_BOXED_READ", "BYTE_WRITE", Byte.class, colIdx);
+                return new TupleAccessorExpr("READ_BYTE_BOXED", "WRITE_BYTE", Byte.class, colIdx);
             case SHORT:
-                break;
+                return new TupleAccessorExpr("READ_SHORT_BOXED", "WRITE_SHORT", Short.class, colIdx);
             case INT:
-                break;
+                return new TupleAccessorExpr("READ_INT_BOXED", "WRITE_INT", Integer.class, colIdx);
             case LONG:
-                break;
+                return new TupleAccessorExpr("READ_LONG_BOXED", "WRITE_LONG", Long.class, colIdx);
             case FLOAT:
-                break;
+                return new TupleAccessorExpr("READ_FLOAT_BOXED", "WRITE_FLOAT", Float.class, colIdx);
             case DOUBLE:
-                break;
+                return new TupleAccessorExpr("READ_DOUBLE_BOXED", "WRITE_DOUBLE", Double.class, colIdx);
             case STRING:
-                break;
+                return new TupleAccessorExpr("READ_STRING", "WRITE_STRING", String.class, colIdx);
             case UUID:
-                break;
+                return new TupleAccessorExpr("READ_UUID", "WRITE_UUID", UUID.class, colIdx);
             case BYTE_ARR:
-                break;
+                return new TupleAccessorExpr("READ_BYTE_ARR", "WRITE_BYTE_ARR", byte[].class, colIdx);
             case BITSET:
-                break;
+                return new TupleAccessorExpr("READ_BITSET", "WRITE_BITSET", BitSet.class, colIdx);
         }
 
         throw new IllegalStateException("Unsupported binary mode: " + mode);
@@ -125,7 +143,7 @@ public class TupleAccessorExpr {
 
     private final String readExpr;
     private final String writeExpr;
-    private final int colIdx;
+    final int colIdx;
 
     private TupleAccessorExpr(String readExpr, String writeExpr, Class<?> rType, int colIdx) {
         this.readExpr = readExpr;
@@ -146,7 +164,7 @@ public class TupleAccessorExpr {
                 .add("{\n").indent()
                 .addStatement("$T fVal", rType)
                 .beginControlFlow("if((fVal = ($T)$L) == null)", rType, valExpr)
-                .addStatement("$T.NULL_WRITE.invokeExact($L)", TupleAccessorExpr.class, asmVar)
+                .addStatement("$T.WRITE_NULL.invoke($L)", TupleAccessorExpr.class, asmVar)
                 .nextControlFlow("else")
                 .addStatement("$T.$L.invoke($L, fVal)", TupleAccessorExpr.class, writeExpr, asmVar)
                 .endControlFlow()
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
index 1f0ebef..e84e73b 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
@@ -17,18 +17,21 @@
 
 package org.apache.ignite.internal.benchmarks;
 
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
 import java.lang.reflect.Field;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
+import javax.lang.model.element.Modifier;
 import org.apache.ignite.internal.schema.Column;
 import org.apache.ignite.internal.schema.Columns;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
 import org.apache.ignite.internal.schema.marshaller.Serializer;
 import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
 import org.apache.ignite.internal.util.Factory;
 import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.CompilerFactoryFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.BenchmarkMode;
 import org.openjdk.jmh.annotations.Fork;
@@ -155,28 +158,32 @@ public class SerializerBenchmarkTest {
      * @return Generated test object class.
      * @throws Exception If failed.
      */
-    private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) throws Exception {
-        final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator();
+    private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) {
+        final String packageName = "org.apache.ignite.internal.benchmarks";
+        final String className = "TestObject";
 
-        ce.setClassName("TestObject");
-        ce.setDefaultImports("java.util.Random");
+        final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
 
-        final StringBuilder sb = new StringBuilder();
         for (int i = 0; i < maxFields; i++)
-            sb.append(fieldType.getName()).append(" col").append(i).append(";\n");
+            classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
 
-        // Constructor.
-        sb.append("public TestObject() {\n");
-        sb.append("    Random rnd = new Random();\n");
-        for (int i = 0; i < maxFields; i++)
-            sb.append("    col").append(i).append(" = rnd.nextLong();\n");
-        sb.append("}\n");
+        { // Build constructor.
+            final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addStatement("$T rnd = new $T()", Random.class, Random.class);
 
-        try {
-            ce.setParentClassLoader(getClass().getClassLoader());
-            ce.cook(sb.toString());
+            for (int i = 0; i < maxFields; i++)
+                builder.addStatement("col$L = rnd.nextLong()", i);
+
+            classBuilder.addMethod(builder.build());
+        }
 
-            return ce.getClazz();
+        final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+        final ClassLoader loader = MarshallerUtil.compileCode(javaFile);
+
+        try {
+            return loader.loadClass(packageName + '.' + className);
         }
         catch (Exception ex) {
             throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
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
index d172e86..a9589e9 100644
--- 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
@@ -17,13 +17,19 @@
 
 package org.apache.ignite.internal.schema.marshaller;
 
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Random;
 import java.util.UUID;
 import java.util.stream.Stream;
+import javax.lang.model.element.Modifier;
 import org.apache.ignite.internal.schema.Bitmask;
 import org.apache.ignite.internal.schema.Column;
 import org.apache.ignite.internal.schema.Columns;
@@ -33,6 +39,7 @@ import org.apache.ignite.internal.schema.SchemaDescriptor;
 import org.apache.ignite.internal.schema.TestUtils;
 import org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator;
 import org.apache.ignite.internal.schema.marshaller.reflection.JavaSerializerFactory;
+import org.apache.ignite.internal.util.ObjectFactory;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DynamicNode;
 import org.junit.jupiter.api.TestFactory;
@@ -261,6 +268,45 @@ public class JavaSerializerTest {
             );
     }
 
+
+    /**
+     *
+     */
+    @ParameterizedTest
+    @MethodSource("serializerFactoryProvider")
+    public void testClassLoader(SerializerFactory factory) throws SerializationException {
+        Column[] keyCols = new Column[] {
+            new Column("key", LONG, false)
+        };
+
+        Column[] valCols = new Column[] {
+            new Column("col0", LONG, false),
+            new Column("col1", LONG, false),
+            new Column("col2", LONG, false),
+        };
+
+        SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(keyCols), new Columns(valCols));
+
+        final Map<String, byte[]> classes = new HashMap<>();
+        final Class<?> valClass = createGeneratedObjectClass(Long.class, classes);
+        final ObjectFactory<?> objFactory = new ObjectFactory<>(valClass);
+
+        final Long key = rnd.nextLong();
+
+        if (factory instanceof JaninoSerializerGenerator)
+            ((JaninoSerializerGenerator)factory).setClasses(classes);
+
+        Serializer serializer = factory.create(schema, key.getClass(), valClass);
+
+        byte[] bytes = serializer.serialize(key, objFactory.create());
+
+        Object key1 = serializer.deserializeKey(bytes);
+        Object val1 = serializer.deserializeValue(bytes);
+
+        assertTrue(key.getClass().isInstance(key1));
+        assertTrue(valClass.isInstance(val1));
+    }
+
     /**
      * Generate random key-value pair of given types and
      * check serialization and deserialization works fine.
@@ -318,6 +364,45 @@ public class JavaSerializerTest {
     }
 
     /**
+     * Generate class for test objects.
+     *
+     * @param fieldType Field type.
+     * @param classes
+     * @return Generated test object class.
+     */
+    private Class<?> createGeneratedObjectClass(Class<?> fieldType, Map<String, byte[]> classes) {
+        final String packageName = getClass().getPackageName();
+        final String className = "GeneratedTestObject";
+
+        final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
+
+        for (int i = 0; i < 3; i++)
+            classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
+
+        { // Build constructor.
+            final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addStatement("$T rnd = new $T()", Random.class, Random.class);
+
+            for (int i = 0; i < 3; i++)
+                builder.addStatement("col$L = rnd.nextLong()", i);
+
+            classBuilder.addMethod(builder.build());
+        }
+
+        final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+        final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
+
+        try {
+            return loader.loadClass(packageName + '.' + className);
+        }
+        catch (Exception ex) {
+            throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+        }
+    }
+
+    /**
      * Test object.
      */
     public static class TestObject {
@@ -413,7 +498,7 @@ public class JavaSerializerTest {
     /**
      * Test object with private constructor.
      */
-    private static class PrivateTestObject {
+    public static class PrivateTestObject {
         /**
          * @return Random TestObject.
          */
@@ -431,7 +516,6 @@ public class JavaSerializerTest {
         /**
          * Private constructor.
          */
-        @SuppressWarnings("RedundantNoArgConstructor")
         private PrivateTestObject() {
         }