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 3a0646d3aafb30b8b281e22fcb29dd13f0f67e35 Author: Andrew Mashenkov <[email protected]> AuthorDate: Thu Nov 19 13:51:27 2020 +0300 WIP. Add serializer generator. --- .../ignite/internal/schema/TupleAssembler.java | 4 - .../marshaller/FieldAccessExprGenerator.java | 76 ++++ .../marshaller/JaninoSerializerGenerator.java | 382 +++++++++++++++++++++ .../internal/schema/marshaller/JavaSerializer.java | 91 +---- ...onException.java => JavaSerializerFactory.java} | 17 +- .../internal/schema/marshaller/Marshaller.java | 44 ++- .../schema/marshaller/MarshallerFactory.java | 74 ---- .../internal/schema/marshaller/MarshallerUtil.java | 95 +++++ .../marshaller/ObjectMarshallerExprGenerator.java | 68 ++++ .../schema/marshaller/SerializationException.java | 10 + ...SerializationException.java => Serializer.java} | 25 +- ...zationException.java => SerializerFactory.java} | 24 +- ...FieldAccessor.java => UnsafeFieldAccessor.java} | 32 +- .../schema/marshaller/FieldAccessorTest.java | 8 +- .../schema/marshaller/JavaSerializerTest.java | 360 ++++++++++--------- 15 files changed, 925 insertions(+), 385 deletions(-) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/TupleAssembler.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/TupleAssembler.java index 45d3982..71c3eda 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/TupleAssembler.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/TupleAssembler.java @@ -17,12 +17,8 @@ package org.apache.ignite.internal.schema; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; import java.nio.charset.StandardCharsets; import java.util.BitSet; import java.util.UUID; diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessExprGenerator.java new file mode 100644 index 0000000..1ef3484 --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessExprGenerator.java @@ -0,0 +1,76 @@ +/* + * 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; + +class FieldAccessExprGenerator { + final long offset; + final int colIdx; + + private final String castClass; + private final String putFieldMethod; + private final String getFieldMethod; + private final String writeColMethod; + private final String readColMethod; + + public FieldAccessExprGenerator(int colIdx, String castClass, String writeColMethod, + String readColMethod, long offset) { + this(colIdx, castClass, readColMethod, writeColMethod, offset, + "IgniteUnsafeUtils.getObjectField", "IgniteUnsafeUtils.putObjectField"); + } + + public FieldAccessExprGenerator(int colIdx, String readColMethod, String writeColMethod, long offset, + String getFieldMethod, String putFieldMethod) { + this(colIdx, null, readColMethod, writeColMethod, offset, getFieldMethod, putFieldMethod); + } + + private FieldAccessExprGenerator(int colIdx, String castClass, String readColMethod, String writeColMethod, + long offset, String getFieldMethod, String putFieldMethod) { + this.offset = offset; + this.colIdx = colIdx; + this.castClass = castClass; + this.putFieldMethod = putFieldMethod; + this.getFieldMethod = getFieldMethod; + this.writeColMethod = writeColMethod; + this.readColMethod = readColMethod; + } + + public String getFieldExpr() { + if (offset == -1) + return "obj"; + + return getFieldMethod + "(obj, " + offset + ')'; + } + + public final void addPutFieldExpr(StringBuilder sb, String val, String indent) { + sb.append(indent).append(putFieldMethod).append("(obj, ").append(offset).append(", ").append(val).append(')'); + sb.append(";" + JaninoSerializerGenerator.LF); + } + + public final void addWriteColumnExpr(StringBuilder sb, String expr, String indent) { + sb.append(indent).append(writeColMethod).append('('); + + if (castClass != null) + sb.append("(").append(castClass).append(")"); + + sb.append(expr).append(");" + JaninoSerializerGenerator.LF); + } + + public String readColumnExpr() { + return readColMethod + "(" + colIdx + ")"; + } +} diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JaninoSerializerGenerator.java new file mode 100644 index 0000000..e96e5c2 --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JaninoSerializerGenerator.java @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.schema.marshaller; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import org.apache.ignite.internal.schema.Columns; +import org.apache.ignite.internal.schema.SchemaDescriptor; +import org.apache.ignite.internal.util.IgniteUnsafeUtils; +import org.codehaus.commons.compiler.CompilerFactoryFactory; +import org.codehaus.commons.compiler.IClassBodyEvaluator; + +/** + * + */ +public class JaninoSerializerGenerator implements SerializerFactory { + /** Tabulate. */ + static final String TAB = " "; + + /** Line feed. */ + static final char LF = '\n'; + + /** Debug flag. */ + private static final boolean enabledDebug = false; + + @Override public Serializer create( + SchemaDescriptor schema, + Class<?> keyClass, + Class<?> valClass + ) { + try { + final String packageName = "org.apache.ignite.internal.schema.marshaller."; + final String className = "JaninoSerializerForSchema_" + schema.version(); + + final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator(); + + ce.setClassName(packageName + 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" + ); + + final StringBuilder sb = new StringBuilder(8 * 1024); + + // Create class fields and constructor. + sb.append("private final SchemaDescriptor schema;" + LF); + sb.append("private final Class kClass;" + LF); + sb.append("private final Class vClass;" + LF); + // Constructor. + sb.append(LF + "public ").append(className).append("(SchemaDescriptor schema, Class kClass, Class vClass) {" + LF); + sb.append(TAB + "this.kClass = kClass;" + LF); + sb.append(TAB + "this.vClass = vClass;" + LF); + sb.append(TAB + "this.schema = schema; " + LF); + sb.append("}" + LF); + + // Build field accessor generators. + final ObjectMarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "kClass", schema.keyColumns(), 0); + final ObjectMarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "vClass", schema.valueColumns(), schema.keyColumns().length()); + + generateTupleFactoryMethod(sb, schema, keyMarsh, valMarsh); + + writeSerializeMethod(sb, keyMarsh, valMarsh); + writeDeserializeMethods(sb, keyMarsh, valMarsh); + + final String code = sb.toString(); + + if (enabledDebug) { + ce.setDebuggingInformation(true, true, true); + //TODO: pass to logger. + System.out.println(code); + } + + ce.setParentClassLoader(getClass().getClassLoader()); + ce.cook(code); + + try { + final Constructor<Serializer> ctor = (Constructor<Serializer>)ce.getClazz() + .getDeclaredConstructor(schema.getClass(), Class.class, Class.class); + + return ctor.newInstance(schema, keyClass, valClass); + } + catch (Exception ex) { + System.err.println(code); + + throw ex; + } + } + catch (Exception ex) { + //TODO: fallback to java serializer? + throw new IllegalStateException(ex); + } + } + + private ObjectMarshallerExprGenerator createObjectMarshaller(Class<?> aClass, String classField, Columns columns, + int firstColIdx) { + BinaryMode mode = MarshallerUtil.mode(aClass); + + if (mode != null) + return new ObjectMarshallerExprGenerator.IdentityObjectMarshaller(createAccessor(mode, firstColIdx, -1L)); + + FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()]; + try { + for (int i = 0; i < columns.length(); i++) { + final Field field = aClass.getDeclaredField(columns.column(i).name()); + + accessors[i] = createAccessor( + MarshallerUtil.mode(field.getType()), + firstColIdx + i /* schma absolute index. */, + IgniteUnsafeUtils.objectFieldOffset(field)); + } + } + catch (NoSuchFieldException ex) { + throw new IllegalStateException(ex); + } + + return new ObjectMarshallerExprGenerator(classField, accessors); + } + + private FieldAccessExprGenerator createAccessor(BinaryMode mode, int colIdx, long offset) { + switch (mode) { + case BYTE: + return new FieldAccessExprGenerator( + colIdx, + "Byte", + "asm.appendByte", + "tuple.byteValueBoxed", + offset); + + case P_BYTE: + return new FieldAccessExprGenerator( + colIdx, + "tuple.byteValue", "asm.appendByte", + offset, + "IgniteUnsafeUtils.getByteField", + "IgniteUnsafeUtils.putByteField" + ); + + case SHORT: + return new FieldAccessExprGenerator( + colIdx, + "Short", + "asm.appendShort", + "tuple.shortValueBoxed", + offset); + + case P_SHORT: + return new FieldAccessExprGenerator( + colIdx, + "tuple.shortValue", "asm.appendShort", + offset, + "IgniteUnsafeUtils.getShortField", + "IgniteUnsafeUtils.putShortField" + ); + + case INT: + return new FieldAccessExprGenerator( + colIdx, + "Integer", + "asm.appendInt", + "tuple.intValueBoxed", + offset); + + case P_INT: + return new FieldAccessExprGenerator( + colIdx, + "tuple.intValue", "asm.appendInt", + offset, + "IgniteUnsafeUtils.getIntField", + "IgniteUnsafeUtils.putIntField" + ); + + case LONG: + return new FieldAccessExprGenerator( + colIdx, + "Long", + "asm.appendLong", + "tuple.longValueBoxed", + offset); + + case P_LONG: + return new FieldAccessExprGenerator( + colIdx, + "tuple.longValue", "asm.appendLong", + offset, + "IgniteUnsafeUtils.getLongField", + "IgniteUnsafeUtils.putLongField" + ); + + case FLOAT: + return new FieldAccessExprGenerator( + colIdx, + "Float", + "asm.appendFloat", + "tuple.floatValueBoxed", + offset); + + case P_FLOAT: + return new FieldAccessExprGenerator( + colIdx, + "tuple.floatValue", "asm.appendFloat", + offset, + "IgniteUnsafeUtils.getFloatField", + "IgniteUnsafeUtils.putFloatField" + ); + + case DOUBLE: + return new FieldAccessExprGenerator( + colIdx, + "Double", + "asm.appendDouble", + "tuple.doubleValueBoxed", + offset); + + case P_DOUBLE: + return new FieldAccessExprGenerator( + colIdx, + "tuple.doubleValue", "asm.appendDouble", + offset, + "IgniteUnsafeUtils.getDoubleField", + "IgniteUnsafeUtils.putDoubleField" + ); + + case UUID: + return new FieldAccessExprGenerator( + colIdx, + "UUID", + "asm.appendUuid", + "tuple.uuidValue", + offset); + + case BITSET: + return new FieldAccessExprGenerator( + colIdx, + "BitSet", + "asm.appendBitmask", + "tuple.bitmaskValue", + offset); + + case STRING: + return new FieldAccessExprGenerator( + colIdx, + "String", + "asm.appendString", + "tuple.stringValue", + offset); + + case BYTE_ARR: + return new FieldAccessExprGenerator( + colIdx, + "byte[]", + "asm.appendBytes", + "tuple.bytesValue", + offset); + default: + throw new IllegalStateException("Unsupportd binary mode"); + } + } + + private void writeSerializeMethod(StringBuilder sb, + ObjectMarshallerExprGenerator keyMarsh, + ObjectMarshallerExprGenerator valMarsh + ) { + sb.append(LF + "@Override public byte[] serialize(Object key, Object val) throws SerializationException {" + LF); + sb.append(TAB + "TupleAssembler asm = createAssembler(key, val);" + LF); + + sb.append(TAB + "{" + LF); + sb.append(TAB + TAB + "Object obj = key;" + LF); + keyMarsh.marshallObject(sb, TAB + TAB); + sb.append(TAB + "} {" + LF); + sb.append(TAB + TAB + "Object obj = val;" + LF); + valMarsh.marshallObject(sb, TAB + TAB); + sb.append(TAB + "}" + LF); + + sb.append(TAB + "return asm.build();" + LF); + sb.append("}" + LF); + } + + private void writeDeserializeMethods(StringBuilder sb, + ObjectMarshallerExprGenerator keyMarsh, + ObjectMarshallerExprGenerator valMarsh + ) { + sb.append(LF + "@Override public Object deserializeKey(byte[] data) throws SerializationException {" + LF); + sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF); + + keyMarsh.unmarshallObject(sb, TAB); + + sb.append(TAB + "return obj;" + LF); + sb.append("}" + LF); + + sb.append(LF + "@Override public Object deserializeValue(byte[] data) throws SerializationException {" + LF); + sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF); + + valMarsh.unmarshallObject(sb, TAB); + + sb.append(TAB + "return obj;" + LF); + sb.append("}" + LF); + } + + private void generateTupleFactoryMethod( + StringBuilder sb, + SchemaDescriptor schema, + ObjectMarshallerExprGenerator keyMarsh, + ObjectMarshallerExprGenerator valMarsh + ) { + sb.append(LF + "TupleAssembler createAssembler(Object key, Object val) {" + LF); + 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) { + sb.append(TAB + "{" + LF); + sb.append(TAB + TAB + "Object fVal, obj = key;" + LF); + + 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) { + sb.append(TAB + "{" + LF); + sb.append(TAB + TAB + "Object fVal, obj = val;" + LF); + + 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); + } + + 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); + + sb.append(TAB + "return new TupleAssembler(schema, size, nonNullVarlenKeys, nonNullVarlenValues);" + LF); + sb.append("}" + LF); + } +} 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 9294ce9..1aae7b2 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 @@ -21,66 +21,16 @@ import java.util.BitSet; import java.util.UUID; import org.apache.ignite.internal.schema.ByteBufferTuple; import org.apache.ignite.internal.schema.Columns; -import org.apache.ignite.internal.schema.NativeType; import org.apache.ignite.internal.schema.SchemaDescriptor; import org.apache.ignite.internal.schema.Tuple; import org.apache.ignite.internal.schema.TupleAssembler; +import static org.apache.ignite.internal.schema.marshaller.MarshallerUtil.getValueSize; + /** - * Cache objects (de)serializer. - * <p> - * TODO: Extract interface. + * Reflection based (de)serializer. */ -public class JavaSerializer { - /** - * Gets binary read/write mode for given class. - * - * @param cls Type. - * @return Binary mode. - */ - public static BinaryMode mode(Class<?> cls) { - assert cls != null; - - // Primitives. - if (cls == byte.class) - return BinaryMode.P_BYTE; - else if (cls == short.class) - return BinaryMode.P_SHORT; - else if (cls == int.class) - return BinaryMode.P_INT; - else if (cls == long.class) - return BinaryMode.P_LONG; - else if (cls == float.class) - return BinaryMode.P_FLOAT; - else if (cls == double.class) - return BinaryMode.P_DOUBLE; - - // Boxed primitives. - else if (cls == Byte.class) - return BinaryMode.BYTE; - else if (cls == Short.class) - return BinaryMode.SHORT; - else if (cls == Integer.class) - return BinaryMode.INT; - else if (cls == Long.class) - return BinaryMode.LONG; - else if (cls == Float.class) - return BinaryMode.FLOAT; - else if (cls == Double.class) - return BinaryMode.DOUBLE; - - // Other types - else if (cls == byte[].class) - return BinaryMode.BYTE_ARR; - else if (cls == String.class) - return BinaryMode.STRING; - else if (cls == UUID.class) - return BinaryMode.UUID; - else if (cls == BitSet.class) - return BinaryMode.BITSET; - - return null; - } +public class JavaSerializer implements Serializer { /** * Reads value object from tuple. @@ -253,8 +203,8 @@ public class JavaSerializer { this.keyClass = keyClass; this.valClass = valClass; - keyMarsh = MarshallerFactory.createMarshaller(schema.keyColumns(), 0, keyClass); - valMarsh = MarshallerFactory.createMarshaller(schema.valueColumns(), schema.keyColumns().length(), valClass); + keyMarsh = Marshaller.createMarshaller(schema.keyColumns(), 0, keyClass); + valMarsh = Marshaller.createMarshaller(schema.valueColumns(), schema.keyColumns().length(), valClass); } /** @@ -264,7 +214,7 @@ public class JavaSerializer { * @param val Value object. * @return Serialized key-value pair. */ - public byte[] serialize(Object key, Object val) throws SerializationException { + @Override public byte[] serialize(Object key, Object val) throws SerializationException { assert keyClass.isInstance(key); assert val == null || valClass.isInstance(val); @@ -286,9 +236,8 @@ public class JavaSerializer { * @param key Key object. * @param val Value object. * @return Tuple assembler. - * @throws SerializationException If failed. */ - private TupleAssembler createAssembler(Object key, Object val) throws SerializationException { + private TupleAssembler createAssembler(Object key, Object val) { ObjectStatistic keyStat = collectObjectStats(schema.keyColumns(), keyMarsh, key); ObjectStatistic valStat = collectObjectStats(schema.valueColumns(), valMarsh, val); @@ -328,29 +277,9 @@ public class JavaSerializer { } /** - * Calculates size for serialized value of varlen type. - * - * @param val Field value. - * @param type Mapped type. - * @return Serialized value size. - */ - private int getValueSize(Object val, NativeType type) { - switch (type.spec()) { - case BYTES: - return ((byte[])val).length; - - case STRING: - return TupleAssembler.utf8EncodedLength((CharSequence)val); - - default: - throw new IllegalStateException("Unsupported test varsize type: " + type); - } - } - - /** * @return Key object. */ - public Object deserializeKey(byte[] data) throws SerializationException { + @Override public Object deserializeKey(byte[] data) throws SerializationException { final Tuple tuple = new ByteBufferTuple(schema, data); final Object o = keyMarsh.readObject(tuple); @@ -363,7 +292,7 @@ public class JavaSerializer { /** * @return Value object. */ - public Object deserializeValue(byte[] data) throws SerializationException { + @Override public Object deserializeValue(byte[] data) throws SerializationException { final Tuple tuple = new ByteBufferTuple(schema, data); // TODO: add tomstone support. diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerFactory.java similarity index 74% copy from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java copy to modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerFactory.java index aa8a497..93351bb 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerFactory.java @@ -17,17 +17,10 @@ package org.apache.ignite.internal.schema.marshaller; -/** - * Serialization exception. - */ -public class SerializationException extends Exception { - /** - * Constructor. - * - * @param message Message. - * @param cause Cause. - */ - public SerializationException(String message, Throwable cause) { - super(message, cause); +import org.apache.ignite.internal.schema.SchemaDescriptor; + +public class JavaSerializerFactory implements SerializerFactory { + @Override public Serializer create(SchemaDescriptor schema, Class<?> keyClass, Class<?> valClass) { + return new JavaSerializer(schema, keyClass, valClass); } } 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 3b73a3e..deb6150 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 @@ -35,6 +35,8 @@ package org.apache.ignite.internal.schema.marshaller; import java.util.Objects; +import org.apache.ignite.internal.schema.Column; +import org.apache.ignite.internal.schema.Columns; import org.apache.ignite.internal.schema.Tuple; import org.apache.ignite.internal.schema.TupleAssembler; import org.jetbrains.annotations.Nullable; @@ -44,10 +46,44 @@ import org.jetbrains.annotations.Nullable; */ public class Marshaller { /** + * 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 = MarshallerUtil.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(UnsafeFieldAccessor.createIdentityAccessor(col, firstColId, mode)); + } + + UnsafeFieldAccessor[] fieldAccessors = new UnsafeFieldAccessor[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] = UnsafeFieldAccessor.create(aClass, col, colIdx); + } + + return new Marshaller(new ObjectFactory<>(aClass), fieldAccessors); + } + + /** * Field accessors for mapped columns. * Array has same size and order as columns. */ - private final FieldAccessor[] fieldAccessors; + private final UnsafeFieldAccessor[] fieldAccessors; /** * Object factory for complex types or {@code null} for basic type. @@ -62,7 +98,7 @@ public class Marshaller { * @param fieldAccessors Object field accessors for mapped columns. */ @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") - public Marshaller(Factory<?> factory, FieldAccessor[] fieldAccessors) { + public Marshaller(Factory<?> factory, UnsafeFieldAccessor[] fieldAccessors) { this.fieldAccessors = fieldAccessors; this.factory = Objects.requireNonNull(factory); } @@ -73,8 +109,8 @@ public class Marshaller { * * @param fieldAccessor Identity field accessor for object of basic type. */ - public Marshaller(FieldAccessor fieldAccessor) { - fieldAccessors = new FieldAccessor[] {fieldAccessor}; + public Marshaller(UnsafeFieldAccessor fieldAccessor) { + fieldAccessors = new UnsafeFieldAccessor[] {fieldAccessor}; factory = null; } 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 deleted file mode 100644 index 3e642da..0000000 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java +++ /dev/null @@ -1,74 +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. - */ - -/* - * 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/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java new file mode 100644 index 0000000..d6ff9eb --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.schema.marshaller; + +import java.util.BitSet; +import java.util.UUID; +import org.apache.ignite.internal.schema.NativeType; +import org.apache.ignite.internal.schema.TupleAssembler; + +public class MarshallerUtil { + /** + * Calculates size for serialized value of varlen type. + * + * @param val Field value. + * @param type Mapped type. + * @return Serialized value size. + */ + public static int getValueSize(Object val, NativeType type) { + switch (type.spec()) { + case BYTES: + return ((byte[])val).length; + + case STRING: + return TupleAssembler.utf8EncodedLength((CharSequence)val); + + default: + throw new IllegalStateException("Unsupported test varsize type: " + type); + } + } + + /** + * Gets binary read/write mode for given class. + * + * @param cls Type. + * @return Binary mode. + */ + public static BinaryMode mode(Class<?> cls) { + assert cls != null; + + // Primitives. + if (cls == byte.class) + return BinaryMode.P_BYTE; + else if (cls == short.class) + return BinaryMode.P_SHORT; + else if (cls == int.class) + return BinaryMode.P_INT; + else if (cls == long.class) + return BinaryMode.P_LONG; + else if (cls == float.class) + return BinaryMode.P_FLOAT; + else if (cls == double.class) + return BinaryMode.P_DOUBLE; + + // Boxed primitives. + else if (cls == Byte.class) + return BinaryMode.BYTE; + else if (cls == Short.class) + return BinaryMode.SHORT; + else if (cls == Integer.class) + return BinaryMode.INT; + else if (cls == Long.class) + return BinaryMode.LONG; + else if (cls == Float.class) + return BinaryMode.FLOAT; + else if (cls == Double.class) + return BinaryMode.DOUBLE; + + // Other types + else if (cls == byte[].class) + return BinaryMode.BYTE_ARR; + else if (cls == String.class) + return BinaryMode.STRING; + else if (cls == UUID.class) + return BinaryMode.UUID; + else if (cls == BitSet.class) + return BinaryMode.BITSET; + + return null; + } +} diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectMarshallerExprGenerator.java new file mode 100644 index 0000000..f6a274a --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ObjectMarshallerExprGenerator.java @@ -0,0 +1,68 @@ +/* + * 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; + +class ObjectMarshallerExprGenerator { + private final String classFieldExpr; + protected FieldAccessExprGenerator[] accessors; + + public ObjectMarshallerExprGenerator(String classFieldExpr, FieldAccessExprGenerator[] accessors) { + this.accessors = accessors; + this.classFieldExpr = classFieldExpr; + } + + public void unmarshallObject(StringBuilder sb, String indent) { + sb.append(indent).append("Object obj;" + JaninoSerializerGenerator.LF); + sb.append(indent).append("try {" + JaninoSerializerGenerator.LF); + sb.append(indent).append(JaninoSerializerGenerator.TAB + "obj = IgniteUnsafeUtils.allocateInstance(").append(classFieldExpr).append(");" + JaninoSerializerGenerator.LF); + + for (int i = 0; i < accessors.length; i++) + accessors[i].addPutFieldExpr(sb, accessors[i].readColumnExpr(), indent + JaninoSerializerGenerator.TAB); + sb.append(indent).append("} catch (InstantiationException ex) {" + JaninoSerializerGenerator.LF); + + sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(\"Failed to instantiate object: \" + ") + .append(classFieldExpr).append(".getSimpleName(), ex);").append(JaninoSerializerGenerator.LF); + sb.append(indent).append("}" + JaninoSerializerGenerator.LF); + } + + public void marshallObject(StringBuilder sb, String indent) { + sb.append(indent).append("try {" + JaninoSerializerGenerator.LF); + + for (int i = 0; i < accessors.length; i++) + accessors[i].addWriteColumnExpr(sb, accessors[i].getFieldExpr(), indent + JaninoSerializerGenerator.TAB); + + 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); + } + + static class IdentityObjectMarshaller extends ObjectMarshallerExprGenerator { + IdentityObjectMarshaller(FieldAccessExprGenerator accessors) { + super(null, new FieldAccessExprGenerator[] {accessors}); + } + + @Override public void marshallObject(StringBuilder sb, String indent) { + for (int i = 0; i < accessors.length; i++) + accessors[i].addWriteColumnExpr(sb, "obj", indent); + } + + @Override public void unmarshallObject(StringBuilder sb, String indent) { + sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF); + } + } +} diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java index aa8a497..e690710 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java @@ -24,6 +24,16 @@ public class SerializationException extends Exception { /** * Constructor. * + * @param cause Cause. + */ + public SerializationException(Throwable cause) { + // Used by serializers generated with Janino. + super(cause); + } + + /** + * Constructor. + * * @param message Message. * @param cause Cause. */ diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Serializer.java similarity index 63% copy from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java copy to modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Serializer.java index aa8a497..21a1560 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Serializer.java @@ -18,16 +18,25 @@ package org.apache.ignite.internal.schema.marshaller; /** - * Serialization exception. + * Key-value objects (de)serializer. */ -public class SerializationException extends Exception { +public interface Serializer { /** - * Constructor. + * Writes key-value pair to tuple. * - * @param message Message. - * @param cause Cause. + * @param key Key object. + * @param val Value object. + * @return Serialized key-value pair. */ - public SerializationException(String message, Throwable cause) { - super(message, cause); - } + byte[] serialize(Object key, Object val) throws SerializationException; + + /** + * @return Key object. + */ + Object deserializeKey(byte[] data) throws SerializationException; + + /** + * @return Value object. + */ + Object deserializeValue(byte[] data) throws SerializationException; } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java similarity index 66% copy from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java copy to modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java index aa8a497..b83e9b9 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java @@ -17,17 +17,17 @@ package org.apache.ignite.internal.schema.marshaller; -/** - * Serialization exception. - */ -public class SerializationException extends Exception { - /** - * Constructor. - * - * @param message Message. - * @param cause Cause. - */ - public SerializationException(String message, Throwable cause) { - super(message, cause); +import org.apache.ignite.internal.schema.SchemaDescriptor; + +public interface SerializerFactory { + public static SerializerFactory createJaninoSerializerFactory() { + return new JaninoSerializerGenerator(); + } + + public static SerializerFactory createJavaSerializerFactory() { + return new JavaSerializerFactory(); + } + + public Serializer create(SchemaDescriptor schema, Class<?> keyClass, Class<?> valClass); } 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/UnsafeFieldAccessor.java similarity index 92% rename from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java rename to modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/UnsafeFieldAccessor.java index 713553d..1f286c6 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/UnsafeFieldAccessor.java @@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; * Field accessor to speedup access. */ // TODO: Extract interface, move to java-8 profile and add Java9+ implementation using VarHandles. -public abstract class FieldAccessor { +public abstract class UnsafeFieldAccessor { /** * TODO: implement sesitive information filtering. * @@ -64,14 +64,14 @@ public abstract class FieldAccessor { * @param colIdx Column index in schema. * @return Accessor. */ - static FieldAccessor create(Class<?> type, Column col, int colIdx) { + static UnsafeFieldAccessor create(Class<?> type, Column col, int colIdx) { try { final Field field = type.getDeclaredField(col.name()); 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()); + BinaryMode mode = MarshallerUtil.mode(field.getType()); switch (mode) { case P_BYTE: @@ -123,7 +123,7 @@ public abstract class FieldAccessor { * @param mode Binary mode. * @return Accessor. */ - static FieldAccessor createIdentityAccessor(Column col, int colIdx, BinaryMode mode) { + static UnsafeFieldAccessor createIdentityAccessor(Column col, int colIdx, BinaryMode mode) { switch (mode) { // Marshaller read/write object contract methods allowed boxed types only. case P_BYTE: @@ -160,7 +160,7 @@ public abstract class FieldAccessor { * @param colIdx Column index. * @param mode Binary mode; */ - protected FieldAccessor(Field field, int colIdx, BinaryMode mode) { + protected UnsafeFieldAccessor(Field field, int colIdx, BinaryMode mode) { assert field != null; assert colIdx >= 0; assert mode != null; @@ -169,8 +169,6 @@ public abstract class FieldAccessor { this.mode = mode; offset = IgniteUnsafeUtils.objectFieldOffset(field); name = field.getName(); - - field.setAccessible(true); } /** @@ -179,7 +177,7 @@ public abstract class FieldAccessor { * @param colIdx Column index. * @param mode Binary mode; */ - private FieldAccessor(int colIdx, BinaryMode mode) { + private UnsafeFieldAccessor(int colIdx, BinaryMode mode) { assert colIdx >= 0; assert mode != null; @@ -211,7 +209,7 @@ public abstract class FieldAccessor { } catch (Exception ex) { if (includeSensitive() && name != null) - throw new SerializationException("Failed to write field [name=" + name + ']', ex); + throw new SerializationException("Failed to read field [id=" + colIdx + ']', ex); else throw new SerializationException("Failed to write field [id=" + colIdx + ']', ex); } @@ -277,7 +275,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code byte} type. */ - private static class IdentityAccessor extends FieldAccessor { + private static class IdentityAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -312,7 +310,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code byte} type. */ - private static class BytePrimitiveAccessor extends FieldAccessor { + private static class BytePrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -341,7 +339,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code short} type. */ - private static class ShortPrimitiveAccessor extends FieldAccessor { + private static class ShortPrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -370,7 +368,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code int} type. */ - private static class IntPrimitiveAccessor extends FieldAccessor { + private static class IntPrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -399,7 +397,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code long} type. */ - private static class LongPrimitiveAccessor extends FieldAccessor { + private static class LongPrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -428,7 +426,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code float} type. */ - private static class FloatPrimitiveAccessor extends FieldAccessor { + private static class FloatPrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -457,7 +455,7 @@ public abstract class FieldAccessor { /** * Accessor for field of primitive {@code double} type. */ - private static class DoublePrimitiveAccessor extends FieldAccessor { + private static class DoublePrimitiveAccessor extends UnsafeFieldAccessor { /** * Constructor. * @@ -486,7 +484,7 @@ public abstract class FieldAccessor { /** * Accessor for field of reference type. */ - private static class ReferenceFieldAccessor extends FieldAccessor { + private static class ReferenceFieldAccessor extends UnsafeFieldAccessor { /** * Constructor. * diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/FieldAccessorTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/FieldAccessorTest.java index 461d66a..a4a3c56 100644 --- a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/FieldAccessorTest.java +++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/FieldAccessorTest.java @@ -101,7 +101,7 @@ public class FieldAccessorTest { final TestObject obj = TestObject.randomObject(rnd); for (int i = 0; i < cols.length; i++) { - FieldAccessor accessor = FieldAccessor.create(TestObject.class, cols[i], i); + UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestObject.class, cols[i], i); accessor.write(obj, tupleAssembler); } @@ -109,7 +109,7 @@ public class FieldAccessorTest { final TestObject restoredObj = new TestObject(); for (int i = 0; i < cols.length; i++) { - FieldAccessor accessor = FieldAccessor.create(TestObject.class, cols[i], i); + UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestObject.class, cols[i], i); accessor.read(restoredObj, tuple); } @@ -139,7 +139,7 @@ public class FieldAccessorTest { */ @Test public void testIdentityAccessor() throws Exception { - final FieldAccessor accessor = FieldAccessor.createIdentityAccessor( + final UnsafeFieldAccessor accessor = UnsafeFieldAccessor.createIdentityAccessor( new Column("col0", STRING, true), 0, BinaryMode.STRING); @@ -157,7 +157,7 @@ public class FieldAccessorTest { */ @Test public void testWrongIdentityAccessor() throws Exception { - final FieldAccessor accessor = FieldAccessor.createIdentityAccessor( + final UnsafeFieldAccessor accessor = UnsafeFieldAccessor.createIdentityAccessor( new Column("col0", STRING, true), 42, BinaryMode.UUID); 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 3cfb0da..53550b5 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 @@ -19,6 +19,7 @@ package org.apache.ignite.internal.schema.marshaller; import java.util.Arrays; import java.util.BitSet; +import java.util.List; import java.util.Objects; import java.util.Random; import java.util.UUID; @@ -30,7 +31,8 @@ import org.apache.ignite.internal.schema.NativeTypeSpec; import org.apache.ignite.internal.schema.SchemaDescriptor; import org.apache.ignite.internal.schema.TestUtils; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static org.apache.ignite.internal.schema.NativeType.BYTE; import static org.apache.ignite.internal.schema.NativeType.BYTES; @@ -43,13 +45,20 @@ import static org.apache.ignite.internal.schema.NativeType.STRING; import static org.apache.ignite.internal.schema.NativeType.UUID; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; /** * Serializer test. */ public class JavaSerializerTest { + + private static List<SerializerFactory> serializerFactoryProvider() { + return Arrays.asList( + new JaninoSerializerGenerator(), + new JavaSerializerFactory() + ); + } + /** Random. */ private Random rnd; @@ -66,189 +75,202 @@ public class JavaSerializerTest { } /** - * @throws SerializationException If serialization failed. + * */ - @Test - public void testBasicTypes() throws SerializationException { + @ParameterizedTest + @MethodSource("serializerFactoryProvider") + public void testBasicTypes(SerializerFactory factory) throws SerializationException { // Fixed types: - checkBasicType(BYTE, BYTE); - checkBasicType(SHORT, SHORT); - checkBasicType(INTEGER, INTEGER); - checkBasicType(LONG, LONG); - checkBasicType(FLOAT, FLOAT); - checkBasicType(DOUBLE, DOUBLE); - checkBasicType(UUID, UUID); - checkBasicType(Bitmask.of(4), Bitmask.of(5)); + checkBasicType(factory, BYTE, BYTE); + checkBasicType(factory, SHORT, SHORT); + checkBasicType(factory, INTEGER, INTEGER); + checkBasicType(factory, LONG, LONG); + checkBasicType(factory, FLOAT, FLOAT); + checkBasicType(factory, DOUBLE, DOUBLE); + checkBasicType(factory, UUID, UUID); + checkBasicType(factory, Bitmask.of(4), Bitmask.of(5)); // Varlen types: - checkBasicType(BYTES, BYTES); - checkBasicType(STRING, STRING); + checkBasicType(factory, BYTES, BYTES); + checkBasicType(factory, STRING, STRING); // Mixed: - checkBasicType(LONG, INTEGER); - checkBasicType(INTEGER, BYTES); - checkBasicType(STRING, LONG); - checkBasicType(Bitmask.of(9), BYTES); - } - - /** - * @throws SerializationException If serialization failed. - */ - @Test - public void testComplexType() throws SerializationException { - Column[] cols = new Column[] { - new Column("pByteCol", BYTE, false), - new Column("pShortCol", SHORT, false), - new Column("pIntCol", INTEGER, false), - new Column("pLongCol", LONG, false), - new Column("pFloatCol", FLOAT, false), - new Column("pDoubleCol", DOUBLE, false), - - new Column("byteCol", BYTE, true), - new Column("shortCol", SHORT, true), - new Column("intCol", INTEGER, true), - new Column("longCol", LONG, true), - new Column("floatCol", FLOAT, true), - new Column("doubleCol", DOUBLE, true), - - new Column("uuidCol", UUID, true), - new Column("bitmaskCol", Bitmask.of(42), true), - new Column("stringCol", STRING, true), - new Column("bytesCol", BYTES, true), - }; - - SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); - - final Object key = TestObject.randomObject(rnd); - final Object val = TestObject.randomObject(rnd); - - JavaSerializer serializer = new JavaSerializer(schema, key.getClass(), val.getClass()); - - 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); - } - - /** - * - */ - @Test - public void testClassWithIncorrectBitmaskSize() { - Column[] cols = new Column[] { - new Column("pLongCol", LONG, false), - new Column("bitmaskCol", Bitmask.of(9), true), - }; - - SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); - - final Object key = TestObject.randomObject(rnd); - final Object val = TestObject.randomObject(rnd); - - JavaSerializer serializer = new JavaSerializer(schema, key.getClass(), val.getClass()); - - assertThrows( - SerializationException.class, - () -> serializer.serialize(key, val), - "Failed to write field [name=bitmaskCol]" - ); - } - - /** - * - */ - @Test - public void testClassWithWrongFieldType() { - Column[] cols = new Column[] { - new Column("bitmaskCol", Bitmask.of(42), true), - new Column("shortCol", UUID, true) - }; - - SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); - - final Object key = TestObject.randomObject(rnd); - final Object val = TestObject.randomObject(rnd); - - JavaSerializer serializer = new JavaSerializer(schema, key.getClass(), val.getClass()); - - assertThrows( - SerializationException.class, - () -> serializer.serialize(key, val), - "Failed to write field [name=shortCol]" - ); + checkBasicType(factory, LONG, INTEGER); + checkBasicType(factory, FLOAT, DOUBLE); + checkBasicType(factory, INTEGER, BYTES); + checkBasicType(factory, STRING, LONG); + checkBasicType(factory, Bitmask.of(9), BYTES); } - /** - * - */ - @Test - public void testClassWithPrivateConstructor() throws SerializationException { - Column[] cols = new Column[] { - new Column("pLongCol", LONG, false), - }; - - SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); - - final Object key = PrivateTestObject.randomObject(rnd); - final Object val = PrivateTestObject.randomObject(rnd); - - JavaSerializer serializer = new JavaSerializer(schema, key.getClass(), val.getClass()); - - 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); - } - - /** - * - */ - @Test - public void testClassWithNoDefaultConstructor() throws SerializationException { - Column[] cols = new Column[] { - new Column("pLongCol", LONG, false), - }; - - SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); - - final Object key = WrongTestObject.randomObject(rnd); - final Object val = WrongTestObject.randomObject(rnd); - - 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); - } +// /** +// * @throws SerializationException If serialization failed. +// */ +// @ParameterizedTest +// @DisplayName("testComplexType") +// @MethodSource("serializerFactoryProvider") +// public void testComplexType(SerializerFactory factory) throws SerializationException { +// Column[] cols = new Column[] { +// new Column("pByteCol", BYTE, false), +// new Column("pShortCol", SHORT, false), +// new Column("pIntCol", INTEGER, false), +// new Column("pLongCol", LONG, false), +// new Column("pFloatCol", FLOAT, false), +// new Column("pDoubleCol", DOUBLE, false), +// +// new Column("byteCol", BYTE, true), +// new Column("shortCol", SHORT, true), +// new Column("intCol", INTEGER, true), +// new Column("longCol", LONG, true), +// new Column("floatCol", FLOAT, true), +// new Column("doubleCol", DOUBLE, true), +// +// new Column("uuidCol", UUID, true), +// new Column("bitmaskCol", Bitmask.of(42), true), +// new Column("stringCol", STRING, true), +// new Column("bytesCol", BYTES, true), +// }; +// +// SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); +// +// final Object key = TestObject.randomObject(rnd); +// final Object val = TestObject.randomObject(rnd); +// +// Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); +// +// byte[] bytes = serializer.serialize(key, val); +// +// // Try different order. +// Object restoredVal = serializer.deserializeValue(bytes); +// Object restoredKey = serializer.deserializeKey(bytes); +// +// assertTrue(key.getClass().isInstance(restoredKey)); +// assertTrue(val.getClass().isInstance(restoredVal)); +// +// assertEquals(key, restoredKey); +// assertEquals(val, restoredVal); +// } +// +// /** +// * +// */ +// @ParameterizedTest +// @MethodSource("serializerFactoryProvider") +// public void testClassWithIncorrectBitmaskSize(SerializerFactory factory) { +// Column[] cols = new Column[] { +// new Column("pLongCol", LONG, false), +// new Column("bitmaskCol", Bitmask.of(9), true), +// }; +// +// SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); +// +// final Object key = TestObject.randomObject(rnd); +// final Object val = TestObject.randomObject(rnd); +// +// Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); +// +// assertThrows( +// SerializationException.class, +// () -> serializer.serialize(key, val), +// "Failed to write field [name=bitmaskCol]" +// ); +// } +// +// /** +// * +// */ +// @ParameterizedTest +// @DisplayName("testClassWithWrongFieldType") +// @MethodSource("serializerFactoryProvider") +// public void testClassWithWrongFieldType(SerializerFactory factory) throws Exception { +// Column[] cols = new Column[] { +// new Column("bitmaskCol", Bitmask.of(42), true), +// new Column("shortCol", UUID, true) +// }; +// +// SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); +// +// final Object key = TestObject.randomObject(rnd); +// final Object val = TestObject.randomObject(rnd); +// +// Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); +// +// assertThrows( +// SerializationException.class, +// () -> serializer.serialize(key, val), +// "Failed to write field [name=shortCol]" +// ); +// } +// +// /** +// * +// */ +// @ParameterizedTest +// @MethodSource("serializerFactoryProvider") +// public void testClassWithPrivateConstructor(SerializerFactory factory) throws SerializationException { +// Column[] cols = new Column[] { +// new Column("pLongCol", LONG, false), +// }; +// +// SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); +// +// final Object key = PrivateTestObject.randomObject(rnd); +// final Object val = PrivateTestObject.randomObject(rnd); +// +// Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); +// +// 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); +// } +// +// /** +// * +// */ +// @ParameterizedTest +// @DisplayName("testClassWithNoDefaultConstructor") +// @MethodSource("serializerFactoryProvider") +// public void testClassWithNoDefaultConstructor(SerializerFactory factory) throws SerializationException { +// Column[] cols = new Column[] { +// new Column("pLongCol", LONG, false), +// }; +// +// SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(cols), new Columns(cols.clone())); +// +// final Object key = WrongTestObject.randomObject(rnd); +// final Object val = WrongTestObject.randomObject(rnd); +// +// Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); +// +// 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); +// } /** * Generate random key-value pair of given types and * check serialization and deserialization works fine. * + * @param factory Serializer factory. * @param keyType Key type. * @param valType Value type. * @throws SerializationException If (de)serialization failed. */ - private void checkBasicType(NativeType keyType, NativeType valType) throws SerializationException { + private void checkBasicType(SerializerFactory factory, NativeType keyType, + NativeType valType) throws SerializationException { final Object key = generateRandomValue(keyType); final Object val = generateRandomValue(valType); @@ -257,7 +279,7 @@ public class JavaSerializerTest { SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(keyCols), new Columns(valCols)); - JavaSerializer serializer = new JavaSerializer(schema, key.getClass(), val.getClass()); + Serializer serializer = factory.create(schema, key.getClass(), val.getClass()); byte[] bytes = serializer.serialize(key, val);
