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); } /**