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

commit 5cc7dd047f97fda8e978d864faa5b77a2235373f
Author: Andrew Mashenkov <andrey.mashen...@gmail.com>
AuthorDate: Mon Nov 16 15:02:40 2020 +0300

    WIP. Replace reflection with unsafe.
---
 .../ignite/internal/schema/marshaller/Factory.java |  31 +++
 .../internal/schema/marshaller/FieldAccessor.java  | 144 ++++++++------
 .../internal/schema/marshaller/JavaSerializer.java |  77 ++------
 .../internal/schema/marshaller/Marshaller.java     |   9 +-
 .../schema/marshaller/MarshallerFactory.java       |  74 +++++++
 .../internal/schema/marshaller/ObjectFactory.java  |  49 ++---
 .../ignite/internal/util/IgniteUnsafeUtils.java    | 219 +++++++++++++++++++++
 .../schema/marshaller/JavaSerializerTest.java      |  19 +-
 8 files changed, 461 insertions(+), 161 deletions(-)

diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Factory.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Factory.java
new file mode 100644
index 0000000..0ad31e4
--- /dev/null
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Factory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.marshaller;
+
+/**
+ * Factory interface.
+ * @param <T> Object type.
+ */
+public interface Factory<T> {
+    /**
+     * Creates object.
+     *
+     * @return Object.
+     */
+    public T create();
+}
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 6e5603d..713553d 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
@@ -23,13 +23,13 @@ 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.apache.ignite.internal.util.IgniteUnsafeUtils;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Field accessor to speedup access.
  */
-//TODO: Rewrite to direct field access via Unsafe to bypass security checks.
-//TODO: Extract interface, move to java-8 profile and add implementation based 
on VarHandle for java9+.
+// TODO: Extract interface, move to java-8 profile and add Java9+ 
implementation using VarHandles.
 public abstract class FieldAccessor {
     /**
      * TODO: implement sesitive information filtering.
@@ -40,12 +40,15 @@ public abstract class FieldAccessor {
         return true;
     }
 
-    /** Field name */
-    protected final Field field;
+    /** Offset. */
+    protected final long offset;
 
     /** Mode. */
     protected final BinaryMode mode;
 
+    /** Field name */
+    protected final String name;
+
     /**
      * Mapped column position in schema.
      * <p>
@@ -61,12 +64,11 @@ public abstract class FieldAccessor {
      * @param colIdx Column index in schema.
      * @return Accessor.
      */
-    //TODO: Extract a provider for this factory-method.
-    public static FieldAccessor create(Class<?> type, Column col, int colIdx) {
+    static FieldAccessor create(Class<?> type, Column col, int colIdx) {
         try {
             final Field field = type.getDeclaredField(col.name());
 
-            if (field.getType().isPrimitive() && col.nullable()) //TODO: 
convert to assert?
+            if (field.getType().isPrimitive() && col.nullable())
                 throw new IllegalArgumentException("Failed to map non-nullable 
field to nullable column [name=" + field.getName() + ']');
 
             BinaryMode mode = JavaSerializer.mode(field.getType());
@@ -159,15 +161,32 @@ 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;
 
-        this.field = field;
         this.colIdx = colIdx;
         this.mode = mode;
+        offset = IgniteUnsafeUtils.objectFieldOffset(field);
+        name = field.getName();
+
+        field.setAccessible(true);
+    }
+
+    /**
+     * Protected constructor.
+     *
+     * @param colIdx Column index.
+     * @param mode Binary mode;
+     */
+    private FieldAccessor(int colIdx, BinaryMode mode) {
+        assert colIdx >= 0;
+        assert mode != null;
 
-        if (field != null)
-            field.setAccessible(true);
+        this.colIdx = colIdx;
+        this.mode = mode;
+        offset = 0;
+        name = null;
     }
 
     /**
@@ -191,8 +210,8 @@ public abstract class FieldAccessor {
             write0(Objects.requireNonNull(obj), writer);
         }
         catch (Exception ex) {
-            if (includeSensitive() && field != null)
-                throw new SerializationException("Failed to write field 
[name=" + field.getName() + ']', ex);
+            if (includeSensitive() && name != null)
+                throw new SerializationException("Failed to write field 
[name=" + name + ']', ex);
             else
                 throw new SerializationException("Failed to write field [id=" 
+ colIdx + ']', ex);
         }
@@ -219,8 +238,8 @@ public abstract class FieldAccessor {
             read0(Objects.requireNonNull(obj), reader);
         }
         catch (Exception ex) {
-            if (includeSensitive())
-                throw new SerializationException("Failed to read field [name=" 
+ field.getName() + ']', ex);
+            if (includeSensitive() && name != null)
+                throw new SerializationException("Failed to read field [name=" 
+ name + ']', ex);
             else
                 throw new SerializationException("Failed to read field [id=" + 
colIdx + ']', ex);
         }
@@ -250,18 +269,9 @@ public abstract class FieldAccessor {
      *
      * @param obj Object.
      * @return Field value of given object.
-     * @throws SerializationException If failed.
      */
-    @Nullable Object value(Object obj) throws SerializationException {
-        try {
-            return field.get(Objects.requireNonNull(obj));
-        }
-        catch (IllegalAccessException ex) {
-            if (includeSensitive())
-                throw new SerializationException("Failed to read field [name=" 
+ field.getName() + ']', ex);
-            else
-                throw new SerializationException("Failed to read field [id=" + 
colIdx + ']', ex);
-        }
+    @Nullable Object value(Object obj) {
+        return IgniteUnsafeUtils.getObjectField(Objects.requireNonNull(obj), 
offset);
     }
 
     /**
@@ -275,7 +285,7 @@ public abstract class FieldAccessor {
          * @param mode Binary mode.
          */
         public IdentityAccessor(int colIdx, BinaryMode mode) {
-            super(null, colIdx, mode);
+            super(colIdx, mode);
         }
 
         /** {@inheritDoc} */
@@ -314,13 +324,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendByte(field.getByte(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final byte val = IgniteUnsafeUtils.getByteField(obj, offset);
+
+            writer.appendByte(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setByte(obj, reader.byteValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final byte val = reader.byteValue(colIdx);
+
+            IgniteUnsafeUtils.putByteField(obj, offset, val);
         }
     }
 
@@ -339,13 +353,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendShort(field.getShort(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final short val = IgniteUnsafeUtils.getShortField(obj, offset);
+
+            writer.appendShort(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setShort(obj, reader.shortValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final short val = reader.shortValue(colIdx);
+
+            IgniteUnsafeUtils.putShortField(obj, offset, val);
         }
     }
 
@@ -364,13 +382,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendInt(field.getInt(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final int val = IgniteUnsafeUtils.getIntField(obj, offset);
+
+            writer.appendInt(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setInt(obj, reader.intValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final int val = reader.intValue(colIdx);
+
+            IgniteUnsafeUtils.putIntField(obj, offset, val);
         }
     }
 
@@ -389,13 +411,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendLong(field.getLong(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final long val = IgniteUnsafeUtils.getLongField(obj, offset);
+
+            writer.appendLong(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setLong(obj, reader.longValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final long val = reader.longValue(colIdx);
+
+            IgniteUnsafeUtils.putLongField(obj, offset, val);
         }
     }
 
@@ -414,13 +440,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendFloat(field.getFloat(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final float val = IgniteUnsafeUtils.getFloatField(obj, offset);
+
+            writer.appendFloat(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setFloat(obj, reader.floatValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final float val = reader.floatValue(colIdx);
+
+            IgniteUnsafeUtils.putFloatField(obj, offset, val);
         }
     }
 
@@ -439,13 +469,17 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
-            writer.appendDouble(field.getDouble(obj));
+        @Override protected void write0(Object obj, TupleAssembler writer) {
+            final double val = IgniteUnsafeUtils.getDoubleField(obj, offset);
+
+            writer.appendDouble(val);
         }
 
         /** {@inheritDoc} */
-        @Override protected void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
-            field.setDouble(obj, reader.doubleValue(colIdx));
+        @Override protected void read0(Object obj, Tuple reader) {
+            final double val = reader.doubleValue(colIdx);
+
+            IgniteUnsafeUtils.putDoubleField(obj, offset, val);
         }
     }
 
@@ -465,13 +499,13 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override protected void write0(Object obj, TupleAssembler writer) 
throws IllegalAccessException {
+        @Override protected void write0(Object obj, TupleAssembler writer) {
             assert obj != null;
             assert writer != null;
 
             Object val;
 
-            val = field.get(obj);
+            val = IgniteUnsafeUtils.getObjectField(obj, offset);
 
             if (val == null) {
                 writer.appendNull();
@@ -483,12 +517,10 @@ public abstract class FieldAccessor {
         }
 
         /** {@inheritDoc} */
-        @Override public void read0(Object obj, Tuple reader) throws 
IllegalAccessException {
+        @Override public void read0(Object obj, Tuple reader) {
             Object val = JavaSerializer.readRefValue(reader, colIdx, mode);
 
-            assert !field.getType().isPrimitive();
-
-            field.set(obj, val);
+            IgniteUnsafeUtils.putObjectField(obj, offset, val);
         }
     }
 }
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 1687ccc..9294ce9 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
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.schema.marshaller;
 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;
@@ -254,42 +253,8 @@ public class JavaSerializer {
         this.keyClass = keyClass;
         this.valClass = valClass;
 
-        keyMarsh = createMarshaller(schema.keyColumns(), 0, keyClass);
-        valMarsh = createMarshaller(schema.valueColumns(), 
schema.keyColumns().length(), valClass);
-    }
-
-    /**
-     * Creates marshaller for class.
-     *
-     * @param cols Columns.
-     * @param firstColId First column position in schema.
-     * @param aClass Type.
-     * @return Marshaller.
-     */
-    private static Marshaller createMarshaller(Columns cols, int firstColId, 
Class<?> aClass) {
-        final BinaryMode mode = mode(aClass);
-
-        if (mode != null) {
-            final Column col = cols.column(0);
-
-            assert cols.length() == 1;
-            assert mode.typeSpec() == col.type().spec() : "Target type is not 
compatible.";
-            assert !aClass.isPrimitive() : "Non-nullable types are not 
allowed.";
-
-            return new Marshaller(FieldAccessor.createIdentityAccessor(col, 
firstColId, mode));
-        }
-
-        FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
-
-        // Build accessors
-        for (int i = 0; i < cols.length(); i++) {
-            final Column col = cols.column(i);
-
-            final int colIdx = firstColId + i; /* Absolute column idx in 
schema. */
-            fieldAccessors[i] = FieldAccessor.create(aClass, col, colIdx);
-        }
-
-        return new Marshaller(ObjectFactory.classFactory(aClass), 
fieldAccessors);
+        keyMarsh = MarshallerFactory.createMarshaller(schema.keyColumns(), 0, 
keyClass);
+        valMarsh = MarshallerFactory.createMarshaller(schema.valueColumns(), 
schema.keyColumns().length(), valClass);
     }
 
     /**
@@ -335,33 +300,14 @@ public class JavaSerializer {
     }
 
     /**
-     * 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 {
+    private ObjectStatistic collectObjectStats(Columns cols, Marshaller marsh, 
Object obj) {
         if (obj == null || cols.firstVarlengthColumn() < 0 /* No varlen 
columns */)
             return new ObjectStatistic(0, 0);
 
@@ -428,4 +374,21 @@ public class JavaSerializer {
 
         return o;
     }
+
+    /**
+     * 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;
+        }
+    }
 }
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 f907c16..3b73a3e 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
@@ -52,7 +52,7 @@ public class Marshaller {
     /**
      * Object factory for complex types or {@code null} for basic type.
      */
-    private final ObjectFactory<?> factory;
+    private final Factory<?> factory;
 
     /**
      * Constructor.
@@ -62,7 +62,7 @@ public class Marshaller {
      * @param fieldAccessors Object field accessors for mapped columns.
      */
     @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
-    public Marshaller(ObjectFactory<?> factory, FieldAccessor[] 
fieldAccessors) {
+    public Marshaller(Factory<?> factory, FieldAccessor[] fieldAccessors) {
         this.fieldAccessors = fieldAccessors;
         this.factory = Objects.requireNonNull(factory);
     }
@@ -84,9 +84,8 @@ public class Marshaller {
      * @param obj Object.
      * @param fldIdx Field index.
      * @return Field value.
-     * @throws SerializationException If failed.
      */
-    public @Nullable Object value(Object obj, int fldIdx) throws 
SerializationException {
+    public @Nullable Object value(Object obj, int fldIdx) {
         return fieldAccessors[fldIdx].value(obj);
     }
 
@@ -101,7 +100,7 @@ public class Marshaller {
         if (isBasicTypeMarshaller())
             return fieldAccessors[0].read(reader);
 
-        final Object obj = factory.newInstance();
+        final Object obj = factory.create();
 
         for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
             fieldAccessors[fldIdx].read(obj, reader);
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
new file mode 100644
index 0000000..3e642da
--- /dev/null
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.Column;
+import org.apache.ignite.internal.schema.Columns;
+
+public abstract class MarshallerFactory {
+    /**
+     * Creates marshaller for class.
+     *
+     * @param cols Columns.
+     * @param firstColId First column position in schema.
+     * @param aClass Type.
+     * @return Marshaller.
+     */
+    public static Marshaller createMarshaller(Columns cols, int firstColId, 
Class<? extends Object> aClass) {
+        final BinaryMode mode = JavaSerializer.mode(aClass);
+
+        if (mode != null) {
+            final Column col = cols.column(0);
+
+            assert cols.length() == 1;
+            assert mode.typeSpec() == col.type().spec() : "Target type is not 
compatible.";
+            assert !aClass.isPrimitive() : "Non-nullable types are not 
allowed.";
+
+            return new Marshaller(FieldAccessor.createIdentityAccessor(col, 
firstColId, mode));
+        }
+
+        FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
+
+        // Build accessors
+        for (int i = 0; i < cols.length(); i++) {
+            final Column col = cols.column(i);
+
+            final int colIdx = firstColId + i; /* Absolute column idx in 
schema. */
+            fieldAccessors[i] = FieldAccessor.create(aClass, col, colIdx);
+        }
+
+        return new Marshaller(new ObjectFactory<>(aClass), fieldAccessors);
+    }
+}
diff --git 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectFactory.java
 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectFactory.java
index 954b656..d98ca69 100644
--- 
a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectFactory.java
+++ 
b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectFactory.java
@@ -17,56 +17,31 @@
 
 package org.apache.ignite.internal.schema.marshaller;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+import org.apache.ignite.internal.util.IgniteUnsafeUtils;
 
 /**
  * Object factory.
  */
-// TODO: Rewrite to direct field access via Unsafe to bypass security checks.
-// TODO: Extract interface, move to java-8 profile and add Java9+ 
implementation using VarHandles.
-class ObjectFactory<T> {
-    /**
-     * Creates factory for class.
-     *
-     * @param tClass Class.
-     * @return Object factory.
-     */
-    static <T> ObjectFactory<T> classFactory(Class<T> tClass) {
-        try {
-            return new ObjectFactory<>(tClass.getDeclaredConstructor());
-        }
-        catch (NoSuchMethodException e) {
-            throw new IllegalStateException("No default constructor found for 
class: " + tClass.getSimpleName());
-        }
-    }
-
-    /** Constructor for class. */
-    private final Constructor<T> ctor;
+class ObjectFactory<T> implements Factory<T> {
+    /** Class. */
+    private final Class<T> tClass;
 
     /**
      * Constructor.
      *
-     * @param ctor Class constructor for factory.
+     * @param tClass Class.
      */
-    private ObjectFactory(Constructor<T> ctor) {
-        this.ctor = ctor;
-
-        ctor.setAccessible(true);
+    ObjectFactory(Class<T> tClass) {
+        this.tClass = tClass;
     }
 
-    /**
-     * Creates new class instance using default constructor.
-     *
-     * @return New instance of class.
-     * @throws IllegalStateException If failed.
-     */
-    public T newInstance() throws IllegalStateException {
+    /** {@inheritDoc} */
+    @Override public T create() throws IllegalStateException {
         try {
-            return ctor.newInstance();
+            return (T)IgniteUnsafeUtils.allocateInstance(tClass);
         }
-        catch (InstantiationException | InvocationTargetException | 
IllegalAccessException e) {
-            throw new IllegalStateException("Failed to instantiate class: " + 
ctor.getDeclaringClass(), e);
+        catch (InstantiationException e) {
+            throw new IllegalStateException("Failed to instantiate class: " + 
tClass.getSimpleName(), e);
         }
     }
 }
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
index 3bce3df..db07a16 100644
--- 
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
@@ -29,6 +29,7 @@ import sun.misc.Unsafe;
 public class IgniteUnsafeUtils {
     /** Unsafe. */
     private static final Unsafe UNSAFE = unsafe();
+
     /**
      * @return Instance of Unsafe class.
      */
@@ -54,4 +55,222 @@ public class IgniteUnsafeUtils {
             }
         }
     }
+
+    /**
+     * Returns object field offset.
+     *
+     * @param field Field.
+     * @return Object field offset.
+     */
+    public static long objectFieldOffset(Field field) {
+        return UNSAFE.objectFieldOffset(field);
+    }
+
+    /**
+     * Gets boolean value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Boolean value from object field.
+     */
+    public static boolean getBooleanField(Object obj, long fieldOff) {
+        return UNSAFE.getBoolean(obj, fieldOff);
+    }
+
+    /**
+     * Stores boolean value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putBooleanField(Object obj, long fieldOff, boolean val) 
{
+        UNSAFE.putBoolean(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets byte value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Byte value from object field.
+     */
+    public static byte getByteField(Object obj, long fieldOff) {
+        return UNSAFE.getByte(obj, fieldOff);
+    }
+
+    /**
+     * Stores byte value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putByteField(Object obj, long fieldOff, byte val) {
+        UNSAFE.putByte(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets short value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Short value from object field.
+     */
+    public static short getShortField(Object obj, long fieldOff) {
+        return UNSAFE.getShort(obj, fieldOff);
+    }
+
+    /**
+     * Stores short value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putShortField(Object obj, long fieldOff, short val) {
+        UNSAFE.putShort(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets char value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Char value from object field.
+     */
+    public static char getCharField(Object obj, long fieldOff) {
+        return UNSAFE.getChar(obj, fieldOff);
+    }
+
+    /**
+     * Stores char value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putCharField(Object obj, long fieldOff, char val) {
+        UNSAFE.putChar(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets integer value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Integer value from object field.
+     */
+    public static int getIntField(Object obj, long fieldOff) {
+        return UNSAFE.getInt(obj, fieldOff);
+    }
+
+    /**
+     * Stores integer value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putIntField(Object obj, long fieldOff, int val) {
+        UNSAFE.putInt(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets long value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Long value from object field.
+     */
+    public static long getLongField(Object obj, long fieldOff) {
+        return UNSAFE.getLong(obj, fieldOff);
+    }
+
+    /**
+     * Stores long value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putLongField(Object obj, long fieldOff, long val) {
+        UNSAFE.putLong(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets float value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Float value from object field.
+     */
+    public static float getFloatField(Object obj, long fieldOff) {
+        return UNSAFE.getFloat(obj, fieldOff);
+    }
+
+    /**
+     * Stores float value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putFloatField(Object obj, long fieldOff, float val) {
+        UNSAFE.putFloat(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets double value from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Double value from object field.
+     */
+    public static double getDoubleField(Object obj, long fieldOff) {
+        return UNSAFE.getDouble(obj, fieldOff);
+    }
+
+    /**
+     * Stores double value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putDoubleField(Object obj, long fieldOff, double val) {
+        UNSAFE.putDouble(obj, fieldOff, val);
+    }
+
+    /**
+     * Gets reference from object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @return Reference from object field.
+     */
+    public static Object getObjectField(Object obj, long fieldOff) {
+        return UNSAFE.getObject(obj, fieldOff);
+    }
+
+    /**
+     * Stores reference value into object field.
+     *
+     * @param obj Object.
+     * @param fieldOff Field offset.
+     * @param val Value.
+     */
+    public static void putObjectField(Object obj, long fieldOff, Object val) {
+        UNSAFE.putObject(obj, fieldOff, val);
+    }
+
+    /**
+     * Allocates instance of given class.
+     *
+     * @param cls Class.
+     * @return Allocated instance.
+     */
+    public static Object allocateInstance(Class cls) throws 
InstantiationException {
+        return UNSAFE.allocateInstance(cls);
+    }
 }
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 372c27e..3cfb0da 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
@@ -215,9 +215,8 @@ public class JavaSerializerTest {
     /**
      *
      */
-    @SuppressWarnings("ResultOfObjectAllocationIgnored")
     @Test
-    public void testClassWithNoDefaultConstructor() {
+    public void testClassWithNoDefaultConstructor() throws 
SerializationException {
         Column[] cols = new Column[] {
             new Column("pLongCol", LONG, false),
         };
@@ -227,10 +226,18 @@ public class JavaSerializerTest {
         final Object key = WrongTestObject.randomObject(rnd);
         final Object val = WrongTestObject.randomObject(rnd);
 
-        assertThrows(IllegalStateException.class,
-            () -> new JavaSerializer(schema, key.getClass(), val.getClass()),
-            "No default constructor found for class: WrongTestObject"
-        );
+        final JavaSerializer serializer = new JavaSerializer(schema, 
key.getClass(), val.getClass());
+
+        final byte[] bytes = serializer.serialize(key, val);
+
+        Object key1 = serializer.deserializeKey(bytes);
+        Object val1 = serializer.deserializeValue(bytes);
+
+        assertTrue(key.getClass().isInstance(key1));
+        assertTrue(val.getClass().isInstance(val1));
+
+        assertEquals(key, key);
+        assertEquals(val, val1);
     }
 
     /**

Reply via email to